aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Samples/SampleBase
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 /PhysX_3.4/Samples/SampleBase
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 'PhysX_3.4/Samples/SampleBase')
-rw-r--r--PhysX_3.4/Samples/SampleBase/AcclaimLoader.cpp683
-rw-r--r--PhysX_3.4/Samples/SampleBase/AcclaimLoader.h132
-rw-r--r--PhysX_3.4/Samples/SampleBase/Dummy.cpp49
-rw-r--r--PhysX_3.4/Samples/SampleBase/InputEventBuffer.cpp162
-rw-r--r--PhysX_3.4/Samples/SampleBase/InputEventBuffer.h228
-rw-r--r--PhysX_3.4/Samples/SampleBase/ParticleEmitter.cpp210
-rw-r--r--PhysX_3.4/Samples/SampleBase/ParticleEmitter.h205
-rw-r--r--PhysX_3.4/Samples/SampleBase/ParticleEmitterPressure.cpp221
-rw-r--r--PhysX_3.4/Samples/SampleBase/ParticleEmitterPressure.h90
-rw-r--r--PhysX_3.4/Samples/SampleBase/ParticleEmitterRate.cpp203
-rw-r--r--PhysX_3.4/Samples/SampleBase/ParticleEmitterRate.h64
-rw-r--r--PhysX_3.4/Samples/SampleBase/ParticleFactory.cpp123
-rw-r--r--PhysX_3.4/Samples/SampleBase/ParticleFactory.h73
-rw-r--r--PhysX_3.4/Samples/SampleBase/ParticleSystem.cpp550
-rw-r--r--PhysX_3.4/Samples/SampleBase/ParticleSystem.h163
-rw-r--r--PhysX_3.4/Samples/SampleBase/PhysXSample.cpp2901
-rw-r--r--PhysX_3.4/Samples/SampleBase/PhysXSample.h364
-rw-r--r--PhysX_3.4/Samples/SampleBase/PhysXSampleApplication.cpp1513
-rw-r--r--PhysX_3.4/Samples/SampleBase/PhysXSampleApplication.h364
-rw-r--r--PhysX_3.4/Samples/SampleBase/Picking.cpp289
-rw-r--r--PhysX_3.4/Samples/SampleBase/Picking.h121
-rw-r--r--PhysX_3.4/Samples/SampleBase/RawLoader.cpp415
-rw-r--r--PhysX_3.4/Samples/SampleBase/RawLoader.h120
-rw-r--r--PhysX_3.4/Samples/SampleBase/RaycastCCD.cpp252
-rw-r--r--PhysX_3.4/Samples/SampleBase/RaycastCCD.h46
-rw-r--r--PhysX_3.4/Samples/SampleBase/RenderBaseActor.cpp279
-rw-r--r--PhysX_3.4/Samples/SampleBase/RenderBaseActor.h126
-rw-r--r--PhysX_3.4/Samples/SampleBase/RenderBaseObject.cpp52
-rw-r--r--PhysX_3.4/Samples/SampleBase/RenderBaseObject.h49
-rw-r--r--PhysX_3.4/Samples/SampleBase/RenderBoxActor.cpp48
-rw-r--r--PhysX_3.4/Samples/SampleBase/RenderBoxActor.h49
-rw-r--r--PhysX_3.4/Samples/SampleBase/RenderCapsuleActor.cpp58
-rw-r--r--PhysX_3.4/Samples/SampleBase/RenderCapsuleActor.h53
-rw-r--r--PhysX_3.4/Samples/SampleBase/RenderClothActor.cpp946
-rw-r--r--PhysX_3.4/Samples/SampleBase/RenderClothActor.h117
-rw-r--r--PhysX_3.4/Samples/SampleBase/RenderGridActor.cpp50
-rw-r--r--PhysX_3.4/Samples/SampleBase/RenderGridActor.h49
-rw-r--r--PhysX_3.4/Samples/SampleBase/RenderMaterial.cpp184
-rw-r--r--PhysX_3.4/Samples/SampleBase/RenderMaterial.h78
-rw-r--r--PhysX_3.4/Samples/SampleBase/RenderMeshActor.cpp66
-rw-r--r--PhysX_3.4/Samples/SampleBase/RenderMeshActor.h54
-rw-r--r--PhysX_3.4/Samples/SampleBase/RenderParticleSystemActor.cpp178
-rw-r--r--PhysX_3.4/Samples/SampleBase/RenderParticleSystemActor.h66
-rw-r--r--PhysX_3.4/Samples/SampleBase/RenderPhysX3Debug.cpp923
-rw-r--r--PhysX_3.4/Samples/SampleBase/RenderPhysX3Debug.h100
-rw-r--r--PhysX_3.4/Samples/SampleBase/RenderSphereActor.cpp48
-rw-r--r--PhysX_3.4/Samples/SampleBase/RenderSphereActor.h44
-rw-r--r--PhysX_3.4/Samples/SampleBase/RenderTexture.cpp109
-rw-r--r--PhysX_3.4/Samples/SampleBase/RenderTexture.h55
-rw-r--r--PhysX_3.4/Samples/SampleBase/SampleAllocator.cpp332
-rw-r--r--PhysX_3.4/Samples/SampleBase/SampleAllocator.h87
-rw-r--r--PhysX_3.4/Samples/SampleBase/SampleAllocatorSDKClasses.h47
-rw-r--r--PhysX_3.4/Samples/SampleBase/SampleArray.h51
-rw-r--r--PhysX_3.4/Samples/SampleBase/SampleBaseInputEventIds.h95
-rw-r--r--PhysX_3.4/Samples/SampleBase/SampleCamera.cpp481
-rw-r--r--PhysX_3.4/Samples/SampleBase/SampleCamera.h157
-rw-r--r--PhysX_3.4/Samples/SampleBase/SampleCameraController.cpp274
-rw-r--r--PhysX_3.4/Samples/SampleBase/SampleCameraController.h103
-rw-r--r--PhysX_3.4/Samples/SampleBase/SampleCharacterHelpers.cpp578
-rw-r--r--PhysX_3.4/Samples/SampleBase/SampleCharacterHelpers.h152
-rw-r--r--PhysX_3.4/Samples/SampleBase/SampleConsole.cpp609
-rw-r--r--PhysX_3.4/Samples/SampleBase/SampleConsole.h134
-rw-r--r--PhysX_3.4/Samples/SampleBase/SampleInputMappingAsset.cpp264
-rw-r--r--PhysX_3.4/Samples/SampleBase/SampleInputMappingAsset.h66
-rw-r--r--PhysX_3.4/Samples/SampleBase/SampleMain.cpp311
-rw-r--r--PhysX_3.4/Samples/SampleBase/SampleMouseFilter.cpp107
-rw-r--r--PhysX_3.4/Samples/SampleBase/SampleMouseFilter.h56
-rw-r--r--PhysX_3.4/Samples/SampleBase/SamplePreprocessor.h34
-rw-r--r--PhysX_3.4/Samples/SampleBase/SampleRandomPrecomputed.cpp92
-rw-r--r--PhysX_3.4/Samples/SampleBase/SampleRandomPrecomputed.h64
-rw-r--r--PhysX_3.4/Samples/SampleBase/SampleStepper.cpp206
-rw-r--r--PhysX_3.4/Samples/SampleBase/SampleStepper.h229
-rw-r--r--PhysX_3.4/Samples/SampleBase/SampleUserInputDefines.h138
-rw-r--r--PhysX_3.4/Samples/SampleBase/SampleUtils.h47
-rw-r--r--PhysX_3.4/Samples/SampleBase/Test.h39
-rw-r--r--PhysX_3.4/Samples/SampleBase/TestCloth.h108
-rw-r--r--PhysX_3.4/Samples/SampleBase/TestClothCollisionHelpers.cpp213
-rw-r--r--PhysX_3.4/Samples/SampleBase/TestClothCollisionHelpers.h98
-rw-r--r--PhysX_3.4/Samples/SampleBase/TestClothHelpers.cpp759
-rw-r--r--PhysX_3.4/Samples/SampleBase/TestClothHelpers.h115
-rw-r--r--PhysX_3.4/Samples/SampleBase/TestClothReadDataLock.h51
-rw-r--r--PhysX_3.4/Samples/SampleBase/TestGeometryHelpers.cpp43
-rw-r--r--PhysX_3.4/Samples/SampleBase/TestGeometryHelpers.h49
-rw-r--r--PhysX_3.4/Samples/SampleBase/TestGroup.cpp315
-rw-r--r--PhysX_3.4/Samples/SampleBase/TestGroup.h201
-rw-r--r--PhysX_3.4/Samples/SampleBase/TestMotionGenerator.cpp108
-rw-r--r--PhysX_3.4/Samples/SampleBase/TestMotionGenerator.h53
-rw-r--r--PhysX_3.4/Samples/SampleBase/wavefront.cpp946
-rw-r--r--PhysX_3.4/Samples/SampleBase/wavefront.h52
89 files changed, 21186 insertions, 0 deletions
diff --git a/PhysX_3.4/Samples/SampleBase/AcclaimLoader.cpp b/PhysX_3.4/Samples/SampleBase/AcclaimLoader.cpp
new file mode 100644
index 00000000..135bec1f
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/AcclaimLoader.cpp
@@ -0,0 +1,683 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include <stdio.h>
+#include "AcclaimLoader.h"
+#include "FrameworkFoundation.h"
+#include "PsMathUtils.h"
+#include "PxTkFile.h"
+#include "SampleAllocatorSDKClasses.h"
+#include "SampleArray.h"
+
+#define MAX_FILE_BUFFER_SIZE 4096
+#define MAX_TOKEN_LENGTH 512
+
+///////////////////////////////////////////////////////////////////////////////
+static inline bool isWhiteSpace(int c)
+{
+ return ( c == ' ') || (c == '\t');
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static inline bool isWhiteSpaceAndNewline(int c)
+{
+ return ( c == ' ') || (c == '\t') || (c == '\n') || (c == '\r') ;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static inline bool isNumeric(int c)
+{
+ return ('0' <= c) && (c <= '9');
+}
+
+///////////////////////////////////////////////////////////////////////////////
+class SampleFileBuffer
+{
+ SampleFramework::File* mFP;
+ char mBuffer[MAX_FILE_BUFFER_SIZE];
+ int mCurrentBufferSize;
+ int mCurrentCounter;
+ int mEOF;
+
+public:
+ SampleFileBuffer(SampleFramework::File* fp) :
+ mFP(fp),
+ mCurrentBufferSize(0),
+ mCurrentCounter(0),
+ mEOF(0)
+ {}
+
+ ///////////////////////////////////////////////////////////////////////////
+ inline void rewind(int offset = 1)
+ {
+ mCurrentCounter -= offset;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ void readBuffer()
+ {
+ mCurrentBufferSize = (int)fread(mBuffer, 1, MAX_FILE_BUFFER_SIZE, mFP);
+ mEOF = feof(mFP);
+ mCurrentCounter = 0;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ char getCharacter()
+ {
+ if (mCurrentCounter >= mCurrentBufferSize)
+ {
+ if (mEOF) return EOF;
+ readBuffer();
+ if (mCurrentBufferSize == 0)
+ return EOF;
+ }
+ return mBuffer[mCurrentCounter++];
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ bool skipWhiteSpace(bool stopAtEndOfLine)
+ {
+ char c = 0;
+ do
+ {
+ c = getCharacter();
+ bool skip = (stopAtEndOfLine) ? isWhiteSpace(c) : isWhiteSpaceAndNewline(c);
+ if (skip == false)
+ {
+ rewind();
+ return true;
+ }
+ } while (c != EOF);
+
+ return false; // end of file
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////
+ bool getNextToken(char* token, bool stopAtEndOfLine)
+ {
+ if (skipWhiteSpace(stopAtEndOfLine) == false)
+ return false;
+
+ char* str = token;
+ char c = 0;
+ do
+ {
+ c = getCharacter();
+ if (c == EOF)
+ {
+ *str = 0;
+ }
+ else if (isWhiteSpaceAndNewline(c) == true)
+ {
+ *str = 0;
+ rewind();
+ return (strlen(token) > 0);
+ }
+ else
+ *str++ = (char) c;
+ } while (c != EOF);
+
+ return false;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////
+ bool getNextTokenButMarker(char* token)
+ {
+ if (skipWhiteSpace(false) == false)
+ return 0;
+
+ char* str = token;
+ char c = 0;
+ do
+ {
+ c = getCharacter();
+ if (c == ':')
+ {
+ rewind();
+ *str = 0;
+ return false;
+ }
+
+ if (c == EOF)
+ {
+ *str = 0;
+ }
+ else if (isWhiteSpaceAndNewline(c) == true)
+ {
+ *str = 0;
+ rewind();
+ return (strlen(token) > 0);
+ }
+ else
+ *str++ = (char) c;
+ } while (c != EOF);
+
+ return false;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////
+ bool getNextTokenButNumeric(char* token)
+ {
+ if (skipWhiteSpace(false) == false)
+ return 0;
+
+ char* str = token;
+ char c = 0;
+ do
+ {
+ c = getCharacter();
+ if (isNumeric(c))
+ {
+ rewind();
+ *str = 0;
+ return false;
+ }
+
+ if (c == EOF)
+ {
+ *str = 0;
+ }
+ else if (isWhiteSpaceAndNewline(c) == true)
+ {
+ *str = 0;
+ rewind();
+ return (strlen(token) > 0);
+ }
+ else
+ *str++ = (char) c;
+ } while (c != EOF);
+
+ return false;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////
+ void skipUntilNextLine()
+ {
+ char c = 0;
+ do
+ {
+ c = getCharacter();
+ } while ((c != '\n') && (c != EOF));
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////
+ void skipUntilNextBlock()
+ {
+ char dummy[MAX_TOKEN_LENGTH];
+ while (getNextTokenButMarker(dummy) == true)
+ ;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////
+ bool getNextFloat(float& val, bool stopAtEndOfLine = true)
+ {
+ char dummy[MAX_TOKEN_LENGTH];
+ if (getNextToken(dummy, stopAtEndOfLine) == false)
+ return false;
+
+ val = float(atof(dummy));
+ return true;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////
+ bool getNextInt(int& val, bool stopAtEndOfLine = true)
+ {
+ char dummy[MAX_TOKEN_LENGTH];
+ if (getNextToken(dummy, stopAtEndOfLine) == false)
+ return false;
+
+ val = int(atoi(dummy));
+ return true;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////
+ bool getNextString(char* val, bool stopAtEndOfLine = true)
+ {
+ char dummy[MAX_TOKEN_LENGTH];
+
+ if (getNextToken(dummy, stopAtEndOfLine) == false)
+ return false;
+
+ strcpy(val, dummy);
+ return true;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////
+ bool getNextVec3(PxVec3& val, bool stopAtEndOfLine = true)
+ {
+ if (getNextFloat(val.x, stopAtEndOfLine) == false)
+ return false;
+
+ if (getNextFloat(val.y, stopAtEndOfLine) == false)
+ return false;
+
+ if (getNextFloat(val.z, stopAtEndOfLine) == false)
+ return false;
+
+ return true;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+static bool readHeader(SampleFileBuffer& buffer, Acclaim::ASFData& data)
+{
+ using namespace Acclaim;
+
+ char token[MAX_TOKEN_LENGTH], value[MAX_TOKEN_LENGTH];
+
+ while (buffer.getNextTokenButMarker(token) == true)
+ {
+
+ if (strcmp(token, "mass") == 0)
+ {
+ if (buffer.getNextFloat(data.mHeader.mMass) == false)
+ return false;
+ }
+ else if (strcmp(token, "length") == 0)
+ {
+ if (buffer.getNextFloat(data.mHeader.mLengthUnit) == false)
+ return false;
+ }
+ else if (strcmp(token, "angle") == 0)
+ {
+ if (buffer.getNextToken(value, true) == false)
+ return false;
+
+ data.mHeader.mAngleInDegree = (strcmp(value, "deg") == 0);
+ }
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static bool readRoot(SampleFileBuffer& buffer, Acclaim::ASFData& data)
+{
+ using namespace Acclaim;
+
+ char token[MAX_TOKEN_LENGTH];
+
+ while (buffer.getNextTokenButMarker(token) == true)
+ {
+ if (strcmp(token, "order") == 0)
+ buffer.skipUntilNextLine();
+ else if (strcmp(token, "axis") == 0)
+ buffer.skipUntilNextLine();
+ else if (strcmp(token, "position") == 0)
+ {
+ if (buffer.getNextVec3(data.mRoot.mPosition) == false)
+ return false;
+ }
+ else if (strcmp(token, "orientation") == 0)
+ {
+ if (buffer.getNextVec3(data.mRoot.mOrientation) == false)
+ return false;
+ }
+ else
+ {
+ buffer.skipUntilNextLine();
+ }
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static bool readBone(SampleFileBuffer& buffer, Acclaim::Bone& bone)
+{
+ using namespace Acclaim;
+
+ int nbDOF = 0;
+ char token[MAX_TOKEN_LENGTH], dummy[MAX_TOKEN_LENGTH];
+
+ if (buffer.getNextTokenButMarker(token) == false)
+ return false;
+
+ if (strcmp(token, "begin") != 0)
+ return false;
+
+ while (buffer.getNextToken(token, false) == true)
+ {
+ if (strcmp(token, "id") == 0)
+ {
+ if (buffer.getNextInt(bone.mID) == false) return false;
+ }
+ else if (strcmp(token, "name") == 0)
+ {
+ if (buffer.getNextString(bone.mName) == false) return false;
+ }
+ else if (strcmp(token, "direction") == 0)
+ {
+ if (buffer.getNextVec3(bone.mDirection) == false) return false;
+ }
+ else if (strcmp(token, "length") == 0)
+ {
+ if (buffer.getNextFloat(bone.mLength) == false) return false;
+ }
+ else if (strcmp(token, "axis") == 0)
+ {
+ if (buffer.getNextVec3(bone.mAxis) == false) return false;
+ buffer.getNextToken(dummy, true);
+ }
+ else if (strcmp(token, "dof") == 0)
+ {
+ while ((buffer.getNextToken(dummy, true) == true))
+ {
+ if (strcmp(dummy, "rx") == 0)
+ {
+ bone.mDOF |= BoneDOFFlag::eRX;
+ nbDOF++;
+ }
+ else if (strcmp(dummy, "ry") == 0)
+ {
+ bone.mDOF |= BoneDOFFlag::eRY;
+ nbDOF++;
+ }
+ else if (strcmp(dummy, "rz") == 0)
+ {
+ bone.mDOF |= BoneDOFFlag::eRZ;
+ nbDOF++;
+ }
+ else if (strcmp(dummy, "l") == 0)
+ {
+ bone.mDOF |= BoneDOFFlag::eLENGTH;
+ nbDOF++;
+ }
+
+ }
+ continue;
+ }
+ else if (strcmp(token, "limits") == 0)
+ {
+ int cnt = 0;
+ while ( cnt++ < nbDOF)
+ {
+ // we ignore limit data for now
+ if (buffer.getNextToken(dummy, false) == false) return false;
+ if (buffer.getNextToken(dummy, false) == false) return false;
+ }
+ }
+ else if (strcmp(token, "end") == 0)
+ break;
+ else
+ buffer.skipUntilNextLine();
+
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static bool readBoneData(SampleFileBuffer& buffer, Acclaim::ASFData& data)
+{
+ using namespace Acclaim;
+
+ Bone tempBones[MAX_BONE_NUMBER];
+ PxU32 nbBones = 0;
+
+ // read all the temporary bones onto temporary buffer
+ bool moreBone = false;
+ do {
+ moreBone = readBone(buffer, tempBones[nbBones]);
+ if (moreBone)
+ nbBones++;
+
+ PX_ASSERT(nbBones <= MAX_BONE_NUMBER);
+ } while (moreBone == true);
+
+ // allocate the right size and copy the bone data
+ data.mBones = (Bone*)malloc(sizeof(Bone) * nbBones);
+ data.mNbBones = nbBones;
+
+ for (PxU32 i = 0; i < nbBones; i++)
+ {
+ data.mBones[i] = tempBones[i];
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static Acclaim::Bone* getBoneFromName(Acclaim::ASFData& data, const char* name)
+{
+ // use a simple linear search -> probably we could use hash map if performance is an issue
+ for (PxU32 i = 0; i < data.mNbBones; i++)
+ {
+ if (strcmp(name, data.mBones[i].mName) == 0)
+ return &data.mBones[i];
+ }
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static bool readHierarchy(SampleFileBuffer& buffer, Acclaim::ASFData& data)
+{
+ using namespace Acclaim;
+
+ char token[MAX_TOKEN_LENGTH];
+ char dummy[MAX_TOKEN_LENGTH];
+
+ while (buffer.getNextTokenButMarker(token) == true)
+ {
+ if (strcmp(token, "begin") == 0)
+ ;
+ else if (strcmp(token, "end") == 0)
+ break;
+ else
+ {
+ Bone* parent = getBoneFromName(data, token);
+
+ while (buffer.getNextToken(dummy, true) == true)
+ {
+ Bone* child = getBoneFromName(data, dummy);
+ if (!child)
+ return false;
+
+ child->mParent = parent;
+ }
+ }
+
+ buffer.skipUntilNextLine();
+ }
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static bool readFrameData(SampleFileBuffer& buffer, Acclaim::ASFData& asfData, Acclaim::FrameData& frameData)
+{
+ using namespace Acclaim;
+ char token[MAX_TOKEN_LENGTH];
+
+ while (buffer.getNextTokenButNumeric(token) == true)
+ {
+ if (strcmp(token, "root") == 0)
+ {
+ buffer.getNextVec3(frameData.mRootPosition);
+ buffer.getNextVec3(frameData.mRootOrientation);
+ }
+ else
+ {
+ Bone* bone = getBoneFromName(asfData, token);
+
+ if (bone == 0)
+ return false;
+
+ int id = bone->mID - 1;
+ float val = 0;
+ if (bone->mDOF & BoneDOFFlag::eRX)
+ {
+
+ buffer.getNextFloat(val);
+ frameData.mBoneFrameData[id].x = val;
+ }
+ if (bone->mDOF & BoneDOFFlag::eRY)
+ {
+
+ buffer.getNextFloat(val);
+ frameData.mBoneFrameData[id].y = val;
+ }
+ if (bone->mDOF & BoneDOFFlag::eRZ)
+ {
+
+ buffer.getNextFloat(val);
+ frameData.mBoneFrameData[id].z = val;
+ }
+ }
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+bool Acclaim::readASFData(const char* filename, Acclaim::ASFData& data)
+{
+ using namespace Acclaim;
+
+ char token[MAX_TOKEN_LENGTH];
+
+ SampleFramework::File* fp = NULL;
+ PxToolkit::fopen_s(&fp, filename, "r");
+
+ if (!fp)
+ return false;
+
+ SampleFileBuffer buffer(fp);
+
+ while (buffer.getNextToken(token, false) == true)
+ {
+ if (token[0] == '#') // comment
+ {
+ buffer.skipUntilNextLine();
+ continue;
+ }
+ else if (token[0] == ':') // blocks
+ {
+ const char* str = token + 1; // remainder of the string
+
+ if (strcmp(str, "version") == 0) // ignore version number
+ buffer.skipUntilNextLine();
+ else if (strcmp(str, "name") == 0) // probably 'VICON'
+ buffer.skipUntilNextLine();
+ else if (strcmp(str, "units") == 0)
+ {
+ if ( readHeader(buffer, data) == false)
+ return false;
+ }
+ else if (strcmp(str, "documentation") == 0)
+ buffer.skipUntilNextBlock();
+ else if (strcmp(str, "root") == 0)
+ {
+ if (readRoot(buffer, data) == false)
+ return false;
+ }
+ else if (strcmp(str, "bonedata") == 0)
+ {
+ if (readBoneData(buffer, data) == false)
+ return false;
+ }
+ else if (strcmp(str, "hierarchy") == 0)
+ {
+ if (readHierarchy(buffer, data) == false)
+ return false;
+ }
+ else
+ {
+ // ERROR! - unrecognized block name
+ }
+ }
+ else
+ {
+ // ERRROR!
+ continue;
+ }
+ }
+
+
+ fclose(fp);
+
+ return true;
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+bool Acclaim::readAMCData(const char* filename, Acclaim::ASFData& asfData, Acclaim::AMCData& amcData)
+{
+ using namespace Acclaim;
+
+ char token[MAX_TOKEN_LENGTH];
+
+ SampleArray<FrameData> tempFrameData;
+ tempFrameData.reserve(300);
+
+ SampleFramework::File* fp = NULL;
+ PxToolkit::fopen_s(&fp, filename, "r");
+
+ if (!fp)
+ return false;
+
+ SampleFileBuffer buffer(fp);
+
+ while (buffer.getNextToken(token, false) == true)
+ {
+ if (token[0] == '#') // comment
+ {
+ buffer.skipUntilNextLine();
+ continue;
+ }
+ else if (token[0] == ':') // blocks
+ {
+ const char* str = token + 1; // remainder of the string
+
+ if (strcmp(str, "FULLY-SPECIFIED") == 0)
+ continue;
+ else if (strcmp(str, "DEGREES") == 0)
+ continue;
+ }
+ else if (isNumeric(token[0]) == true)
+ {
+ // frame number
+ //int frameNo = atoi(token);
+
+ FrameData frameData;
+ if (readFrameData(buffer, asfData, frameData) == true)
+ tempFrameData.pushBack(frameData);
+ }
+ }
+
+ amcData.mNbFrames = tempFrameData.size();
+
+ amcData.mFrameData = (FrameData*)malloc(sizeof(FrameData) * amcData.mNbFrames);
+ memcpy(amcData.mFrameData, tempFrameData.begin(), sizeof(FrameData) * amcData.mNbFrames);
+
+ fclose(fp);
+
+ return true;
+}
+
diff --git a/PhysX_3.4/Samples/SampleBase/AcclaimLoader.h b/PhysX_3.4/Samples/SampleBase/AcclaimLoader.h
new file mode 100644
index 00000000..f53e181c
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/AcclaimLoader.h
@@ -0,0 +1,132 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef ACCLAIM_LOADER
+#define ACCLAIM_LOADER
+
+#include "foundation/PxFlags.h"
+#include "foundation/PxTransform.h"
+#include "SampleAllocator.h"
+#include "SampleArray.h"
+
+namespace Acclaim
+{
+
+#define MAX_BONE_NAME_CHARACTER_LENGTH 100
+#define MAX_BONE_NUMBER 32
+
+///////////////////////////////////////////////////////////////////////////////
+struct BoneDOFFlag
+{
+ enum Enum
+ {
+ eRX = (1<<0),
+ eRY = (1<<1),
+ eRZ = (1<<2),
+ eLENGTH = (1<<3)
+ };
+};
+
+typedef PxFlags<BoneDOFFlag::Enum,PxU16> BoneDOFFlags;
+PX_FLAGS_OPERATORS(BoneDOFFlag::Enum, PxU16)
+
+///////////////////////////////////////////////////////////////////////////////
+struct Bone
+{
+ int mID;
+ char mName[MAX_BONE_NAME_CHARACTER_LENGTH];
+ PxVec3 mDirection;
+ PxReal mLength;
+ PxVec3 mAxis;
+ BoneDOFFlags mDOF;
+ Bone* mParent;
+
+public:
+ Bone() :
+ mID(-1),
+ mDirection(0.0f),
+ mLength(0.0f),
+ mAxis(0.0f, 0.0f, 1.0f),
+ mDOF(0),
+ mParent(NULL)
+ {
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+struct ASFData
+{
+ struct Header
+ {
+ PxReal mMass;
+ PxReal mLengthUnit;
+ bool mAngleInDegree;
+ };
+
+ struct Root
+ {
+ PxVec3 mPosition;
+ PxVec3 mOrientation;
+ };
+
+ Header mHeader;
+ Root mRoot;
+ Bone* mBones;
+ PxU32 mNbBones;
+
+public:
+ void release() { if (mBones) free(mBones); }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+struct FrameData
+{
+ PxVec3 mRootPosition;
+ PxVec3 mRootOrientation;
+
+ PxVec3 mBoneFrameData[MAX_BONE_NUMBER];
+ PxU32 mNbBones;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+struct AMCData
+{
+ FrameData* mFrameData;
+ PxU32 mNbFrames;
+
+public:
+ void release() { if (mFrameData) free(mFrameData); }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+bool readASFData(const char* filename, ASFData& data);
+bool readAMCData(const char* filename, ASFData& asfData, AMCData& amcData);
+}
+
+#endif // ACCLAIM_LOADER
diff --git a/PhysX_3.4/Samples/SampleBase/Dummy.cpp b/PhysX_3.4/Samples/SampleBase/Dummy.cpp
new file mode 100644
index 00000000..f7e89d92
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/Dummy.cpp
@@ -0,0 +1,49 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+// PT: dummy file to test each header can be included on his own without anything else
+// DON'T REMOVE.
+
+//#include "SampleErrorStream.h"
+//#include "RenderBaseActor.h"
+//#include "RenderBoxActor.h"
+//#include "RenderSphereActor.h"
+//#include "RenderCapsuleActor.h"
+//#include "RenderMeshActor.h"
+//#include "RenderGridActor.h"
+//#include "RenderMaterial.h"
+//#include "RawLoader.h"
+//#include "RenderPhysX3Debug.h"
+//#include "SampleBase.h"
+//#include "SampleBridges.h"
+//#include "SampleMain.h"
+//#include "SampleMouseFilter.h"
+//#include "SampleUtils.h"
+//#include "SampleCamera.h"
+//#include "SampleCameraController.h"
+#include "SampleStepper.h"
diff --git a/PhysX_3.4/Samples/SampleBase/InputEventBuffer.cpp b/PhysX_3.4/Samples/SampleBase/InputEventBuffer.cpp
new file mode 100644
index 00000000..146d44b3
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/InputEventBuffer.cpp
@@ -0,0 +1,162 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "InputEventBuffer.h"
+#include "PhysXSampleApplication.h"
+
+using namespace physx;
+using namespace SampleRenderer;
+using namespace SampleFramework;
+using namespace PxToolkit;
+
+InputEventBuffer::InputEventBuffer(PhysXSampleApplication& p)
+: mResetInputCacheReq(0)
+, mResetInputCacheAck(0)
+, mLastKeyDownEx(NULL)
+, mLastDigitalInput(NULL)
+, mLastAnalogInput(NULL)
+, mLastPointerInput(NULL)
+, mApp(p)
+, mClearBuffer(false)
+{
+}
+
+InputEventBuffer::~InputEventBuffer()
+{
+}
+
+void InputEventBuffer::onKeyDownEx(SampleFramework::SampleUserInput::KeyCode keyCode, PxU32 wParam)
+{
+ checkResetLastInput();
+ if(mLastKeyDownEx && mLastKeyDownEx->isEqual(keyCode, wParam))
+ return;
+ if(mRingBuffer.isFull())
+ return;
+ KeyDownEx& event = mRingBuffer.front().get<KeyDownEx>();
+ PX_PLACEMENT_NEW(&event, KeyDownEx);
+ event.keyCode = keyCode;
+ event.wParam = wParam;
+ mLastKeyDownEx = &event;
+ mRingBuffer.incFront(1);
+}
+
+void InputEventBuffer::onAnalogInputEvent(const SampleFramework::InputEvent& e, float val)
+{
+ checkResetLastInput();
+ if(mLastAnalogInput && mLastAnalogInput->isEqual(e, val))
+ return;
+ if(mRingBuffer.isFull() || (mRingBuffer.size() > MAX_ANALOG_EVENTS))
+ return;
+ AnalogInput& event = mRingBuffer.front().get<AnalogInput>();
+ PX_PLACEMENT_NEW(&event, AnalogInput);
+ event.e = e;
+ event.val = val;
+ mLastAnalogInput = &event;
+ mRingBuffer.incFront(1);
+}
+
+void InputEventBuffer::onDigitalInputEvent(const SampleFramework::InputEvent& e, bool val)
+{
+ checkResetLastInput();
+ if(mLastDigitalInput && mLastDigitalInput->isEqual(e, val))
+ return;
+ if(mRingBuffer.isFull())
+ return;
+ DigitalInput& event = mRingBuffer.front().get<DigitalInput>();
+ PX_PLACEMENT_NEW(&event, DigitalInput);
+ event.e = e;
+ event.val = val;
+ mLastDigitalInput = &event;
+ mRingBuffer.incFront(1);
+}
+
+void InputEventBuffer::onPointerInputEvent(const SampleFramework::InputEvent& e, PxU32 x, PxU32 y, PxReal dx, PxReal dy, bool val)
+{
+ checkResetLastInput();
+ if(mLastPointerInput && mLastPointerInput->isEqual(e, x, y, dx, dy, val))
+ return;
+ if(mRingBuffer.isFull() || (mRingBuffer.size() > MAX_MOUSE_EVENTS))
+ return;
+ PointerInput& event = mRingBuffer.front().get<PointerInput>();
+ PX_PLACEMENT_NEW(&event, PointerInput);
+ event.e = e;
+ event.x = x;
+ event.y = y;
+ event.dx = dx;
+ event.dy = dy;
+ event.val = val;
+ mLastPointerInput = &event;
+ mRingBuffer.incFront(1);
+}
+
+void InputEventBuffer::clear()
+{
+ mClearBuffer = true;
+}
+
+void InputEventBuffer::flush()
+{
+ if(mResetInputCacheReq==mResetInputCacheAck)
+ mResetInputCacheReq++;
+
+ PxU32 size = mRingBuffer.size();
+ Ps::memoryBarrier();
+ // do not work on more than size, else input cache might become overwritten
+ while(size-- && !mClearBuffer)
+ {
+ mRingBuffer.back().get<EventType>().report(mApp);
+ mRingBuffer.incBack(1);
+ }
+
+ if(mClearBuffer)
+ {
+ mRingBuffer.clear();
+ mClearBuffer = false;
+ }
+}
+
+void InputEventBuffer::KeyDownEx::report(PhysXSampleApplication& app) const
+{
+ app.onKeyDownEx(keyCode, wParam);
+}
+
+void InputEventBuffer::AnalogInput::report(PhysXSampleApplication& app) const
+{
+ app.onAnalogInputEvent(e, val);
+}
+
+void InputEventBuffer::DigitalInput::report(PhysXSampleApplication& app) const
+{
+ app.onDigitalInputEvent(e, val);
+}
+
+void InputEventBuffer::PointerInput::report(PhysXSampleApplication& app) const
+{
+ app.onPointerInputEvent(e, x, y, dx, dy, val);
+}
diff --git a/PhysX_3.4/Samples/SampleBase/InputEventBuffer.h b/PhysX_3.4/Samples/SampleBase/InputEventBuffer.h
new file mode 100644
index 00000000..824cd64a
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/InputEventBuffer.h
@@ -0,0 +1,228 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef INPUT_BUFFER_H
+#define INPUT_BUFFER_H
+
+#include "SamplePreprocessor.h"
+#include "SampleAllocator.h"
+#include "SampleUserInput.h"
+#include "foundation/PxAssert.h"
+#include "PsIntrinsics.h"
+
+class PhysXSampleApplication;
+
+template<typename T, PxU32 SIZE>
+class RingBuffer
+{
+public:
+ RingBuffer()
+ : mReadCount(0)
+ , mWriteCount(0)
+ {
+ // SIZE has to be power of two
+#if PX_VC
+ PX_COMPILE_TIME_ASSERT(SIZE > 0);
+ PX_COMPILE_TIME_ASSERT((SIZE&(SIZE-1)) == 0);
+#else
+ PX_ASSERT(SIZE > 0);
+ PX_ASSERT((SIZE&(SIZE-1)) == 0);
+#endif
+ }
+
+ PX_FORCE_INLINE bool isEmpty() const { return mReadCount==mWriteCount; }
+ PX_FORCE_INLINE bool isFull() const { return isFull(mReadCount, mWriteCount); }
+ PX_FORCE_INLINE PxU32 size() const { return size(mReadCount, mWriteCount); }
+ PX_FORCE_INLINE PxU32 capacity() const { return SIZE; }
+ // clear is only save if called from reader thread!
+ PX_FORCE_INLINE void clear() { mReadCount=mWriteCount; }
+ PX_FORCE_INLINE const T& back() const { PX_ASSERT(!isEmpty()); return mRing[mReadCount&moduloMask]; }
+ PX_FORCE_INLINE T& front() { return mRing[mWriteCount&moduloMask]; }
+ PX_FORCE_INLINE void incFront(PxU32 inc) { PX_ASSERT(SIZE-size() >= inc); mWriteCount+=inc; }
+ PX_FORCE_INLINE void incBack(PxU32 inc) { PX_ASSERT(size() >= inc); mReadCount+=inc; }
+
+ PX_FORCE_INLINE bool pushFront(const T& e)
+ {
+ if(!isFull())
+ {
+ mRing[mWriteCount&moduloMask] = e;
+ Ps::memoryBarrier();
+ mWriteCount++;
+ return true;
+ }
+ else
+ return false;
+
+ }
+
+ PX_FORCE_INLINE bool popBack(T& e)
+ {
+ if(!isEmpty())
+ {
+ e = mRing[mReadCount&moduloMask];
+ mReadCount++;
+ return true;
+ }
+ else
+ return false;
+ }
+
+private:
+ PX_FORCE_INLINE static PxU32 moduloDistance(PxI32 r, PxI32 w) { return PxU32((w-r)&moduloMask); }
+ PX_FORCE_INLINE static bool isFull(PxI32 r, PxI32 w) { return r!=w && moduloDistance(r,w)==0; }
+ PX_FORCE_INLINE static PxU32 size(PxI32 r, PxI32 w) { return isFull(r, w) ? SIZE : moduloDistance(r, w); }
+
+private:
+ static const PxU32 moduloMask = SIZE-1;
+ T mRing[SIZE];
+ volatile PxI32 mReadCount;
+ volatile PxI32 mWriteCount;
+};
+
+
+class InputEventBuffer: public SampleFramework::InputEventListener, public SampleAllocateable
+{
+public:
+
+ InputEventBuffer(PhysXSampleApplication& p);
+ virtual ~InputEventBuffer();
+
+ virtual void onKeyDownEx(SampleFramework::SampleUserInput::KeyCode keyCode, PxU32 wParam);
+ virtual void onAnalogInputEvent(const SampleFramework::InputEvent& , float val);
+ virtual void onDigitalInputEvent(const SampleFramework::InputEvent& , bool val);
+ virtual void onPointerInputEvent(const SampleFramework::InputEvent&, PxU32 x, PxU32 y, PxReal dx, PxReal dy, bool val);
+ void clear();
+ void flush();
+private:
+ PX_FORCE_INLINE void checkResetLastInput()
+ {
+ if(mResetInputCacheReq!=mResetInputCacheAck)
+ {
+ mLastKeyDownEx = NULL;
+ mLastDigitalInput = NULL;
+ mLastAnalogInput = NULL;
+ mLastPointerInput = NULL;
+ mResetInputCacheAck++;
+ PX_ASSERT(mResetInputCacheReq==mResetInputCacheAck);
+ }
+ }
+ struct EventType
+ {
+ virtual ~EventType() {}
+ virtual void report(PhysXSampleApplication& app) const { }
+ };
+ struct KeyDownEx: public EventType
+ {
+ virtual void report(PhysXSampleApplication& app) const;
+
+ bool isEqual(SampleFramework::SampleUserInput::KeyCode _keyCode, PxU32 _wParam)
+ {
+ return (_keyCode == keyCode) && (_wParam == wParam);
+ }
+
+ SampleFramework::SampleUserInput::KeyCode keyCode;
+ PxU32 wParam;
+ };
+ struct AnalogInput: public EventType
+ {
+ virtual void report(PhysXSampleApplication& app) const;
+
+ bool isEqual(SampleFramework::InputEvent _e, float _val)
+ {
+ return (_e.m_Id == e.m_Id) && (_e.m_Analog == e.m_Analog) && (_e.m_Sensitivity == e.m_Sensitivity) && (_val == val);
+ }
+
+ SampleFramework::InputEvent e;
+ float val;
+ };
+ struct DigitalInput: public EventType
+ {
+ virtual void report(PhysXSampleApplication& app) const;
+
+ bool isEqual(SampleFramework::InputEvent _e, bool _val)
+ {
+ return (_e.m_Id == e.m_Id) && (_e.m_Analog == e.m_Analog) && (_e.m_Sensitivity == e.m_Sensitivity) && (_val == val);
+ }
+
+ SampleFramework::InputEvent e;
+ bool val;
+ };
+ struct PointerInput: public EventType
+ {
+ virtual void report(PhysXSampleApplication& app) const;
+
+ bool isEqual(SampleFramework::InputEvent _e, PxU32 _x, PxU32 _y, PxReal _dx, PxReal _dy, bool _val)
+ {
+ return (_e.m_Id == e.m_Id) && (_e.m_Analog == e.m_Analog) && (_e.m_Sensitivity == e.m_Sensitivity) &&
+ (_x == x) && (_y == y) && (_dx == dx) && (_dy == dy) && (_val == val);
+ }
+
+ SampleFramework::InputEvent e;
+ PxU32 x;
+ PxU32 y;
+ PxReal dx;
+ PxReal dy;
+ bool val;
+ };
+
+ struct EventsUnion
+ {
+ template<class Event> PX_CUDA_CALLABLE PX_FORCE_INLINE Event& get()
+ {
+ return reinterpret_cast<Event&>(events);
+ }
+ template<class Event> PX_CUDA_CALLABLE PX_FORCE_INLINE const Event& get() const
+ {
+ return reinterpret_cast<const Event&>(events);
+ }
+ union
+ {
+ PxU8 eventType[sizeof(EventType)];
+ PxU8 keyDownEx[sizeof(KeyDownEx)];
+ PxU8 analogInput[sizeof(AnalogInput)];
+ PxU8 digitalInput[sizeof(DigitalInput)];
+ PxU8 pointerInput[sizeof(PointerInput)];
+ } events;
+ };
+
+ static const PxU32 MAX_EVENTS = 64;
+ static const PxU32 MAX_MOUSE_EVENTS = 48;
+ static const PxU32 MAX_ANALOG_EVENTS = 48;
+ RingBuffer<EventsUnion, MAX_EVENTS> mRingBuffer;
+ volatile PxU32 mResetInputCacheReq;
+ volatile PxU32 mResetInputCacheAck;
+ KeyDownEx* mLastKeyDownEx;
+ DigitalInput* mLastDigitalInput;
+ AnalogInput* mLastAnalogInput;
+ PointerInput* mLastPointerInput;
+ PhysXSampleApplication& mApp;
+ bool mClearBuffer;
+};
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/ParticleEmitter.cpp b/PhysX_3.4/Samples/SampleBase/ParticleEmitter.cpp
new file mode 100644
index 00000000..8d9d513f
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/ParticleEmitter.cpp
@@ -0,0 +1,210 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "ParticleEmitterRate.h"
+
+//----------------------------------------------------------------------------//
+
+#if PARTICLE_EMITTER_RANDOMIZE_EMISSION
+PxToolkit::BasicRandom ParticleEmitter::mRandom(42);
+#endif
+
+ParticleEmitter::ParticleEmitter(Shape::Enum shape, PxReal extentX, PxReal extentY, PxReal spacing) :
+ mRandomPos(0.0f),
+ mRandomAngle(0.0f),
+ mVelocity(1.0f),
+ mParticleMass(0.0f),
+ mNumSites(0),
+ mSpacingX(spacing),
+ mLocalPose(PxTransform()),
+ mFrameBody(NULL),
+ mExtentX(extentX),
+ mExtentY(extentY),
+ mShape(shape)
+{
+ PX_ASSERT(spacing > 0.0f);
+ updateDerivedBase();
+}
+
+//----------------------------------------------------------------------------//
+
+ParticleEmitter::~ParticleEmitter()
+{
+
+}
+
+//----------------------------------------------------------------------------//
+
+void ParticleEmitter::updateDerivedBase()
+{
+ PX_ASSERT(mSpacingX > 0.0f);
+ mSpacingY = mSpacingX * PxSqrt(3.0f) * 0.5f;
+ mSpacingZ = mSpacingX;
+
+ mNumX = 2*(int)floor(mExtentX/mSpacingX);
+ mNumY = 2*(int)floor(mExtentY/mSpacingY);
+
+ //SDS: limit minimal dimension to 1
+ if (mNumX == 0)
+ {
+ mNumX = 1;
+ mSpacingX = 0.0f;
+ }
+ if (mNumY == 0)
+ {
+ mNumY = 1;
+ mSpacingY = 0.0f;
+ }
+
+ mNumSites = mNumX * mNumY;
+
+ if (mShape == Shape::eELLIPSE)
+ {
+ if (mNumX > 1)
+ mEllipseRadius2 = 0.5f - 1.0f/(mNumX-1);
+ else
+ mEllipseRadius2 = 0.5f;
+ mEllipseRadius2 *= mEllipseRadius2;
+
+ mEllipseConstX0 = (mNumX-0.5f) * 0.5f;
+ mEllipseConstX1 = 1.0f/mNumX;
+ mEllipseConstY0 = (mNumY-1.0f) * 0.5f;
+ mEllipseConstY1 = PxSqrt(3.0f) * 0.5f / mNumY;
+ }
+ else
+ {
+ mEllipseRadius2 = 0;
+ mEllipseConstX0 = 0;
+ mEllipseConstX1 = 0;
+ mEllipseConstY0 = 0;
+ mEllipseConstY1 = 0;
+ }
+}
+
+//----------------------------------------------------------------------------//
+
+void ParticleEmitter::step(ParticleData& particles, PxReal dt, const PxVec3& externalAcceleration, PxReal maxParticleVelocity)
+{
+ initStep(particles, dt);
+ stepInternal(particles, dt, externalAcceleration, maxParticleVelocity);
+ finalizeStep();
+}
+
+//----------------------------------------------------------------------------//
+
+void ParticleEmitter::initStep(ParticleData& particles, PxReal dt)
+{
+ mLinMomentum = PxVec3(0.0f);
+ mAngMomentum = PxVec3(0.0f);
+
+ // state of frameBody
+ if (mFrameBody)
+ {
+ mBodyAngVel = mFrameBody->getAngularVelocity();
+ mBodyLinVel = mFrameBody->getLinearVelocity();
+ mBodyCenter = mFrameBody->getGlobalPose().p;
+ mGlobalPose = mFrameBody->getGlobalPose() * mLocalPose;
+ }
+ else
+ {
+ mBodyAngVel = PxVec3(0.0f);
+ mBodyLinVel = PxVec3(0.0f);
+ mBodyCenter = PxVec3(0.0f);
+ mGlobalPose = mLocalPose;
+ }
+
+ mAxisX = mGlobalPose.q.getBasisVector0();
+ mAxisY = mGlobalPose.q.getBasisVector1();
+ mAxisZ = mGlobalPose.q.getBasisVector2();
+
+ mBasePos = mGlobalPose.p
+ - mAxisX * (mNumX-0.5f)*0.5f*mSpacingX
+ - mAxisY * (mNumY-1.0f)*0.5f*mSpacingY;
+}
+
+//----------------------------------------------------------------------------//
+
+void ParticleEmitter::finalizeStep()
+{
+ // apply impulse on attached body
+ if (mFrameBody && mParticleMass > 0.0f)
+ {
+ mLinMomentum *= mParticleMass;
+ mAngMomentum *= mParticleMass;
+
+ mFrameBody->addForce(mLinMomentum, PxForceMode::eIMPULSE);
+ mFrameBody->addTorque(mAngMomentum, PxForceMode::eIMPULSE);
+ }
+}
+
+//----------------------------------------------------------------------------//
+
+void ParticleEmitter::computeSiteVelocity(PxVec3& siteVel, const PxVec3& sitePos)
+{
+ //velocity dir noise
+ PxReal noiseXYAngle = randInRange(0.0f, PxTwoPi);
+ PxReal noiseZAngle = randInRange(0.0f, mRandomAngle);
+
+ PxVec3 noiseDirVec = mAxisX * PxCos(noiseXYAngle) + mAxisY * PxSin(noiseXYAngle);
+ noiseDirVec.normalize();
+ noiseDirVec = mAxisZ * PxCos(noiseZAngle) + noiseDirVec * PxSin(noiseZAngle);
+
+ siteVel = noiseDirVec * mVelocity;
+
+ //add emitter repulsion
+ if (mParticleMass > 0.0f)
+ {
+ mLinMomentum -= siteVel;
+ mAngMomentum -= (sitePos - mBodyCenter).cross(siteVel);
+ }
+
+ if (mFrameBody)
+ siteVel += mBodyLinVel + (mBodyAngVel.cross(sitePos - mBodyCenter));
+}
+
+//----------------------------------------------------------------------------//
+
+bool ParticleEmitter::spawnParticle(ParticleData& data,
+ PxU32& num,
+ const PxU32 max,
+ const PxVec3& position,
+ const PxVec3& velocity)
+{
+ PX_ASSERT(PxI32(max) - PxI32(num) <= PxI32(data.maxParticles) - PxI32(data.numParticles));
+ if(num >= max)
+ return false;
+
+ data.positions[data.numParticles] = position;
+ data.velocities[data.numParticles] = velocity;
+ data.numParticles++;
+ num++;
+ return true;
+}
+
+//----------------------------------------------------------------------------//
diff --git a/PhysX_3.4/Samples/SampleBase/ParticleEmitter.h b/PhysX_3.4/Samples/SampleBase/ParticleEmitter.h
new file mode 100644
index 00000000..0167378b
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/ParticleEmitter.h
@@ -0,0 +1,205 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef PARTICLE_EMITTER_H
+#define PARTICLE_EMITTER_H
+
+#include "ParticleFactory.h"
+#include "PxTkRandom.h"
+
+using namespace PxToolkit;
+//----------------------------------------------------------------------------//
+
+#define PARTICLE_EMITTER_RANDOMIZE_EMISSION 1
+
+//----------------------------------------------------------------------------//
+
+class ParticleEmitter : public SampleAllocateable
+{
+public:
+
+ struct Shape
+ {
+ enum Enum
+ {
+ eELLIPSE = 0,
+ eRECTANGLE = 1,
+ };
+ };
+
+ ParticleEmitter(Shape::Enum shape, PxReal extentX, PxReal extentY, PxReal spacing);
+ virtual ~ParticleEmitter();
+
+ // Relative to mFrameBody, or relative to global frame, if mFrameBody == NULL
+ void setLocalPose(const PxTransform& pose) { mLocalPose = pose; }
+ PxTransform getLocalPose() const { return mLocalPose; }
+
+ void setFrameRigidBody(PxRigidDynamic* rigidBody){ mFrameBody = rigidBody; }
+ PxRigidDynamic* getFrameRigidBody() const { return mFrameBody; }
+
+ void setRandomPos(PxVec3 t) { mRandomPos = t; }
+ PxVec3 getRandomPos() const { return mRandomPos; }
+
+ void setRandomAngle(PxReal t) { mRandomAngle = t; }
+ PxReal getRandomAngle() const { return mRandomAngle; }
+
+ void setVelocity(PxReal t) { mVelocity = t; }
+ PxReal getVelocity() const { return mVelocity; }
+
+ // Used for two way interaction, zero meaning, there is none
+ void setParticleMass(PxReal m) { mParticleMass = m; }
+ PxReal getParticleMass() const { return mParticleMass; }
+
+ void step(ParticleData& particles, PxReal dt, const PxVec3& externalAcceleration, PxReal maxParticleVelocity);
+
+protected:
+
+ virtual void stepInternal(ParticleData& particles, PxReal dt, const PxVec3& externalAcceleration, PxReal maxParticleVelocity) = 0;
+
+ void initStep(ParticleData& particles, PxReal dt);
+ void finalizeStep();
+
+ PX_INLINE void computePositionNoise(PxVec3& posNoise);
+ void computeSiteVelocity(PxVec3& siteVel, const PxVec3& sitePos);
+ PX_INLINE bool isOutsideShape(PxU32 x, PxU32 y, PxReal offset) { return mShape == Shape::eELLIPSE && outsideEllipse(x, y, offset); }
+
+ static bool spawnParticle(
+ ParticleData& data,
+ PxU32& num,
+ const PxU32 max,
+ const PxVec3& position,
+ const PxVec3& velocity);
+
+ static PX_INLINE PxReal randInRange(PxReal a,PxReal b);
+ static PX_INLINE PxU32 randInRange(PxU32 range);
+#if PARTICLE_EMITTER_RANDOMIZE_EMISSION
+ static PxToolkit::BasicRandom mRandom;
+#endif
+
+protected:
+
+ PxVec3 mRandomPos;
+ PxReal mRandomAngle;
+ PxReal mVelocity;
+ PxReal mParticleMass;
+
+ //derived quantities
+ PxU32 mNumSites;
+ PxU32 mNumX;
+ PxU32 mNumY;
+ PxReal mSpacingX;
+ PxReal mSpacingY;
+ PxReal mSpacingZ;
+
+ //only needed during step computations.
+ PxVec3 mAxisX;
+ PxVec3 mAxisY;
+ PxVec3 mAxisZ;
+ PxVec3 mBasePos;
+
+private:
+
+ PX_INLINE bool outsideEllipse(PxU32 x, PxU32 y, PxReal offset);
+ void updateDerivedBase();
+
+private:
+
+ PxTransform mLocalPose;
+ PxRigidDynamic* mFrameBody;
+
+ PxReal mExtentX;
+ PxReal mExtentY;
+ Shape::Enum mShape;
+
+ //state derived quantities
+ PxReal mEllipseRadius2;
+ PxReal mEllipseConstX0;
+ PxReal mEllipseConstX1;
+ PxReal mEllipseConstY0;
+ PxReal mEllipseConstY1;
+
+ //only needed during step computations.
+ PxVec3 mBodyAngVel;
+ PxVec3 mBodyLinVel;
+ PxVec3 mBodyCenter;
+ PxTransform mGlobalPose;
+ PxVec3 mLinMomentum;
+ PxVec3 mAngMomentum;
+};
+
+//----------------------------------------------------------------------------//
+
+PX_INLINE bool ParticleEmitter::outsideEllipse(PxU32 x, PxU32 y, PxReal offset)
+{
+ PxReal cX = (x + offset - mEllipseConstX0)*mEllipseConstX1;
+ PxReal cY = (y - mEllipseConstY0)*mEllipseConstY1;
+ return ( cX*cX + cY*cY >= mEllipseRadius2);
+}
+
+//----------------------------------------------------------------------------//
+
+PX_INLINE void ParticleEmitter::computePositionNoise(PxVec3& posRand)
+{
+ posRand.x = randInRange(-mRandomPos.x, mRandomPos.x);
+ posRand.y = randInRange(-mRandomPos.y, mRandomPos.y);
+ posRand.z = randInRange(-mRandomPos.z, mRandomPos.z);
+}
+
+//----------------------------------------------------------------------------//
+
+PX_INLINE PxReal ParticleEmitter::randInRange(PxReal a, PxReal b)
+{
+#if PARTICLE_EMITTER_RANDOMIZE_EMISSION
+ return Rand(a, b);
+#else
+ return a + (b-a)/2.0f;
+#endif
+}
+
+//----------------------------------------------------------------------------//
+
+PX_INLINE PxU32 ParticleEmitter::randInRange(PxU32 range)
+{
+#if PARTICLE_EMITTER_RANDOMIZE_EMISSION
+ PxU32 retval = Rand();
+ if(range > 0x7fff)
+ {
+ retval = (retval << 15) | Rand();
+ retval = (retval << 15) | Rand();
+ }
+ return retval % range;
+#else
+ static PxU32 noRandomVal = 0;
+ return noRandomVal++;
+#endif
+}
+
+//----------------------------------------------------------------------------//
+
+#endif // PARTICLE_EMITTER_H
diff --git a/PhysX_3.4/Samples/SampleBase/ParticleEmitterPressure.cpp b/PhysX_3.4/Samples/SampleBase/ParticleEmitterPressure.cpp
new file mode 100644
index 00000000..a2f857c0
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/ParticleEmitterPressure.cpp
@@ -0,0 +1,221 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "ParticleEmitterPressure.h"
+#include "PsMathUtils.h"
+
+//----------------------------------------------------------------------------//
+
+ParticleEmitterPressure::ParticleEmitterPressure(ParticleEmitter::Shape::Enum shape, PxReal extentX, PxReal extentY, PxReal spacing) :
+ ParticleEmitter(shape, extentX, extentY, spacing),
+ mSimulationAcceleration(0.0f),
+ mSimulationMaxVelocity(1.0f),
+ mMaxRate(10000.0f)
+{
+ mMaxZNoiseOffset = spacing/4.0f;
+ mSites.resize(mNumSites);
+ clearPredecessors();
+}
+
+//----------------------------------------------------------------------------//
+
+ParticleEmitterPressure::~ParticleEmitterPressure()
+{
+}
+
+//----------------------------------------------------------------------------//
+
+void ParticleEmitterPressure::stepInternal(ParticleData& particles, PxReal dt, const PxVec3& externalAcceleration, PxReal maxParticleVelocity)
+{
+ PX_ASSERT(mNumX > 0 && mNumY > 0);
+
+ mSimulationAcceleration = externalAcceleration;
+ mSimulationMaxVelocity = maxParticleVelocity;
+
+ PxU32 numEmittedParticles = 0;
+
+ PxU32 maxParticlesPerStep = (PxU32)physx::shdfnd::floor(mMaxRate*dt);
+ PxU32 maxParticles = PxMin(particles.maxParticles - particles.numParticles, maxParticlesPerStep);
+
+ PxU32 siteNr = 0;
+ for(PxU32 y = 0; y != mNumY; y++)
+ {
+ PxReal offset = 0.0f;
+ if (y%2) offset = mSpacingX * 0.5f;
+
+ for(PxU32 x = 0; x != mNumX; x++)
+ {
+ if (isOutsideShape(x,y,offset))
+ continue;
+
+ SiteData& siteData = mSites[siteNr];
+
+ //position noise
+ PxVec3 posNoise;
+ posNoise.x = randInRange(-mRandomPos.x, mRandomPos.x);
+ posNoise.y = randInRange(-mRandomPos.y, mRandomPos.y);
+
+ //special code for Z noise
+ if (!siteData.predecessor)
+ siteData.noiseZ = randInRange(-mRandomPos.z, mRandomPos.z);
+ else
+ {
+ PxReal noiseZOffset = PxMin(mMaxZNoiseOffset, mRandomPos.z);
+ siteData.noiseZ += randInRange(-noiseZOffset, noiseZOffset);
+ siteData.noiseZ = PxClamp(siteData.noiseZ, mRandomPos.z, -mRandomPos.z);
+ }
+
+ posNoise.z = siteData.noiseZ;
+
+ //set position
+ PxVec3 sitePos = mBasePos + mAxisX*(offset+mSpacingX*x) + mAxisY*(mSpacingY*y) + mAxisZ*siteData.noiseZ;
+ PxVec3 particlePos = sitePos + mAxisX*posNoise.x + mAxisY*posNoise.y;
+
+ PxVec3 siteVel;
+ computeSiteVelocity(siteVel, particlePos);
+
+ if (siteData.predecessor)
+ {
+ predictPredecessorPos(siteData, dt);
+ }
+ else {
+ bool isSpawned = spawnParticle(particles, numEmittedParticles, maxParticles, particlePos, siteVel);
+ if(isSpawned)
+ {
+ updatePredecessor(siteData, particlePos, siteVel);
+ }
+ else
+ {
+ siteData.predecessor = false;
+ return;
+ }
+ }
+
+ bool allSpawned = stepEmissionSite(siteData, particles, numEmittedParticles, maxParticles, sitePos, siteVel, dt);
+ if(!allSpawned)
+ return;
+
+ siteNr++;
+ }
+ }
+}
+
+//----------------------------------------------------------------------------//
+
+void ParticleEmitterPressure::clearPredecessors()
+{
+ PX_ASSERT(mSites.size() == mNumSites);
+ for (PxU32 i = 0; i < mNumSites; i++)
+ mSites[i].predecessor = false;
+}
+
+//----------------------------------------------------------------------------//
+
+bool ParticleEmitterPressure::stepEmissionSite(
+ SiteData& siteData,
+ ParticleData& spawnData,
+ PxU32& spawnNum,
+ const PxU32 spawnMax,
+ const PxVec3 &sitePos,
+ const PxVec3 &siteVel,
+ const PxReal dt)
+{
+ PxReal maxDistanceMoved = 5.0f * mSpacingZ; // don't generate long particle beams
+
+ /**
+ * Find displacement vector of the particle's motion this frame
+ * this is not necessarily v*stepSize because a collision might have occured
+ */
+ PxVec3 displacement = siteData.position - sitePos;
+ PxVec3 normal = displacement;
+ PxReal distanceMoved = normal.normalize();
+
+ if (distanceMoved > maxDistanceMoved)
+ distanceMoved = maxDistanceMoved;
+
+ /**
+ * Place particles along line between emission point and new position
+ * starting backwards from the new position
+ * spacing between the particles is the rest spacing of the fluid
+ */
+ PxReal lastPlaced = 0.0f;
+ while((lastPlaced + mSpacingZ) <= distanceMoved)
+ {
+ PxVec3 pos = sitePos + normal * (distanceMoved - (lastPlaced + mSpacingZ));
+
+ PxVec3 posNoise;
+ posNoise.x = randInRange(-mRandomPos.x, mRandomPos.x);
+ posNoise.y = randInRange(-mRandomPos.y, mRandomPos.y);
+
+ pos += mAxisX*posNoise.x + mAxisY*posNoise.y;
+
+ bool isSpawned = spawnParticle(spawnData, spawnNum, spawnMax, pos, siteVel);
+ if(isSpawned)
+ {
+ updatePredecessor(siteData, pos, siteVel);
+ lastPlaced += mSpacingZ;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------------//
+
+void ParticleEmitterPressure::predictPredecessorPos(SiteData& siteData, PxReal dt)
+{
+ PxReal compensationHack = 2.0f/3.0f;
+
+ siteData.velocity += dt*(mSimulationAcceleration);
+ PxReal velAbs = siteData.velocity.magnitude();
+ PxReal maxVel = mSimulationMaxVelocity;
+
+ if (velAbs > maxVel)
+ {
+ PxReal scale = maxVel/velAbs;
+ siteData.velocity *= scale;
+ }
+
+ siteData.position += dt*compensationHack*siteData.velocity;
+}
+
+//----------------------------------------------------------------------------//
+
+void ParticleEmitterPressure::updatePredecessor(SiteData& siteData, const PxVec3& position, const PxVec3& velocity)
+{
+ siteData.predecessor = true;
+ siteData.position = position;
+ siteData.velocity = velocity;
+}
+
+//----------------------------------------------------------------------------//
+
diff --git a/PhysX_3.4/Samples/SampleBase/ParticleEmitterPressure.h b/PhysX_3.4/Samples/SampleBase/ParticleEmitterPressure.h
new file mode 100644
index 00000000..c14313d2
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/ParticleEmitterPressure.h
@@ -0,0 +1,90 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef PARTICLE_EMITTER_PRESSURE_H
+#define PARTICLE_EMITTER_PRESSURE_H
+
+//----------------------------------------------------------------------------//
+
+#include "ParticleEmitter.h"
+
+//----------------------------------------------------------------------------//
+
+class ParticleEmitterPressure : public ParticleEmitter
+{
+
+public:
+ ParticleEmitterPressure(ParticleEmitter::Shape::Enum shape, PxReal extentX, PxReal extentY, PxReal spacing);
+ virtual ~ParticleEmitterPressure();
+
+ virtual void stepInternal(ParticleData& particles, PxReal dt, const PxVec3& externalAcceleration, PxReal maxParticleVelocity);
+
+ void setMaxRate(PxReal v) { mMaxRate = v; }
+ PxReal getMaxRate() const { return mMaxRate; }
+
+
+private:
+
+ struct SiteData
+ {
+ PxVec3 position;
+ PxVec3 velocity;
+ bool predecessor;
+ PxReal noiseZ;
+ };
+
+private:
+
+ PxVec3 mSimulationAcceleration;
+ PxReal mSimulationMaxVelocity;
+
+ void clearPredecessors();
+
+ bool stepEmissionSite(
+ SiteData& siteData,
+ ParticleData& spawnData,
+ PxU32& spawnNum,
+ const PxU32 spawnMax,
+ const PxVec3 &sitePos,
+ const PxVec3 &siteVel,
+ const PxReal dt);
+
+ void predictPredecessorPos(SiteData& siteData, PxReal dt);
+ void updatePredecessor(SiteData& siteData, const PxVec3& position, const PxVec3& velocity);
+
+private:
+
+ std::vector<SiteData> mSites;
+ PxReal mMaxZNoiseOffset;
+ PxReal mMaxRate;
+};
+
+//----------------------------------------------------------------------------//
+
+#endif // PARTICLE_EMITTER_PRESSURE_H
diff --git a/PhysX_3.4/Samples/SampleBase/ParticleEmitterRate.cpp b/PhysX_3.4/Samples/SampleBase/ParticleEmitterRate.cpp
new file mode 100644
index 00000000..3354049e
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/ParticleEmitterRate.cpp
@@ -0,0 +1,203 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "ParticleEmitterRate.h"
+#include "PsHash.h"
+
+//----------------------------------------------------------------------------//
+
+/**
+If the emitter has less emission sites than PARTICLE_EMITTER_SPARSE_FACTOR
+times the number of particles it needs to emit, "sparse mode" code path is applied.
+*/
+#define PARTICLE_EMITTER_SPARSE_FACTOR 4
+
+/**
+Defines how many random sites are choosen before giving up, avoiding spawning more than
+one particle per site.
+*/
+#define PARTICLE_EMITTER_NUM_HASH_TRIALS 10
+
+//----------------------------------------------------------------------------//
+
+ParticleEmitterRate::ParticleEmitterRate(Shape::Enum shape, PxReal extentX, PxReal extentY, PxReal spacing) :
+ ParticleEmitter(shape, extentX, extentY, spacing),
+ mRate(1.0f),
+ mParticlesToEmit(0)
+{
+}
+
+//----------------------------------------------------------------------------//
+
+ParticleEmitterRate::~ParticleEmitterRate()
+{
+}
+
+//----------------------------------------------------------------------------//
+
+void ParticleEmitterRate::stepInternal(ParticleData& particles, PxReal dt, const PxVec3& externalAcceleration, PxReal maxParticleVelocity)
+{
+ PX_ASSERT(mNumX > 0 && mNumY > 0);
+ PxU32 numEmittedParticles = 0;
+
+ //figure out how many particle have to be emitted with the given rate.
+ mParticlesToEmit += mRate*dt;
+ PxU32 numEmit = (PxU32)(mParticlesToEmit);
+ if(numEmit == 0)
+ return;
+
+ PxU32 numLayers = (PxU32)(numEmit / (mNumX * mNumY)) + 1;
+ PxReal layerDistance = dt * mVelocity / numLayers;
+
+ PxU32 sparseMax = 0;
+
+ //either shuffle or draw without repeat (approximation)
+ bool denseEmission = (PxU32(PARTICLE_EMITTER_SPARSE_FACTOR*numEmit) > mNumSites);
+ if(denseEmission)
+ {
+ initDenseSites();
+ }
+ else
+ {
+ sparseMax = PARTICLE_EMITTER_SPARSE_FACTOR*numEmit;
+ mSites.resize(sparseMax);
+ }
+
+ // generate particles
+ PxU32 l = 0;
+ while(numEmit > 0)
+ {
+ PxVec3 layerVec = mAxisZ * (layerDistance * (PxReal)l);
+ l++;
+
+ if(denseEmission)
+ shuffleDenseSites();
+ else
+ initSparseSiteHash(numEmit, sparseMax);
+
+ for (PxU32 i = 0; i < mNumSites && numEmit > 0; i++)
+ {
+ PxU32 emissionSite;
+ if (denseEmission)
+ emissionSite = mSites[i];
+ else
+ emissionSite = pickSparseEmissionSite(sparseMax);
+
+ PxU32 x = emissionSite / mNumY;
+ PxU32 y = emissionSite % mNumY;
+
+ PxReal offset = 0.0f;
+ if (y%2) offset = mSpacingX * 0.5f;
+
+ if (isOutsideShape(x,y,offset))
+ continue;
+
+ //position noise
+ PxVec3 posNoise;
+ posNoise.x = randInRange(-mRandomPos.x, mRandomPos.x);
+ posNoise.y = randInRange(-mRandomPos.y, mRandomPos.y);
+ posNoise.z = randInRange(-mRandomPos.z, mRandomPos.z);
+
+ PxVec3 emissionPoint = mBasePos + layerVec +
+ mAxisX*(posNoise.x+offset+mSpacingX*x) + mAxisY*(posNoise.y+mSpacingY*y) + mAxisZ*posNoise.z;
+
+ PxVec3 particleVelocity;
+ computeSiteVelocity(particleVelocity, emissionPoint);
+
+ bool isSpawned = spawnParticle(particles, numEmittedParticles, particles.maxParticles - particles.numParticles, emissionPoint, particleVelocity);
+ if(isSpawned)
+ {
+ numEmit--;
+ mParticlesToEmit -= 1.0f;
+ }
+ else
+ return;
+ }
+ }
+}
+
+//----------------------------------------------------------------------------//
+
+void ParticleEmitterRate::initDenseSites()
+{
+ mSites.resize(mNumSites);
+
+ for(PxU32 i = 0; i < mNumSites; i++)
+ mSites[i] = i;
+}
+
+//----------------------------------------------------------------------------//
+
+void ParticleEmitterRate::shuffleDenseSites()
+{
+ PxU32 i,j;
+ PX_ASSERT(mSites.size() == mNumSites);
+
+ for (i = 0; i < mNumSites; i++)
+ {
+ j = randInRange(mNumSites);
+ PX_ASSERT(j<mNumSites);
+
+ PxU32 k = mSites[i];
+ mSites[i] = mSites[j];
+ mSites[j] = k;
+ }
+}
+
+//----------------------------------------------------------------------------//
+
+void ParticleEmitterRate::initSparseSiteHash(PxU32 numEmit, PxU32 sparseMax)
+{
+ PX_ASSERT(PxU32(PARTICLE_EMITTER_SPARSE_FACTOR*numEmit) <= sparseMax);
+ PX_ASSERT(mSites.size() == sparseMax);
+ for(PxU32 i = 0; i < sparseMax; i++)
+ mSites[i] = 0xffffffff;
+}
+
+//----------------------------------------------------------------------------//
+
+PxU32 ParticleEmitterRate::pickSparseEmissionSite(PxU32 sparseMax)
+{
+ PxU32 emissionSite = randInRange(mNumSites);
+ PxU32 hashKey = Ps::hash(emissionSite);
+ PxU32 hashIndex = hashKey % sparseMax;
+ PxU32 numTrials = 0;
+ while(mSites[hashIndex] != 0xffffffff && numTrials < PARTICLE_EMITTER_NUM_HASH_TRIALS)
+ {
+ emissionSite = randInRange(mNumSites);
+ hashKey = Ps::hash(emissionSite);
+ hashIndex = hashKey % sparseMax;
+ numTrials++;
+ }
+ //allow sites to be used multiple times if mSites[hashIndex] == 0xffffffff
+ return mSites[hashIndex] = emissionSite;
+}
+
+//----------------------------------------------------------------------------//
+
diff --git a/PhysX_3.4/Samples/SampleBase/ParticleEmitterRate.h b/PhysX_3.4/Samples/SampleBase/ParticleEmitterRate.h
new file mode 100644
index 00000000..6e503bfc
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/ParticleEmitterRate.h
@@ -0,0 +1,64 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef PARTICLE_EMITTER_RATE_H
+#define PARTICLE_EMITTER_RATE_H
+
+//----------------------------------------------------------------------------//
+
+#include "ParticleEmitter.h"
+
+//----------------------------------------------------------------------------//
+
+class ParticleEmitterRate : public ParticleEmitter
+{
+public:
+ ParticleEmitterRate(ParticleEmitter::Shape::Enum shape, PxReal extentX, PxReal extentY, PxReal spacing);
+ virtual ~ParticleEmitterRate();
+
+ virtual void stepInternal(ParticleData& particles, PxReal dt, const PxVec3& externalAcceleration, PxReal maxParticleVelocity);
+
+ void setRate(PxReal t) { mRate = t; }
+ PxReal getRate() const { return mRate; }
+
+private:
+
+ void initDenseSites();
+ void shuffleDenseSites();
+ void initSparseSiteHash(PxU32 numEmit, PxU32 sparseMax);
+ PxU32 pickSparseEmissionSite(PxU32 sparseMax);
+
+ PxReal mRate;
+ PxReal mParticlesToEmit;
+ std::vector<PxU32> mSites;
+};
+
+//----------------------------------------------------------------------------//
+
+#endif // PARTICLE_EMITTER_RATE_H
diff --git a/PhysX_3.4/Samples/SampleBase/ParticleFactory.cpp b/PhysX_3.4/Samples/SampleBase/ParticleFactory.cpp
new file mode 100644
index 00000000..bf554f26
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/ParticleFactory.cpp
@@ -0,0 +1,123 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "ParticleFactory.h"
+#include "PsMathUtils.h"
+#include "PxTkRandom.h"
+
+using namespace PxToolkit;
+//----------------------------------------------------------------------------//
+
+void CreateParticleAABB(ParticleData& particleData, const PxBounds3& aabb, const PxVec3& vel, float distance)
+{
+ PxVec3 aabbDim = aabb.getExtents() * 2.0f;
+
+ unsigned sideNumX = (unsigned)PxMax(1.0f, physx::shdfnd::floor(aabbDim.x / distance));
+ unsigned sideNumY = (unsigned)PxMax(1.0f, physx::shdfnd::floor(aabbDim.y / distance));
+ unsigned sideNumZ = (unsigned)PxMax(1.0f, physx::shdfnd::floor(aabbDim.z / distance));
+
+ for(unsigned i=0; i<sideNumX; i++)
+ for(unsigned j=0; j<sideNumY; j++)
+ for(unsigned k=0; k<sideNumZ; k++)
+ {
+ if(particleData.numParticles >= particleData.maxParticles)
+ break;
+
+ PxVec3 p = PxVec3(i*distance,j*distance,k*distance);
+ p += aabb.minimum;
+
+ particleData.positions[particleData.numParticles] = p;
+ particleData.velocities[particleData.numParticles] = vel;
+ particleData.numParticles++;
+ }
+}
+
+//----------------------------------------------------------------------------//
+
+void CreateParticleSphere(ParticleData& particleData, const PxVec3& pos, const PxVec3& vel, float distance, unsigned sideNum)
+{
+ float rad = sideNum*distance*0.5f;
+ PxVec3 offset((sideNum-1)*distance*0.5f);
+
+ for(unsigned i=0; i<sideNum; i++)
+ for(unsigned j=0; j<sideNum; j++)
+ for(unsigned k=0; k<sideNum; k++)
+ {
+ if(particleData.numParticles >= particleData.maxParticles)
+ break;
+
+ PxVec3 p = PxVec3(i*distance,j*distance,k*distance);
+ if((p-PxVec3(rad,rad,rad)).magnitude() < rad)
+ {
+ p += pos;
+ p -= offset; // ISG: for symmetry
+
+ particleData.positions[particleData.numParticles] = p;
+ particleData.velocities[particleData.numParticles] = vel;
+ particleData.numParticles++;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------------------------------------------//
+void CreateParticleRand(ParticleData& particleData, const PxVec3& center, const PxVec3& range,const PxVec3& vel)
+{
+ PxToolkit::SetSeed(0);
+ while(particleData.numParticles < particleData.maxParticles)
+ {
+ PxVec3 p(Rand(-range.x, range.x),
+ Rand(-range.y, range.y),
+ Rand(-range.z, range.z));
+
+ p += center;
+
+ PxVec3 v(Rand(-vel.x, vel.x),
+ Rand(-vel.y, vel.y),
+ Rand(-vel.z, vel.z));
+
+ particleData.positions[particleData.numParticles] = p;
+ particleData.velocities[particleData.numParticles] = vel;
+ particleData.numParticles++;
+ }
+}
+
+//----------------------------------------------------------------------------//
+
+void SetParticleRestOffsetVariance(ParticleData& particleData, PxF32 maxRestOffset, PxF32 restOffsetVariance)
+{
+ PxToolkit::SetSeed(0);
+
+ if (particleData.restOffsets.size() == 0)
+ particleData.restOffsets.resize(particleData.maxParticles);
+
+ for (PxU32 i = 0 ; i < particleData.numParticles; ++i)
+ particleData.restOffsets[i] = maxRestOffset*(1.0f - Rand(0.0f, restOffsetVariance));
+}
+
+//----------------------------------------------------------------------------//
diff --git a/PhysX_3.4/Samples/SampleBase/ParticleFactory.h b/PhysX_3.4/Samples/SampleBase/ParticleFactory.h
new file mode 100644
index 00000000..cdbe25ec
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/ParticleFactory.h
@@ -0,0 +1,73 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef PARTICLE_FACTORY_H
+#define PARTICLE_FACTORY_H
+
+//----------------------------------------------------------------------------//
+#include "PxPhysicsAPI.h"
+#include "PhysXSampleApplication.h"
+
+//----------------------------------------------------------------------------//
+
+struct ParticleData : public SampleAllocateable
+{
+ ParticleData() : maxParticles(0), numParticles(0) {}
+
+ ParticleData(PxU32 _maxParticles)
+ {
+ initialize(_maxParticles);
+ }
+
+ void initialize(PxU32 _maxParticles)
+ {
+ maxParticles = _maxParticles;
+ numParticles = 0;
+ positions.resize(maxParticles);
+ velocities.resize(maxParticles);
+ restOffsets.resize(0);
+ }
+
+ SampleArray<PxVec3> positions;
+ SampleArray<PxVec3> velocities;
+ SampleArray<PxF32> restOffsets;
+ PxU32 maxParticles;
+ PxU32 numParticles;
+};
+
+//----------------------------------------------------------------------------//
+
+void CreateParticleAABB(ParticleData& particleData, const PxBounds3& aabb, const PxVec3& vel, float distance);
+void CreateParticleSphere(ParticleData& particleData, const PxVec3& pos, const PxVec3& vel, float distance, unsigned sideNum);
+void CreateParticleRand(ParticleData& particleData, const PxVec3& center, const PxVec3& range,const PxVec3& vel);
+void SetParticleRestOffsetVariance(ParticleData& particleData, PxF32 maxRestOffset, PxF32 restOffsetVariance);
+
+//----------------------------------------------------------------------------//
+
+#endif // PARTICLE_FACTORY_H
diff --git a/PhysX_3.4/Samples/SampleBase/ParticleSystem.cpp b/PhysX_3.4/Samples/SampleBase/ParticleSystem.cpp
new file mode 100644
index 00000000..b79afcff
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/ParticleSystem.cpp
@@ -0,0 +1,550 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "PxPhysXConfig.h"
+
+#if PX_USE_PARTICLE_SYSTEM_API
+
+#include "foundation/PxMemory.h"
+#include "ParticleSystem.h"
+#include "ParticleFactory.h"
+#include "PsMathUtils.h"
+#include "PsBitUtils.h"
+#include "PxTkFile.h"
+#include "PhysXSample.h"
+#include "SampleArray.h"
+#include <algorithm>
+
+#if defined(RENDERER_ENABLE_CUDA_INTEROP)
+#include <cuda.h>
+
+namespace
+{
+ void checkSuccess(CUresult r)
+ {
+ PX_ASSERT(r == CUDA_SUCCESS);
+ }
+}
+
+#endif
+
+ParticleSystem::ParticleSystem(PxParticleBase* _mParticleSystem, bool _useInstancedMeshes) :
+ mParticleSystem(_mParticleSystem),
+ mParticlesPositions(_mParticleSystem->getMaxParticles()),
+ mParticlesVelocities(_mParticleSystem->getMaxParticles()),
+ mParticlesOrientations(_mParticleSystem->getMaxParticles()),
+ mParticleLifetime(0.0f),
+ mValidParticleRange(0),
+ mUseInstancedMeshes(_useInstancedMeshes),
+ mParticlesOrientationsDevice(0),
+ mParticleLifetimeDevice(0),
+ mParticleValidityDevice(0),
+ mCtxMgr(NULL)
+{
+ mNumParticles = _mParticleSystem->getMaxParticles();
+ setUseLifetime(false);
+ if(mUseInstancedMeshes)
+ {
+ initializeParticlesOrientations();
+ }
+ mIndexPool = PxParticleExt::createIndexPool(mNumParticles);
+ mParticleValidity = (PxU32*)PX_ALLOC(((_mParticleSystem->getMaxParticles() + 31) >> 5) << 2, "validParticleBitmap");
+
+#ifdef RENDERER_ENABLE_CUDA_INTEROP
+
+ PxScene* scene = _mParticleSystem->getScene();
+ if (scene)
+ {
+ PxGpuDispatcher* dispatcher = scene->getTaskManager()->getGpuDispatcher();
+ // contxt must be created in at least one valid interop mode
+ if (dispatcher && (mCtxMgr = dispatcher->getCudaContextManager()) &&
+ mCtxMgr->getInteropMode() != PxCudaInteropMode::D3D10_INTEROP &&
+ mCtxMgr->getInteropMode() != PxCudaInteropMode::D3D11_INTEROP)
+ {
+ mCtxMgr = NULL;
+ }
+ }
+
+ if (mCtxMgr)
+ {
+ mCtxMgr->acquireContext();
+
+ checkSuccess(cuMemAlloc(&mParticleValidityDevice, sizeof(PxU32)*(_mParticleSystem->getMaxParticles() + 31) >> 5));
+ checkSuccess(cuMemAlloc(&mParticleLifetimeDevice, sizeof(PxU32)*(_mParticleSystem->getMaxParticles())));
+
+ if(mUseInstancedMeshes)
+ {
+ checkSuccess(cuMemAlloc(&mParticlesOrientationsDevice, sizeof(PxMat33)*_mParticleSystem->getMaxParticles()));
+ checkSuccess(cuMemcpyHtoDAsync(mParticlesOrientationsDevice, &mParticlesOrientations[0], sizeof(PxMat33)*_mParticleSystem->getMaxParticles(), 0));
+ }
+
+ mCtxMgr->releaseContext();
+ }
+#endif
+}
+
+void ParticleSystem::initializeParticlesOrientations()
+{
+ for(PxU32 i = 0; i < mParticleSystem->getMaxParticles(); ++i)
+ {
+ mParticlesOrientations[i].column2 = PxVec3(getSampleRandom().rand(0.0f, 1.0f),
+ getSampleRandom().rand(0.0f, 1.0f),
+ getSampleRandom().rand(0.0f, 1.0f)).getNormalized();
+ PxVec3 vUp(0.0f, 1.0f, 0.0f);
+ mParticlesOrientations[i].column0 = vUp.cross(mParticlesOrientations[i].column2).getNormalized();
+ mParticlesOrientations[i].column1 = mParticlesOrientations[i].column2.
+ cross(mParticlesOrientations[i].column0).
+ getNormalized();
+ }
+}
+
+ParticleSystem::~ParticleSystem()
+{
+#ifdef RENDERER_ENABLE_CUDA_INTEROP
+ if (mCtxMgr)
+ {
+ mCtxMgr->acquireContext();
+ checkSuccess(cuMemFree(mParticleValidityDevice));
+ checkSuccess(cuMemFree(mParticleLifetimeDevice));
+ checkSuccess(cuMemFree(mParticlesOrientationsDevice));
+ mCtxMgr->releaseContext();
+ }
+#endif
+
+ PX_FREE(mParticleValidity);
+ if (mParticleSystem)
+ {
+ mParticleSystem->release();
+ mParticleSystem = NULL;
+ }
+ if (mIndexPool)
+ {
+ mIndexPool->release();
+ mIndexPool = NULL;
+ }
+}
+
+/* enables limiting particles lifetime */
+void ParticleSystem::setUseLifetime(bool use)
+{
+ mUseLifetime = use;
+}
+
+/* returns true if limiting particles lifetime is enabled */
+bool ParticleSystem::useLifetime()
+{
+ return mUseLifetime;
+}
+
+/* setUseLifetime(true) before setting this */
+void ParticleSystem::setLifetime(PxReal lt)
+{
+ PX_ASSERT(lt >= 0.0f);
+ mParticleLifetime = lt;
+ mParticleLifes.resize(mParticleSystem->getMaxParticles());
+ std::fill(mParticleLifes.begin(), mParticleLifes.end(), mParticleLifetime);
+}
+
+/* Modifies rotation matrix of the particle
+ Different rotation rules here.
+*/
+void ParticleSystem::modifyRotationMatrix(PxMat33& rotMatrix, PxReal deltaTime, const PxVec3& velocity)
+{
+ PxVec3 delta = PxVec3(rotMatrix.column1 -
+ rotMatrix.column0).getNormalized() *
+ deltaTime *
+ velocity.magnitude();
+ //PxVec3 vUp(0.0f, 1.0f, 0.0f);
+ rotMatrix.column2 = (rotMatrix.column2 + delta).getNormalized();
+ rotMatrix.column0 = rotMatrix.column1.cross(rotMatrix.column2).getNormalized();
+ rotMatrix.column1 = rotMatrix.column2.cross(rotMatrix.column0).getNormalized();
+}
+
+
+/* fetches particles positions from library,
+ removes invalid particles
+ (intersected with drain, non-positive lifetime),
+ creates new particles */
+void ParticleSystem::update(float deltaTime)
+{
+ mNumParticles = 0;
+ PxParticleReadData* mParticleSystemData = mParticleSystem->lockParticleReadData();
+ PX_ASSERT(mParticleSystemData);
+ std::vector<PxU32> mTmpIndexArray;
+ PxU32 newValidRange = 0;
+ if (mParticleSystemData->validParticleRange > 0)
+ {
+ PxStrideIterator<const PxVec3> positions(mParticleSystemData->positionBuffer);
+ PxStrideIterator<const PxVec3> velocities(mParticleSystemData->velocityBuffer);
+ PxStrideIterator<const PxParticleFlags> particleFlags(mParticleSystemData->flagsBuffer);
+ PxMemCopy(mParticleValidity, mParticleSystemData->validParticleBitmap, ((mParticleSystemData->validParticleRange + 31) >> 5) << 2);
+
+ // copy particles positions
+ for (PxU32 w = 0; w <= (mParticleSystemData->validParticleRange-1) >> 5; w++)
+ {
+ for (PxU32 b = mParticleSystemData->validParticleBitmap[w]; b; b &= b-1)
+ {
+ PxU32 index = (w << 5 | Ps::lowestSetBit(b));
+ bool removed = false;
+ if (particleFlags[index] & PxParticleFlag::eCOLLISION_WITH_DRAIN ||
+ particleFlags[index] & PxParticleFlag::eSPATIAL_DATA_STRUCTURE_OVERFLOW)
+ {
+ mTmpIndexArray.push_back(index);
+ removed = true;
+ }
+ else if(mUseLifetime)
+ {
+ if(mParticleLifes[index] < 0.0)
+ {
+ mParticleLifes[index] = mParticleLifetime;
+ mTmpIndexArray.push_back(index);
+ removed = true;
+ }
+ }
+ if(!removed)
+ {
+ mParticlesPositions[index] = positions[index];
+ mParticlesVelocities[index] = velocities.ptr() ? velocities[index] : PxVec3(0.0f);
+ if(mUseInstancedMeshes)
+ {
+ modifyRotationMatrix(mParticlesOrientations[index], deltaTime, velocities[index]);
+ }
+ if(mUseLifetime)
+ {
+ mParticleLifes[index] -= deltaTime;
+ }
+ mNumParticles++;
+ newValidRange = index;
+ }
+ else
+ {
+ mParticleValidity[w] &= (b-1);
+ }
+ }
+ }
+ }
+
+ mValidParticleRange = newValidRange;
+
+ mParticleSystemData->unlock();
+
+#ifdef RENDERER_ENABLE_CUDA_INTEROP
+ if (mCtxMgr && (mParticleSystem->getParticleBaseFlags()&PxParticleBaseFlag::eGPU))
+ {
+ mCtxMgr->acquireContext();
+
+ if (mValidParticleRange)
+ cuMemcpyHtoDAsync(mParticleValidityDevice, &mParticleValidity[0], sizeof(PxU32)*(mParticleSystem->getMaxParticles() + 31) >> 5, 0);
+
+ if (mUseLifetime && mParticleLifes.size())
+ cuMemcpyHtoDAsync(mParticleLifetimeDevice, &mParticleLifes[0], sizeof(PxReal)*mValidParticleRange, 0);
+
+ if (mUseInstancedMeshes)
+ cuMemcpyHtoDAsync(mParticlesOrientationsDevice, &mParticlesOrientations[0], sizeof(PxMat33)*mValidParticleRange, 0);
+
+ mCtxMgr->releaseContext();
+ }
+#endif
+
+ if(mNumParticles > 0 && mTmpIndexArray.size() != 0)
+ {
+ PxStrideIterator<const PxU32> indexData(&mTmpIndexArray[0]);
+ mParticleSystem->releaseParticles(static_cast<PxU32>(mTmpIndexArray.size()), indexData);
+ mIndexPool->freeIndices(static_cast<PxU32>(mTmpIndexArray.size()), indexData);
+ }
+}
+
+/* creates particles in the PhysX SDK */
+void ParticleSystem::createParticles(ParticleData& particles)
+{
+ particles.numParticles = PxMin(particles.numParticles, mParticleSystem->getMaxParticles() - mNumParticles);
+
+ if (particles.numParticles > 0)
+ {
+ std::vector<PxU32> mTmpIndexArray;
+ mTmpIndexArray.resize(particles.numParticles);
+ PxStrideIterator<PxU32> indexData(&mTmpIndexArray[0]);
+ // allocateIndices() may clamp the number of inserted particles
+ particles.numParticles = mIndexPool->allocateIndices(particles.numParticles, indexData);
+
+ PxParticleCreationData particleCreationData;
+ particleCreationData.numParticles = particles.numParticles;
+ particleCreationData.indexBuffer = PxStrideIterator<const PxU32>(&mTmpIndexArray[0]);
+ particleCreationData.positionBuffer = PxStrideIterator<const PxVec3>(&particles.positions[0]);
+ particleCreationData.velocityBuffer = PxStrideIterator<const PxVec3>(&particles.velocities[0]);
+ mNumParticles += particles.numParticles;
+ bool ok = mParticleSystem->createParticles(particleCreationData);
+ PX_UNUSED(ok);
+ PX_ASSERT(ok);
+ }
+}
+
+/* Returns pointer to the internal PxParticleBase */
+PxParticleBase* ParticleSystem::getPxParticleBase()
+{
+ return mParticleSystem;
+}
+
+/* Returns pointer to the particles positions */
+const std::vector<PxVec3>& ParticleSystem::getPositions()
+{
+ return mParticlesPositions;
+}
+
+/* Returns pointer to the particles velocities */
+const std::vector<PxVec3>& ParticleSystem::getVelocities()
+{
+ return mParticlesVelocities;
+}
+
+/* Returns pointer to the particles orientations */
+const std::vector<PxMat33>& ParticleSystem::getOrientations()
+{
+ return mParticlesOrientations;
+}
+
+/* Returns pointer to the particles validity */
+const PxU32* ParticleSystem::getValidity()
+{
+ return mParticleValidity;
+}
+
+/* Returns range of vaild particles index */
+PxU32 ParticleSystem::getValidParticleRange()
+{
+ return mValidParticleRange;
+}
+
+/* Returns pointer to the particles lifetimes */
+const std::vector<PxReal>& ParticleSystem::getLifetimes()
+{
+ return mParticleLifes;
+}
+
+/* Returns number of particles */
+PxU32 ParticleSystem::getNumParticles()
+{
+ PxParticleReadData* particleReadData = mParticleSystem->lockParticleReadData();
+ PX_ASSERT(particleReadData);
+ PxU32 numParticles = particleReadData->nbValidParticles;
+ particleReadData->unlock();
+ return numParticles;
+}
+
+PxU32 ParticleSystem::createParticles(const PxParticleCreationData& particles, PxStrideIterator<PxU32>* particleIndices, PxReal lifetime)
+{
+ PX_ASSERT(lifetime >= 0.0f);
+ //its not supported currently to pass in particle indices, as they are created here.
+ PX_ASSERT(particles.indexBuffer.ptr() == NULL);
+
+ PxParticleCreationData particlesCopy(particles);
+ SampleArray<PxU32> mTmpIndexArray;
+ mTmpIndexArray.resize(particles.numParticles);
+
+ PxU32 numAllocatedIndices = mIndexPool->allocateIndices(particles.numParticles, PxStrideIterator<PxU32>(mTmpIndexArray.begin()));
+ particlesCopy.indexBuffer = PxStrideIterator<PxU32>(mTmpIndexArray.begin());
+ particlesCopy.numParticles = numAllocatedIndices;
+
+ bool isSuccess = mParticleSystem->createParticles(particlesCopy);
+ PX_UNUSED(isSuccess);
+ PX_ASSERT(isSuccess);
+
+ if (mUseLifetime)
+ {
+ for (PxU32 i = 0; i < numAllocatedIndices; i++)
+ {
+ PxU32 index = mTmpIndexArray[i];
+ PX_ASSERT(index < mParticleSystem->getMaxParticles());
+ mParticleLifes[index] = lifetime;
+ }
+ }
+
+ if (particleIndices)
+ {
+ for (PxU32 i = 0; i < numAllocatedIndices; i++)
+ (*particleIndices)[i] = mTmpIndexArray[i];
+ }
+
+ return numAllocatedIndices;
+}
+
+PxU32 ParticleSystem::createParticles(const ParticleData& particles, PxReal lifetime)
+{
+ PxParticleCreationData particleCreationData;
+ particleCreationData.numParticles = particles.numParticles;
+ particleCreationData.positionBuffer = PxStrideIterator<const PxVec3>(particles.positions.begin());
+ particleCreationData.velocityBuffer = PxStrideIterator<const PxVec3>(particles.velocities.begin());
+
+ if (particles.restOffsets.size() > 0)
+ particleCreationData.restOffsetBuffer = PxStrideIterator<const PxF32>(particles.restOffsets.begin());
+
+ return createParticles(particleCreationData, NULL, lifetime);
+}
+
+PxU32 ParticleSystem::createParticleSphere(PxU32 maxParticles, float particleDistance, const PxVec3& center, const PxVec3& vel, PxReal lifetime, PxReal restOffsetVariance)
+{
+ float sideNumFloat = physx::shdfnd::pow(3.0f*maxParticles/(4.0f*PxPi), 1.0f/3.0f);
+ PxU32 sideNum = static_cast<PxU32>(physx::shdfnd::ceil(sideNumFloat));
+
+ ParticleData initData(PxMin(mParticleSystem->getMaxParticles() - getNumParticles(), sideNum*sideNum*sideNum));
+ CreateParticleSphere(initData, center, vel, particleDistance, sideNum);
+ if (restOffsetVariance > 0.0f)
+ SetParticleRestOffsetVariance(initData, mParticleSystem->getRestOffset(), restOffsetVariance);
+
+ return createParticles(initData, lifetime);
+}
+
+PxU32 ParticleSystem::createParticleCube(PxU32 numX, PxU32 numY, PxU32 numZ, float particleDistance, const PxVec3& center, const PxVec3& vel, PxReal lifetime, PxReal restOffsetVariance)
+{
+// PxU32 numParticles = numX * numY * numZ;
+
+ PxBounds3 aabb;
+ aabb.minimum = center - particleDistance * 0.5f * (PxVec3((PxReal)numX, (PxReal)numY, (PxReal)numZ) + PxVec3(0.5f));
+ aabb.maximum = center + particleDistance * 0.5f * (PxVec3((PxReal)numX, (PxReal)numY, (PxReal)numZ) + PxVec3(0.5f));
+ return createParticleCube(aabb, particleDistance, vel, lifetime, restOffsetVariance);
+}
+
+PxU32 ParticleSystem::createParticleCube(const PxBounds3& aabb, float particleDistance, const PxVec3& vel, PxReal lifetime, PxReal restOffsetVariance)
+{
+ PxVec3 aabbDim = aabb.getExtents();
+ aabbDim *= 2.0f;
+ unsigned sideNumX = (unsigned)PxMax(1.0f, physx::shdfnd::floor(aabbDim.x / particleDistance));
+ unsigned sideNumY = (unsigned)PxMax(1.0f, physx::shdfnd::floor(aabbDim.y / particleDistance));
+ unsigned sideNumZ = (unsigned)PxMax(1.0f, physx::shdfnd::floor(aabbDim.z / particleDistance));
+
+ PxU32 numParticles = PxMin(sideNumX * sideNumY * sideNumZ, mParticleSystem->getMaxParticles() - getNumParticles());
+ ParticleData initData(numParticles);
+ CreateParticleAABB(initData, aabb, vel, particleDistance);
+ if (restOffsetVariance > 0.0f)
+ SetParticleRestOffsetVariance(initData, mParticleSystem->getRestOffset(), restOffsetVariance);
+
+ return createParticles(initData, lifetime);
+}
+
+PxU32 ParticleSystem::createParticleRand(PxU32 numParticles,const PxVec3& particleRange, const PxVec3& center, const PxVec3& vel, PxReal lifetime, PxReal restOffsetVariance)
+{
+ ParticleData initData(numParticles);
+ CreateParticleRand(initData, center, particleRange, vel);
+ if (restOffsetVariance > 0.0f)
+ SetParticleRestOffsetVariance(initData, mParticleSystem->getRestOffset(), restOffsetVariance);
+
+ return createParticles(initData, lifetime);
+}
+
+PxU32 ParticleSystem::createParticlesFromFile(const char* particleFileName)
+{
+ PxU32 count = 0;
+ SampleFramework::File* file = NULL;
+ PxToolkit::fopen_s(&file, particleFileName, "rb");
+ if (!file)
+ return 0;
+
+ bool readSuccess = fread(&count, 1, sizeof(PxU32), file) == sizeof(PxU32);
+ if (!readSuccess)
+ return 0;
+
+ SampleArray<PxVec3> positions;
+ SampleArray<PxVec3> velocities;
+ positions.resize(count);
+ velocities.resize(count);
+
+ for (PxU32 i = 0; i < count; ++i)
+ {
+ readSuccess &= fread(&positions[i], 1, sizeof(PxVec3), file) == sizeof(PxVec3);
+ readSuccess &= fread(&velocities[i], 1, sizeof(PxVec3), file) == sizeof(PxVec3);
+ }
+
+ PxU32 numNewParticles = 0;
+ if (readSuccess)
+ {
+ PxParticleCreationData particleData;
+ particleData.numParticles = count;
+ particleData.positionBuffer = PxStrideIterator<PxVec3>(positions.begin());
+ particleData.velocityBuffer = PxStrideIterator<PxVec3>(velocities.begin());
+ numNewParticles = createParticles(particleData);
+ }
+ fclose(file);
+ return numNewParticles;
+
+}
+
+bool ParticleSystem::dumpParticlesToFile(const char* particleFileName)
+{
+ SampleFramework::File* file = NULL;
+ PxToolkit::fopen_s(&file, particleFileName, "wb");
+ if (!file)
+ return false;
+
+ PxParticleReadData* prd = mParticleSystem->lockParticleReadData();
+ if (!prd->positionBuffer.ptr())
+ return false;
+
+ PxStrideIterator<const PxVec3> positions(prd->positionBuffer);
+
+ //zero velocities if no velocity buffer available
+ PxVec3 zero(0.0f);
+ PxStrideIterator<const PxVec3> velocities = (prd->velocityBuffer.ptr()) ? prd->velocityBuffer : PxStrideIterator<const PxVec3>(&zero, 0);
+
+ //write particle count;
+ bool writeSuccess = fwrite(&prd->nbValidParticles, 1, sizeof(PxU32), file) == sizeof(PxU32);
+
+ //write particles
+ if (prd->validParticleRange > 0)
+ {
+ for (PxU32 w = 0; w <= (prd->validParticleRange-1) >> 5; w++)
+ for (PxU32 b = prd->validParticleBitmap[w]; b; b &= b-1)
+ {
+ PxU32 index = (w<<5|physx::shdfnd::lowestSetBit(b));
+ writeSuccess &= fwrite(&positions[index], 1, sizeof(PxVec3), file) == sizeof(PxVec3);
+ writeSuccess &= fwrite(&velocities[index], 1, sizeof(PxVec3), file) == sizeof(PxVec3);
+ }
+ }
+
+ prd->unlock();
+ fclose(file);
+ return writeSuccess;
+}
+
+void ParticleSystem::releaseParticles(const SampleArray<PxU32>& indices)
+{
+ if (indices.size() == 0)
+ return;
+
+ PxStrideIterator<const PxU32> indexData(indices.begin());
+ mParticleSystem->releaseParticles(indices.size(), indexData);
+ mIndexPool->freeIndices(indices.size(), indexData);
+}
+
+void ParticleSystem::releaseParticles()
+{
+ mParticleSystem->releaseParticles();
+ mIndexPool->freeIndices();
+}
+
+#endif // PX_USE_PARTICLE_SYSTEM_API
diff --git a/PhysX_3.4/Samples/SampleBase/ParticleSystem.h b/PhysX_3.4/Samples/SampleBase/ParticleSystem.h
new file mode 100644
index 00000000..b4aa859a
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/ParticleSystem.h
@@ -0,0 +1,163 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef PARTICLE_SYSTEM_H
+#define PARTICLE_SYSTEM_H
+
+#include "PxPhysicsAPI.h"
+
+#if PX_USE_PARTICLE_SYSTEM_API
+
+#include "task/PxTask.h"
+#include "pvd/PxPvd.h"
+#include "extensions/PxParticleExt.h"
+#include "PhysXSampleApplication.h"
+
+// fwd to avoid including cuda.h
+#if defined(__x86_64) || defined(AMD64) || defined(_M_AMD64)
+typedef unsigned long long CUdeviceptr;
+#else
+typedef unsigned int CUdeviceptr;
+#endif
+
+/*
+ This is class for particle systems/fluids with constant rate emitter.
+The class constructed using PxParticleBase object, the ownership of
+which is transferred to ParticleSystem object. Other parameters are mandatory:
+application pointer, billboard_size and texture object. Each particle rendered
+as a quad, which normals always points to viewer. Texture for this quad must be supplied.
+Depending on actual type of object created (PxParticleBase/PxParticleFluid) either particle system
+could be created, or fluid.
+ This class has copy semantics, so it is possible to store objects of this
+type in container and periodically call it's member functions - update/draw.
+ Particles' lifetime could be limited by lifetime. See setUseLifetime and
+setLifetime functions.
+ In order to get particles created one must set emitter. Emitter is 2D shape (ellipse/rectangle)
+located in some place in world coordinates, which emits particles with some rate.
+This shape also has size. Also, in order to get particles created one must call periodically update()
+function.
+ Worth mentioning, that particles count is limited by two or three factors - maximum number of particles,
+which is set, during PxParticleBase/PxParticleFluid object construction AND emitter rate
+AND IF SET particles lifetime.
+*/
+class ParticleSystem : public SampleAllocateable
+{
+private:
+ PxParticleBase* mParticleSystem;
+ PxParticleExt::IndexPool* mIndexPool;
+ std::vector<PxVec3> mParticlesPositions;
+ std::vector<PxVec3> mParticlesVelocities;
+ std::vector<PxMat33> mParticlesOrientations;
+ PxU32 mNumParticles;
+ PxReal mParticleLifetime;
+ std::vector<PxReal> mParticleLifes;
+ PxU32* mParticleValidity;
+ PxU32 mValidParticleRange;
+ bool mUseLifetime;
+ bool mUseInstancedMeshes;
+
+ CUdeviceptr mParticlesOrientationsDevice;
+ CUdeviceptr mParticleLifetimeDevice;
+ CUdeviceptr mParticleValidityDevice;
+ PxCudaContextManager* mCtxMgr;
+
+ void modifyRotationMatrix(PxMat33& rotMatrix, PxReal deltaTime, const PxVec3& velocity);
+ void initializeParticlesOrientations();
+
+public:
+ class Visitor
+ {
+ public:
+ virtual ~Visitor() {}
+ virtual void visit(ParticleSystem& particleSystem) = 0;
+ };
+ void accept(Visitor& visitor) { visitor.visit(*this); }
+
+ ParticleSystem(PxParticleBase* _particle_system, bool _useInstancedMeshes = false);
+ ~ParticleSystem();
+ /* enables limiting particles lifetime */
+ void setUseLifetime(bool use);
+ /* returns true if limiting particles lifetime is enabled */
+ bool useLifetime();
+ /* NOTE! setUseLifetime(true) before setting this. Sets lifetime of particle to "lt" on emit */
+ void setLifetime(PxReal lt);
+ /* fetches particles positions from the PhysX SDK,
+ removes invalid particles
+ (intersected with drain, non-positive lifetime),
+ creates new particles */
+ void update(float deltaTime);
+ /* creates particles in the PhysX SDK */
+ void createParticles(struct ParticleData& particles);
+
+ /* Returns pointer to the internal PxParticleBase */
+ PxParticleBase* getPxParticleBase();
+ /* Returns pointer to the particles positions */
+ const std::vector<PxVec3>& getPositions();
+ /* Returns pointer to the particles lifetimes */
+ const std::vector<PxReal>& getLifetimes();
+ /* Returns pointer to the particles velocities */
+ const std::vector<PxVec3>& getVelocities();
+ /* Returns pointer to the particles orientations */
+ const std::vector<PxMat33>& getOrientations();
+ /* Returns pointer to the particles validity */
+ const PxU32* getValidity();
+ /* Returns range of vaild particles index */
+ PxU32 getValidParticleRange();
+ /* Returns number of particles */
+ PxU32 getNumParticles();
+
+ /* Return the device copy of particles validity */
+ CUdeviceptr getValiditiesDevice() const { return mParticleValidityDevice; }
+ /* Return the device copy of particles orientation */
+ CUdeviceptr getOrientationsDevice() const { return mParticlesOrientationsDevice; }
+ /* Return the device copy of particle lifetimes*/
+ CUdeviceptr getLifetimesDevice() const { return mParticleLifetimeDevice; }
+ /* Return cuda context manager if set, which is only the case if interop is enabled*/
+ PxCudaContextManager* getCudaContextManager() const { return mCtxMgr; }
+
+public:
+ PxParticleSystem& getPxParticleSystem() { PX_ASSERT(mParticleSystem); return static_cast<PxParticleSystem&>(*mParticleSystem); }
+ PxParticleFluid& getPxParticleFluid() { PX_ASSERT(mParticleSystem); return static_cast<PxParticleFluid&>(*mParticleSystem); }
+
+ PxU32 createParticles(const PxParticleCreationData& particles, PxStrideIterator<PxU32>* particleIndices = NULL, PxReal lifetime = 0.0f);
+ PxU32 createParticleSphere(PxU32 maxParticles, float particleDistance, const PxVec3& center, const PxVec3& vel, PxReal lifetime = 0.0f, PxReal restOffsetVariance = 0.0f);
+ PxU32 createParticleCube(PxU32 numX, PxU32 numY, PxU32 numZ, float particleDistance, const PxVec3& center, const PxVec3& vel, PxReal lifetime = 0.0f, PxReal restOffsetVariance = 0.0f);
+ PxU32 createParticleCube(const PxBounds3& aabb, float particleDistance, const PxVec3& vel, PxReal lifetime = 0.0f, PxReal restOffsetVariance = 0.0f);
+ PxU32 createParticleRand(PxU32 numParticles,const PxVec3& particleRange, const PxVec3& center, const PxVec3& vel, PxReal lifetime = 0.0f, PxReal restOffsetVariance = 0.0f);
+ PxU32 createParticlesFromFile(const char* particleFileName);
+ bool dumpParticlesToFile(const char* particleFileName);
+ void releaseParticles(const SampleArray<PxU32>& indices);
+ void releaseParticles();
+
+private:
+ PxU32 createParticles(const ParticleData& particles, PxReal lifetime);
+};
+
+#endif // PX_USE_PARTICLE_SYSTEM_API
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/PhysXSample.cpp b/PhysX_3.4/Samples/SampleBase/PhysXSample.cpp
new file mode 100644
index 00000000..f72e789b
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/PhysXSample.cpp
@@ -0,0 +1,2901 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+
+#include "foundation/PxFoundationVersion.h"
+
+#include "PxPhysXConfig.h"
+#include "foundation/PxMemory.h"
+#include "SamplePreprocessor.h"
+#include "PhysXSampleApplication.h"
+#include "PhysXSample.h"
+#include "SampleCommandLine.h"
+
+#include "PxTkFile.h"
+#include "PsString.h"
+#include "PsFPU.h"
+
+#include "PxToolkit.h"
+#include "extensions/PxDefaultStreams.h"
+
+#include "RenderBoxActor.h"
+#include "RenderSphereActor.h"
+#include "RenderCapsuleActor.h"
+#include "RenderMeshActor.h"
+#include "RenderGridActor.h"
+#include "RenderMaterial.h"
+#include "RenderTexture.h"
+#include "RenderPhysX3Debug.h"
+#include "RenderClothActor.h"
+#include "RendererClothShape.h"
+#include "ParticleSystem.h"
+
+#include <SamplePlatform.h>
+#include "SampleBaseInputEventIds.h"
+#include <SampleUserInputIds.h>
+#include "SampleUserInputDefines.h"
+#include <SampleInputAsset.h>
+#include "SampleInputMappingAsset.h"
+
+#include <algorithm>
+#include <ctype.h>
+
+#include "cloth/PxClothParticleData.h"
+#include "TestClothHelpers.h"
+#include "extensions/PxClothFabricCooker.h"
+
+#include "Picking.h"
+#include "TestGroup.h"
+
+#if PX_WINDOWS
+// Starting with Release 302 drivers, application developers can direct the Optimus driver at runtime to use the High Performance
+// Graphics to render any application; even those applications for which there is no existing application profile.
+// They can do this by exporting a global variable named PxOptimusEnablement.
+// A value of 0x00000001 indicates that rendering should be performed using High Performance Graphics.
+// A value of 0x00000000 indicates that this method should be ignored.
+extern "C"
+{
+ _declspec(dllexport) DWORD PxOptimusEnablement = 0x00000001;
+}
+#endif
+
+using namespace SampleFramework;
+using namespace SampleRenderer;
+
+static bool gRecook = false;
+PxDefaultAllocator gDefaultAllocatorCallback;
+
+enum MaterialID
+{
+ MATERIAL_CLOTH = 444,
+#ifdef RENDERER_TABLET
+ MATERIAL_CONTROLS,
+ MATERIAL_BUTTONS,
+#endif
+};
+#ifdef RENDERER_TABLET
+#include "SampleMaterialAsset.h"
+static const char* controlMaterialPath = "materials/tablet_sticks.xml";
+static const char* buttonMaterialPath = "materials/tablet_buttons.xml";
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
+PX_FORCE_INLINE PxSimulationFilterShader getSampleFilterShader()
+{
+ return PxDefaultSimulationFilterShader;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+PX_FORCE_INLINE void SetupDefaultRigidDynamic(PxRigidDynamic& body, bool kinematic=false)
+{
+ body.setActorFlag(PxActorFlag::eVISUALIZATION, true);
+ body.setAngularDamping(0.5f);
+ body.setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, kinematic);
+}
+
+void PhysXSample::unlink(RenderBaseActor* renderActor, PxShape* shape, PxRigidActor* actor)
+{
+ PhysXShape theShape(actor, shape);
+ mPhysXShapeToRenderActorMap.erase(theShape);
+
+ PX_UNUSED(renderActor);
+}
+
+void PhysXSample::link(RenderBaseActor* renderActor, PxShape* shape, PxRigidActor* actor)
+{
+ PhysXShape theShape(actor, shape);
+ mPhysXShapeToRenderActorMap[theShape] = renderActor;
+
+ renderActor->setPhysicsShape(shape, actor);
+}
+
+RenderBaseActor* PhysXSample::getRenderActor(PxRigidActor* actor, PxShape* shape)
+{
+ PhysXShape theShape(actor, shape);
+ PhysXShapeToRenderActorMap::iterator it = mPhysXShapeToRenderActorMap.find(theShape);
+ if (mPhysXShapeToRenderActorMap.end() != it)
+ return it->second;
+ return NULL;
+}
+
+SampleDirManager& PhysXSample::getSampleOutputDirManager()
+{
+ static SampleDirManager gSampleOutputDirManager(SAMPLE_OUTPUT_DIR, false);
+ return gSampleOutputDirManager;
+}
+
+PxToolkit::BasicRandom& getSampleRandom()
+{
+ static PxToolkit::BasicRandom gRandom(42);
+ return gRandom;
+}
+
+PxErrorCallback& getSampleErrorCallback()
+{
+ static PxDefaultErrorCallback gDefaultErrorCallback;
+ return gDefaultErrorCallback;
+}
+
+// sschirm: same here: would be good to have a place for platform independent path manipulation
+// shared for all apps
+const char* getFilenameFromPath(const char* filePath, char* buffer)
+{
+ const char* ptr = strrchr(filePath, '/');
+ if (!ptr)
+ ptr = strrchr(filePath, '\\');
+
+ if (ptr)
+ {
+ strcpy(buffer, ptr + 1);
+ }
+ else
+ {
+ strcpy(buffer, filePath);
+ }
+ return buffer;
+}
+
+const char* PhysXSample::getSampleOutputFilePath(const char* inFilePath, const char* outExtension)
+{
+ static char sBuffer[1024];
+ char tmpBuffer[1024];
+
+ const char* inFilename = getFilenameFromPath(inFilePath, sBuffer);
+ sprintf(tmpBuffer, "cached/%s%s", inFilename, outExtension);
+ return getSampleOutputDirManager().getFilePath(tmpBuffer, sBuffer, false);
+}
+
+static void GenerateCirclePts(unsigned int nb, PxVec3* pts, float scale, float z)
+{
+ for(unsigned int i=0;i<nb;i++)
+ {
+ const PxF32 angle = 6.28f*PxF32(i)/PxF32(nb);
+ pts[i].x = cosf(angle)*scale;
+ pts[i].y = z;
+ pts[i].z = sinf(angle)*scale;
+ }
+}
+
+static PxConvexMesh* GenerateConvex(PxPhysics& sdk, PxCooking& cooking, PxU32 nbVerts, const PxVec3* verts, bool recenterVerts=false)
+{
+ PxVec3Alloc* tmp = NULL;
+ if(recenterVerts)
+ {
+ PxVec3 center(0);
+ for(PxU32 i=0;i<nbVerts;i++)
+ center += verts[i];
+ center /= PxReal(nbVerts);
+
+ tmp = SAMPLE_NEW(PxVec3Alloc)[nbVerts];
+ PxVec3* recentered = tmp;
+ for(PxU32 i=0;i<nbVerts;i++)
+ recentered[i] = verts[i] - center;
+ }
+
+ PxConvexMesh* convexMesh = PxToolkit::createConvexMesh(sdk, cooking, recenterVerts ? tmp : verts, nbVerts, PxConvexFlag::eCOMPUTE_CONVEX);
+
+ DELETEARRAY(tmp);
+
+ return convexMesh;
+}
+
+static PxConvexMesh* GenerateConvex(PxPhysics& sdk, PxCooking& cooking, float scale, bool large=false, bool randomize=true)
+{
+ const PxI32 minNb = large ? 16 : 3;
+ const PxI32 maxNb = large ? 32 : 8;
+ const int nbInsideCirclePts = !randomize ? 3 : getSampleRandom().rand(minNb, maxNb);
+ const int nbOutsideCirclePts = !randomize ? 8 : getSampleRandom().rand(minNb, maxNb);
+ const int nbVerts = nbInsideCirclePts + nbOutsideCirclePts;
+
+ // Generate random vertices
+ PxVec3Alloc* verts = SAMPLE_NEW(PxVec3Alloc)[nbVerts];
+
+ // Two methods
+ if(randomize && getSampleRandom().rand(0, 100) > 50)
+ {
+ for(int i=0;i<nbVerts;i++)
+ {
+ verts[i].x = scale * getSampleRandom().rand(-2.5f, 2.5f);
+ verts[i].y = scale * getSampleRandom().rand(-2.5f, 2.5f);
+ verts[i].z = scale * getSampleRandom().rand(-2.5f, 2.5f);
+ }
+ }
+ else
+ {
+ GenerateCirclePts(nbInsideCirclePts, verts, scale, 0.0f);
+ GenerateCirclePts(nbOutsideCirclePts, verts+nbInsideCirclePts, scale*3.0f, 10.0f*scale);
+ }
+
+ PxConvexMesh* convexMesh = GenerateConvex(sdk, cooking, nbVerts, verts);
+
+ DELETEARRAY(verts);
+ return convexMesh;
+}
+
+#if 0
+
+static PxConvexMesh* GenerateConvex(PxPhysics& sdk, PxCooking& cooking, int nbInsideCirclePts, int nbOutsideCirclePts, float scale0, float scale1, float z)
+{
+ const int nbVerts = nbInsideCirclePts + nbOutsideCirclePts;
+
+ // Generate random vertices
+ PxVec3Alloc* verts = SAMPLE_NEW(PxVec3Alloc)[nbVerts];
+
+ GenerateCirclePts(nbInsideCirclePts, verts, scale0, 0.0f);
+ GenerateCirclePts(nbOutsideCirclePts, verts+nbInsideCirclePts, scale1, z);
+
+ PxConvexMesh* convexMesh = GenerateConvex(sdk, cooking, nbVerts, verts);
+
+ DELETEARRAY(verts);
+ return convexMesh;
+}
+
+#endif
+
+static PxRigidDynamic* GenerateCompound(PxPhysics& sdk, PxScene* scene, PxMaterial* defaultMat, const PxVec3& pos, const PxQuat& rot, const std::vector<PxTransform>& poses, const std::vector<const PxGeometry*>& geometries, bool kinematic=false, PxReal density = 1.0f)
+{
+ PxRigidDynamic* actor = sdk.createRigidDynamic(PxTransform(pos, rot));
+ SetupDefaultRigidDynamic(*actor);
+
+ PX_ASSERT(poses.size() == geometries.size());
+ for(PxU32 i=0;i<poses.size();i++)
+ {
+ const PxTransform& currentPose = poses[i];
+ const PxGeometry* currentGeom = geometries[i];
+
+ PxShape* shape = PxRigidActorExt::createExclusiveShape(*actor, *currentGeom, *defaultMat);
+ shape->setLocalPose(currentPose);
+ PX_ASSERT(shape);
+ }
+
+ if(actor)
+ {
+ PxRigidBodyExt::updateMassAndInertia(*actor, density);
+ scene->addActor(*actor);
+ }
+ return actor;
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+void PhysXSample::onRelease(const PxBase* observed, void* userData, PxDeletionEventFlag::Enum deletionEvent)
+{
+ PX_UNUSED(userData);
+ PX_UNUSED(deletionEvent);
+
+ if(observed->is<PxRigidActor>())
+ {
+ const PxRigidActor* actor = static_cast<const PxRigidActor*>(observed);
+
+ removeRenderActorsFromPhysicsActor(actor);
+
+ std::vector<PxRigidActor*>::iterator actorIter = std::find(mPhysicsActors.begin(), mPhysicsActors.end(), actor);
+ if(actorIter != mPhysicsActors.end())
+ {
+ mPhysicsActors.erase(actorIter);
+ }
+
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+RenderMeshActor* PhysXSample::createRenderMeshFromRawMesh(const RAWMesh& data, PxShape* shape)
+{
+ // Create render mesh from raw mesh
+ const PxU32 nbTris = data.mNbFaces;
+ const PxU32* src = data.mIndices;
+
+ PxU16* indices = (PxU16*)SAMPLE_ALLOC(sizeof(PxU16)*nbTris*3);
+ for(PxU32 i=0;i<nbTris;i++)
+ {
+ indices[i*3+0] = src[i*3+0];
+ indices[i*3+1] = src[i*3+2];
+ indices[i*3+2] = src[i*3+1];
+ }
+
+ RenderMeshActor* meshActor = SAMPLE_NEW(RenderMeshActor)(*getRenderer(), data.mVerts, data.mNbVerts, data.mVertexNormals, data.mUVs, indices, NULL, nbTris);
+ SAMPLE_FREE(indices);
+
+ if(data.mMaterialID!=0xffffffff)
+ {
+ size_t nbMaterials = mRenderMaterials.size();
+ for(PxU32 i=0;i<nbMaterials;i++)
+ {
+ if(mRenderMaterials[i]->mID==data.mMaterialID)
+ {
+ meshActor->setRenderMaterial(mRenderMaterials[i]);
+ break;
+ }
+ }
+ }
+
+ meshActor->setTransform(data.mTransform);
+ if(data.mName)
+ strcpy(meshActor->mName, data.mName);
+
+ mRenderActors.push_back(meshActor);
+ return meshActor;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+RenderTexture* PhysXSample::createRenderTextureFromRawTexture(const RAWTexture& data)
+{
+ RenderTexture* texture;
+
+ if(!data.mPixels)
+ {
+ // PT: the pixel data is not included in the RAW file so we use the asset manager to load the texture
+ SampleAsset* t = getAsset(getSampleMediaFilename(data.mName), SampleAsset::ASSET_TEXTURE);
+ PX_ASSERT(t->getType()==SampleAsset::ASSET_TEXTURE);
+ mManagedAssets.push_back(t);
+
+ SampleTextureAsset* textureAsset = static_cast<SampleTextureAsset*>(t);
+ texture = SAMPLE_NEW(RenderTexture)(*getRenderer(), data.mID, textureAsset->getTexture());
+
+ }
+ else
+ {
+ // PT: the pixel data is directly included in the RAW file
+ texture = SAMPLE_NEW(RenderTexture)(*getRenderer(), data.mID, data.mWidth, data.mHeight, data.mPixels);
+ }
+ if(data.mName)
+ strcpy(texture->mName, data.mName);
+ mRenderTextures.push_back(texture);
+ return texture;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void PhysXSample::newMaterial(const RAWMaterial& data)
+{
+ RenderTexture* diffuse = NULL;
+ if(data.mDiffuseID!=0xffffffff)
+ {
+ size_t nbTextures = mRenderTextures.size();
+ for(PxU32 i=0;i<nbTextures;i++)
+ {
+ if(mRenderTextures[i]->mID==data.mDiffuseID)
+ {
+ diffuse = mRenderTextures[i];
+ break;
+ }
+ }
+ }
+
+ RenderMaterial* newRM = SAMPLE_NEW(RenderMaterial)(*getRenderer(), data.mDiffuseColor, data.mOpacity, data.mDoubleSided, data.mID, diffuse);
+// strcpy(newRM->mName, data.mName);
+ mRenderMaterials.push_back(newRM);
+}
+
+void PhysXSample::newMesh(const RAWMesh& data)
+{
+ // PT: the mesh name should capture the scale value as well, to make sure different scales give birth to different cooked files
+ const PxU32 scaleTag = PX_IR(mScale);
+
+ PX_ASSERT(mFilename);
+ char extension[256];
+ sprintf(extension, "_%d_%x.cooked", mMeshTag, scaleTag);
+
+ const char* filePathCooked = getSampleOutputFilePath(mFilename, extension);
+ PX_ASSERT(NULL != filePathCooked);
+
+ bool ok = false;
+ if(!gRecook)
+ {
+ SampleFramework::File* fp = NULL;
+ PxToolkit::fopen_s(&fp, filePathCooked, "rb");
+ if(fp)
+ {
+ fclose(fp);
+ ok = true;
+ }
+ }
+
+ if(!ok)
+ {
+ PxTriangleMeshDesc meshDesc;
+ meshDesc.points.count = data.mNbVerts;
+ meshDesc.triangles.count = data.mNbFaces;
+ meshDesc.points.stride = 4*3;
+ meshDesc.triangles.stride = 4*3;
+ meshDesc.points.data = data.mVerts;
+ meshDesc.triangles.data = data.mIndices;
+
+ //
+ shdfnd::printFormatted("Cooking object... %s",filePathCooked);
+ PxDefaultFileOutputStream stream(filePathCooked);
+ ok = mCooking->cookTriangleMesh(meshDesc, stream);
+ shdfnd::printFormatted(" - Done\n");
+ }
+
+ if(ok)
+ {
+ PxDefaultFileInputData stream(filePathCooked);
+ PxTriangleMesh* triangleMesh = mPhysics->createTriangleMesh(stream);
+ if(triangleMesh)
+ {
+ PxTriangleMeshGeometry triGeom;
+ triGeom.triangleMesh = triangleMesh;
+ PxRigidStatic* actor = mPhysics->createRigidStatic(data.mTransform);
+ PxShape* shape = PxRigidActorExt::createExclusiveShape(*actor, triGeom, *mMaterial);
+ PX_UNUSED(shape);
+ mScene->addActor(*actor);
+ addPhysicsActors(actor);
+
+ if(0)
+ {
+ // Create render mesh from PhysX mesh
+ PxU32 nbVerts = triangleMesh->getNbVertices();
+ const PxVec3* verts = triangleMesh->getVertices();
+ PxU32 nbTris = triangleMesh->getNbTriangles();
+ const void* tris = triangleMesh->getTriangles();
+ bool s = triangleMesh->getTriangleMeshFlags() & PxTriangleMeshFlag::e16_BIT_INDICES ? true : false;
+ PX_ASSERT(s);
+ PX_UNUSED(s);
+ const PxU16* src = (const PxU16*)tris;
+ PxU16* indices = (PxU16*)SAMPLE_ALLOC(sizeof(PxU16)*nbTris*3);
+ for(PxU32 i=0;i<nbTris;i++)
+ {
+ indices[i*3+0] = src[i*3+0];
+ indices[i*3+1] = src[i*3+2];
+ indices[i*3+2] = src[i*3+1];
+ }
+
+ RenderMeshActor* meshActor = SAMPLE_NEW(RenderMeshActor)(*getRenderer(), verts, nbVerts, verts, NULL, indices, NULL, nbTris);
+ if(data.mName)
+ strcpy(meshActor->mName, data.mName);
+ PxShape* shape;
+ actor->getShapes(&shape, 1);
+ link(meshActor, shape, actor);
+ mRenderActors.push_back(meshActor);
+ meshActor->setEnableCameraCull(true);
+ SAMPLE_FREE(indices);
+ }
+ else
+ {
+ PxShape* shape;
+ actor->getShapes(&shape, 1);
+ RenderMeshActor* meshActor = createRenderMeshFromRawMesh(data, shape);
+ link(meshActor, shape, actor);
+ meshActor->setEnableCameraCull(true);
+ }
+
+ mMeshTag++;
+ }
+ }
+}
+
+void PhysXSample::newShape(const RAWShape&)
+{
+}
+
+void PhysXSample::newHelper(const RAWHelper&)
+{
+}
+
+void PhysXSample::newTexture(const RAWTexture& data)
+{
+ createRenderTextureFromRawTexture(data);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void PhysXSample::togglePvdConnection()
+{
+ if(mPvd == NULL) return;
+ if (mPvd->isConnected())
+ mPvd->disconnect();
+ else
+ mPvd->connect(*mTransport,mPvdFlags);
+}
+
+void PhysXSample::createPvdConnection()
+{
+#if PX_SUPPORT_PVD
+ //Create a pvd connection that writes data straight to the filesystem. This is
+ //the fastest connection on windows for various reasons. First, the transport is quite fast as
+ //pvd writes data in blocks and filesystems work well with that abstraction.
+ //Second, you don't have the PVD application parsing data and using CPU and memory bandwidth
+ //while your application is running.
+ //physx::PxPvdTransport* transport = physx::PxDefaultPvdFileTransportCreate( "c:\\mywork\\sample.pxd2" );
+
+ //The normal way to connect to pvd. PVD needs to be running at the time this function is called.
+ //We don't worry about the return value because we are already registered as a listener for connections
+ //and thus our onPvdConnected call will take care of setting up our basic connection state.
+ mTransport = physx::PxDefaultPvdSocketTransportCreate(mPvdParams.ip, mPvdParams.port, mPvdParams.timeout);
+ if(mTransport == NULL)
+ return;
+
+ //The connection flags state overall what data is to be sent to PVD. Currently
+ //the Debug connection flag requires support from the implementation (don't send
+ //the data when debug isn't set) but the other two flags, profile and memory
+ //are taken care of by the PVD SDK.
+
+ //Use these flags for a clean profile trace with minimal overhead
+ mPvdFlags = physx::PxPvdInstrumentationFlag::eALL;
+ //if (!mPvdParams.useFullPvdConnection )
+ {
+ mPvdFlags = physx::PxPvdInstrumentationFlag::ePROFILE;
+ }
+
+ mPvd = physx::PxCreatePvd( *mFoundation );
+ mPvd->connect(*mTransport,mPvdFlags);
+#endif
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// default implemententions for PhysXSample interface
+//
+void PhysXSample::onPointerInputEvent(const InputEvent& ie, physx::PxU32 x, physx::PxU32 y, physx::PxReal dx, physx::PxReal dy, bool pressed)
+{
+ switch (ie.m_Id)
+ {
+ case CAMERA_MOUSE_LOOK:
+ {
+ if(mPicking)
+ mPicking->moveCursor(x,y);
+ }
+ break;
+ case PICKUP:
+ {
+ if(mPicking)
+ {
+ mPicked = !mPicked;;
+ if(mPicked)
+ mPicking->lazyPick();
+ else
+ mPicking->letGo();
+ }
+ }
+ break;
+ }
+
+}
+
+void PhysXSample::onResize(PxU32 width, PxU32 height)
+{
+ mApplication.baseResize(width, height);
+}
+
+PhysXSample::~PhysXSample()
+{
+ for (size_t i = mDeletedRenderActors.size(); i--;)
+ {
+ mDeletedRenderActors[i]->release();
+ }
+ mDeletedRenderActors.clear();
+ PX_ASSERT(!mRenderActors.size());
+ PX_ASSERT(!mRenderTextures.size());
+ PX_ASSERT(!mRenderMaterials.size());
+ PX_ASSERT(!mPhysicsActors.size());
+ PX_ASSERT(!mManagedAssets.size());
+ PX_ASSERT(!mBufferedActiveTransforms);
+ PX_ASSERT(!mScene);
+ PX_ASSERT(!mCpuDispatcher);
+// PX_ASSERT(!mMaterial);
+#if PX_SUPPORT_GPU_PHYSX
+ PX_ASSERT(!mCudaContextManager);
+#endif
+
+ PX_ASSERT(!mCooking);
+ PX_ASSERT(!mPhysics);
+ PX_ASSERT(!mFoundation);
+
+ if(SCRATCH_BLOCK_SIZE)
+ SAMPLE_FREE(mScratchBlock);
+
+ delete mPicking;
+}
+
+PhysXSample::PhysXSample(PhysXSampleApplication& app, PxU32 maxSubSteps) :
+ mInitialDebugRender(false),
+ mCreateCudaCtxManager(true),
+ mCreateGroundPlane(true),
+ mStepperType(FIXED_STEPPER),
+ mMaxNumSubSteps(maxSubSteps),
+ mNbThreads(1),
+ mDefaultDensity(20.0f),
+ mDisplayFPS(true),
+
+ mPause(app.mPause),
+ mOneFrameUpdate(app.mOneFrameUpdate),
+ mShowHelp(app.mShowHelp),
+ mShowDescription(app.mShowDescription),
+ mShowExtendedHelp(app.mShowExtendedHelp),
+ mHideGraphics(false),
+ mEnableAutoFlyCamera(false),
+ mCameraController(app.mCameraController),
+ mPvdParams(app.mPvdParams),
+ mApplication(app),
+ mFoundation(NULL),
+ mPhysics(NULL),
+ mCooking(NULL),
+ mScene(NULL),
+ mMaterial(NULL),
+ mCpuDispatcher(NULL),
+ mPvd(NULL),
+ mTransport(NULL),
+#if PX_SUPPORT_GPU_PHYSX
+ mCudaContextManager(NULL),
+#endif
+ mManagedMaterials(app.mManagedMaterials),
+ mSampleInputAsset(NULL),
+ mBufferedActiveTransforms(NULL),
+ mActiveTransformCount(0),
+ mActiveTransformCapacity(0),
+ mIsFlyCamera(false),
+ mMeshTag(0),
+ mFilename(NULL),
+ mScale(1.0f),
+ mDebugRenderScale(1.0f),
+ mWaitForResults(false),
+ mSavedCameraController(NULL),
+
+ mDebugStepper(0.016666660f),
+ mFixedStepper(0.016666660f, maxSubSteps),
+ mVariableStepper(1.0f / 80.0f, 1.0f / 40.0f, maxSubSteps),
+ mWireFrame(false),
+ mSimulationTime(0.0f),
+ mPicked(false),
+ mExtendedHelpPage(0),
+ mDebugObjectType(DEBUG_OBJECT_BOX)//,
+{
+ mDebugStepper.setSample(this);
+ mFixedStepper.setSample(this);
+ mVariableStepper.setSample(this);
+
+ mScratchBlock = SCRATCH_BLOCK_SIZE ? SAMPLE_ALLOC(SCRATCH_BLOCK_SIZE) : 0;
+
+ mFlyCameraController.init(PxVec3(0.0f, 10.0f, 0.0f), PxVec3(0.0f, 0.0f, 0.0f));
+
+ mPicking = new physx::Picking(*this);
+
+ mDeletedActors.clear();
+}
+
+void PhysXSample::render()
+{
+ PxU32 nbVisible = 0;
+
+ if(!mHideGraphics)
+ {
+ PX_PROFILE_ZONE("Renderer.CullObjects", 0);
+ Camera& camera = getCamera();
+ Renderer* renderer = getRenderer();
+
+ for(PxU32 i = 0; i < mRenderActors.size(); ++i)
+ {
+ RenderBaseActor* renderActor = mRenderActors[i];
+ if(camera.mPerformVFC &&
+ renderActor->getEnableCameraCull() &&
+ getCamera().cull(renderActor->getWorldBounds())==PLANEAABB_EXCLUSION)
+ continue;
+
+ renderActor->render(*renderer, mManagedMaterials[MATERIAL_GREY], mWireFrame);
+ ++nbVisible;
+ }
+
+ //if(camera.mPerformVFC)
+ //shdfnd::printFormatted("Nb visible: %d\n", nbVisible);
+ }
+
+ RenderPhysX3Debug* debugRender = getDebugRenderer();
+ if(debugRender)
+ debugRender->queueForRenderTriangle();
+}
+
+void PhysXSample::displayFPS()
+{
+ if(!mDisplayFPS)
+ return;
+
+ char fpsText[512];
+ sprintf(fpsText, "%0.2f fps", mFPS.getFPS());
+
+ Renderer* renderer = getRenderer();
+
+ const PxU32 yInc = 18;
+ renderer->print(10, getCamera().getScreenHeight() - yInc*2, fpsText);
+
+// sprintf(fpsText, "%d visible objects", mNbVisible);
+// renderer->print(10, mCamera.getScreenHeight() - yInc*3, fpsText);
+}
+
+void PhysXSample::onShutdown()
+{
+ //mScene->fetchResults(true);
+
+#if defined(RENDERER_TABLET)
+ getRenderer()->releaseAllButtons();
+#endif
+
+ releaseAll(mRenderActors);
+ releaseAll(mRenderTextures);
+ releaseAll(mRenderMaterials);
+ {
+ PxSceneWriteLock scopedLock(*mScene);
+ releaseAll(mPhysicsActors);
+ }
+
+ SAMPLE_FREE(mBufferedActiveTransforms);
+ mFixedStepper.shutdown();
+ mDebugStepper.shutdown();
+ mVariableStepper.shutdown();
+
+ const size_t nbManagedAssets = mManagedAssets.size();
+ if(nbManagedAssets)
+ {
+ SampleAssetManager* assetManager = mApplication.getAssetManager();
+ for(PxU32 i=0; i<nbManagedAssets; i++)
+ assetManager->returnAsset(*mManagedAssets[i]);
+ }
+ mManagedAssets.clear();
+
+ mApplication.getPlatform()->getSampleUserInput()->shutdown();
+
+ if(mSampleInputAsset)
+ {
+ mApplication.getAssetManager()->returnAsset(*mSampleInputAsset);
+ mSampleInputAsset = NULL;
+ }
+
+ mPhysics->unregisterDeletionListener(*this);
+
+ SAFE_RELEASE(mScene);
+ SAFE_RELEASE(mCpuDispatcher);
+
+// SAFE_RELEASE(mMaterial);
+ SAFE_RELEASE(mCooking);
+
+ PxCloseExtensions();
+
+ SAFE_RELEASE(mPhysics);
+
+#if PX_SUPPORT_GPU_PHYSX
+ SAFE_RELEASE(mCudaContextManager);
+#endif
+
+ SAFE_RELEASE(mPvd);
+ SAFE_RELEASE(mTransport);
+
+ SAFE_RELEASE(mFoundation);
+}
+
+//#define USE_MBP
+
+#ifdef USE_MBP
+
+static void setupMBP(PxScene& scene)
+{
+ const float range = 1000.0f;
+ const PxU32 subdiv = 4;
+// const PxU32 subdiv = 1;
+// const PxU32 subdiv = 2;
+// const PxU32 subdiv = 8;
+
+ const PxVec3 min(-range);
+ const PxVec3 max(range);
+ const PxBounds3 globalBounds(min, max);
+
+ PxBounds3 bounds[256];
+ const PxU32 nbRegions = PxBroadPhaseExt::createRegionsFromWorldBounds(bounds, globalBounds, subdiv);
+
+ for(PxU32 i=0;i<nbRegions;i++)
+ {
+ PxBroadPhaseRegion region;
+ region.bounds = bounds[i];
+ region.userData = (void*)i;
+ scene.addBroadPhaseRegion(region);
+ }
+}
+#endif
+
+
+
+void PhysXSample::onInit()
+{
+
+ //Recording memory allocations is necessary if you want to
+ //use the memory facilities in PVD effectively. Since PVD isn't necessarily connected
+ //right away, we add a mechanism that records all outstanding memory allocations and
+ //forwards them to PVD when it does connect.
+
+ //This certainly has a performance and memory profile effect and thus should be used
+ //only in non-production builds.
+ bool recordMemoryAllocations = true;
+#ifdef RENDERER_ANDROID
+ const bool useCustomTrackingAllocator = false;
+#else
+ const bool useCustomTrackingAllocator = true;
+#endif
+
+ PxAllocatorCallback* allocator = &gDefaultAllocatorCallback;
+
+ if(useCustomTrackingAllocator)
+ allocator = getSampleAllocator(); //optional override that will track memory allocations
+
+ mFoundation = PxCreateFoundation(PX_FOUNDATION_VERSION, *allocator, getSampleErrorCallback());
+ if(!mFoundation)
+ fatalError("PxCreateFoundation failed!");
+
+#if PX_SUPPORT_GPU_PHYSX
+ if(mCreateCudaCtxManager)
+ {
+ PxCudaContextManagerDesc cudaContextManagerDesc;
+
+#if defined(RENDERER_ENABLE_CUDA_INTEROP)
+ if (!mApplication.getCommandLine().hasSwitch("nointerop"))
+ {
+ switch(getRenderer()->getDriverType())
+ {
+ case Renderer::DRIVER_DIRECT3D11:
+ cudaContextManagerDesc.interopMode = PxCudaInteropMode::D3D11_INTEROP;
+ break;
+ case Renderer::DRIVER_OPENGL:
+ cudaContextManagerDesc.interopMode = PxCudaInteropMode::OGL_INTEROP;
+ break;
+ }
+ cudaContextManagerDesc.graphicsDevice = getRenderer()->getDevice();
+ }
+#endif
+ mCudaContextManager = PxCreateCudaContextManager(*mFoundation, cudaContextManagerDesc);
+ if( mCudaContextManager )
+ {
+ if( !mCudaContextManager->contextIsValid() )
+ {
+ mCudaContextManager->release();
+ mCudaContextManager = NULL;
+ }
+ }
+ }
+#endif
+
+ createPvdConnection();
+
+ PxTolerancesScale scale;
+ customizeTolerances(scale);
+
+ mPhysics = PxCreatePhysics(PX_PHYSICS_VERSION, *mFoundation, scale, recordMemoryAllocations, mPvd);
+ if(!mPhysics)
+ fatalError("PxCreatePhysics failed!");
+
+ if(!PxInitExtensions(*mPhysics, mPvd))
+ fatalError("PxInitExtensions failed!");
+
+ PxCookingParams params(scale);
+ params.meshWeldTolerance = 0.001f;
+ params.meshPreprocessParams = PxMeshPreprocessingFlags(PxMeshPreprocessingFlag::eWELD_VERTICES);
+ params.buildGPUData = true; //Enable GRB data being produced in cooking.
+ mCooking = PxCreateCooking(PX_PHYSICS_VERSION, *mFoundation, params);
+ if(!mCooking)
+ fatalError("PxCreateCooking failed!");
+
+ mPhysics->registerDeletionListener(*this, PxDeletionEventFlag::eUSER_RELEASE);
+
+ // setup default material...
+ mMaterial = mPhysics->createMaterial(0.5f, 0.5f, 0.1f);
+ if(!mMaterial)
+ fatalError("createMaterial failed!");
+
+#if defined(RENDERER_TABLET)
+ // load touchscreen control material
+ {
+ SampleFramework::SampleAsset* ps_asset = getAsset(controlMaterialPath, SampleFramework::SampleAsset::ASSET_MATERIAL);
+ mManagedAssets.push_back(ps_asset);
+ PX_ASSERT(ps_asset->getType() == SampleFramework::SampleAsset::ASSET_MATERIAL);
+ SampleFramework::SampleMaterialAsset* mat_ps_asset = static_cast<SampleFramework::SampleMaterialAsset*>(ps_asset);
+ if(mat_ps_asset->getNumVertexShaders() > 0)
+ {
+ RenderMaterial* mat = SAMPLE_NEW(RenderMaterial)(*getRenderer(), mat_ps_asset->getMaterial(0), mat_ps_asset->getMaterialInstance(0), MATERIAL_CONTROLS);
+ mRenderMaterials.push_back(mat);
+ }
+ }
+ // load touchscreen button material
+ {
+ SampleFramework::SampleAsset* ps_asset = getAsset(buttonMaterialPath, SampleFramework::SampleAsset::ASSET_MATERIAL);
+ mManagedAssets.push_back(ps_asset);
+ PX_ASSERT(ps_asset->getType() == SampleFramework::SampleAsset::ASSET_MATERIAL);
+ SampleFramework::SampleMaterialAsset* mat_ps_asset = static_cast<SampleFramework::SampleMaterialAsset*>(ps_asset);
+ if(mat_ps_asset->getNumVertexShaders() > 0)
+ {
+ RenderMaterial* mat = SAMPLE_NEW(RenderMaterial)(*getRenderer(), mat_ps_asset->getMaterial(0), mat_ps_asset->getMaterialInstance(0), MATERIAL_BUTTONS);
+ mRenderMaterials.push_back(mat);
+ }
+ }
+ Renderer* renderer = getRenderer();
+ RenderMaterial* controlMaterial = getMaterial(MATERIAL_CONTROLS);
+ renderer->initControls(controlMaterial->mRenderMaterial,
+ controlMaterial->mRenderMaterialInstance);
+ RenderMaterial* buttonMaterial = getMaterial(MATERIAL_BUTTONS);
+ // add buttons for common use
+ PxReal yInc = -0.12f;
+ PxVec2 leftBottom(0.58f, 0.90f);
+ PxVec2 rightTop(0.99f, 0.82f);
+ renderer->addButton(leftBottom, rightTop, NULL,
+ buttonMaterial->mRenderMaterial, buttonMaterial->mRenderMaterialInstance);
+ leftBottom.y += yInc; rightTop.y += yInc;
+ renderer->addButton(leftBottom, rightTop, NULL,
+ buttonMaterial->mRenderMaterial, buttonMaterial->mRenderMaterialInstance);
+ leftBottom.y += yInc; rightTop.y += yInc;
+ renderer->addButton(leftBottom, rightTop, NULL,
+ buttonMaterial->mRenderMaterial, buttonMaterial->mRenderMaterialInstance);
+ leftBottom.y += yInc; rightTop.y += yInc;
+ renderer->addButton(leftBottom, rightTop, NULL,
+ buttonMaterial->mRenderMaterial, buttonMaterial->mRenderMaterialInstance);
+ leftBottom.y += yInc; rightTop.y += yInc;
+
+ // add buttons for individual sample
+ leftBottom.y += yInc; rightTop.y += yInc;
+ renderer->addButton(leftBottom, rightTop, NULL,
+ buttonMaterial->mRenderMaterial, buttonMaterial->mRenderMaterialInstance);
+ leftBottom.y += yInc; rightTop.y += yInc;
+ renderer->addButton(leftBottom, rightTop, NULL,
+ buttonMaterial->mRenderMaterial, buttonMaterial->mRenderMaterialInstance);
+ leftBottom.y += yInc; rightTop.y += yInc;
+ renderer->addButton(leftBottom, rightTop, NULL,
+ buttonMaterial->mRenderMaterial, buttonMaterial->mRenderMaterialInstance);
+ leftBottom.y += yInc; rightTop.y += yInc;
+ renderer->addButton(leftBottom, rightTop, NULL,
+ buttonMaterial->mRenderMaterial, buttonMaterial->mRenderMaterialInstance);
+ leftBottom.y += yInc; rightTop.y += yInc;
+ renderer->addButton(leftBottom, rightTop, NULL,
+ buttonMaterial->mRenderMaterial, buttonMaterial->mRenderMaterialInstance);
+
+ // quick access button
+ leftBottom.y += yInc; rightTop.y += yInc;
+ renderer->addButton(leftBottom, rightTop, NULL,
+ buttonMaterial->mRenderMaterial, buttonMaterial->mRenderMaterialInstance);
+
+ // next, previous buttons
+ leftBottom.x = -0.4f;
+ leftBottom.y = 0.9f;
+ rightTop.x = -0.1f;
+ rightTop.y = 0.82f;
+ renderer->addButton(leftBottom, rightTop, NULL,
+ buttonMaterial->mRenderMaterial, buttonMaterial->mRenderMaterialInstance);
+ leftBottom.x = 0.1f;
+ leftBottom.y = 0.9f;
+ rightTop.x = 0.4f;
+ rightTop.y = 0.82f;
+ renderer->addButton(leftBottom, rightTop, NULL,
+ buttonMaterial->mRenderMaterial, buttonMaterial->mRenderMaterialInstance);
+
+#endif
+
+ PX_ASSERT(NULL == mScene);
+
+ PxSceneDesc sceneDesc(mPhysics->getTolerancesScale());
+ sceneDesc.gravity = PxVec3(0.0f, -9.81f, 0.0f);
+ getDefaultSceneDesc(sceneDesc);
+
+
+
+ if(!sceneDesc.cpuDispatcher)
+ {
+ mCpuDispatcher = PxDefaultCpuDispatcherCreate(mNbThreads);
+ if(!mCpuDispatcher)
+ fatalError("PxDefaultCpuDispatcherCreate failed!");
+ sceneDesc.cpuDispatcher = mCpuDispatcher;
+ }
+
+ if(!sceneDesc.filterShader)
+ sceneDesc.filterShader = getSampleFilterShader();
+
+#if PX_SUPPORT_GPU_PHYSX
+ if(!sceneDesc.gpuDispatcher && mCudaContextManager)
+ sceneDesc.gpuDispatcher = mCudaContextManager->getGpuDispatcher();
+#endif
+
+ //sceneDesc.frictionType = PxFrictionType::eTWO_DIRECTIONAL;
+ //sceneDesc.frictionType = PxFrictionType::eONE_DIRECTIONAL;
+ sceneDesc.flags |= PxSceneFlag::eENABLE_GPU_DYNAMICS;
+ sceneDesc.flags |= PxSceneFlag::eENABLE_PCM;
+ //sceneDesc.flags |= PxSceneFlag::eENABLE_AVERAGE_POINT;
+ sceneDesc.flags |= PxSceneFlag::eENABLE_STABILIZATION;
+ //sceneDesc.flags |= PxSceneFlag::eADAPTIVE_FORCE;
+ sceneDesc.flags |= PxSceneFlag::eENABLE_ACTIVETRANSFORMS;
+ sceneDesc.flags |= PxSceneFlag::eSUPPRESS_EAGER_SCENE_QUERY_REFIT;
+ //sceneDesc.flags |= PxSceneFlag::eDISABLE_CONTACT_CACHE;
+ sceneDesc.broadPhaseType = PxBroadPhaseType::eGPU;
+ sceneDesc.gpuMaxNumPartitions = 8;
+
+
+#ifdef USE_MBP
+ sceneDesc.broadPhaseType = PxBroadPhaseType::eMBP;
+#endif
+
+ customizeSceneDesc(sceneDesc);
+
+ mScene = mPhysics->createScene(sceneDesc);
+ if(!mScene)
+ fatalError("createScene failed!");
+
+ PxSceneWriteLock scopedLock(*mScene);
+
+ PxSceneFlags flag = mScene->getFlags();
+
+ PX_UNUSED(flag);
+ mScene->setVisualizationParameter(PxVisualizationParameter::eSCALE, mInitialDebugRender ? mDebugRenderScale : 0.0f);
+ mScene->setVisualizationParameter(PxVisualizationParameter::eCOLLISION_SHAPES, 1.0f);
+
+ PxPvdSceneClient* pvdClient = mScene->getScenePvdClient();
+ if(pvdClient)
+ {
+ pvdClient->setScenePvdFlag(PxPvdSceneFlag::eTRANSMIT_CONSTRAINTS, true);
+ pvdClient->setScenePvdFlag(PxPvdSceneFlag::eTRANSMIT_CONTACTS, true);
+ pvdClient->setScenePvdFlag(PxPvdSceneFlag::eTRANSMIT_SCENEQUERIES, true);
+ }
+
+#ifdef USE_MBP
+ setupMBP(*mScene);
+#endif
+
+ mApplication.refreshVisualizationMenuState(PxVisualizationParameter::eCOLLISION_SHAPES);
+ mApplication.applyDefaultVisualizationSettings();
+ mApplication.setMouseCursorHiding(false);
+ mApplication.setMouseCursorRecentering(false);
+ mCameraController.setMouseLookOnMouseButton(false);
+ mCameraController.setMouseSensitivity(1.0f);
+
+ if(mCreateGroundPlane)
+ createGrid();
+
+ LOG_INFO("PhysXSample", "Init sample ok!");
+}
+
+RenderMaterial* PhysXSample::getMaterial(PxU32 materialID)
+{
+ for(PxU32 i = 0; i < mRenderMaterials.size(); ++i)
+ {
+ if(mRenderMaterials[i]->mID == materialID)
+ {
+ return mRenderMaterials[i];
+ }
+ }
+
+ return NULL;
+}
+
+Stepper* PhysXSample::getStepper()
+{
+ switch(mStepperType)
+ {
+ case DEFAULT_STEPPER:
+ return &mDebugStepper;
+ case FIXED_STEPPER:
+ return &mFixedStepper;
+ default:
+ return &mVariableStepper;
+ };
+}
+
+
+// ### PT: TODO: refactor this with onTickPreRender
+void PhysXSample::freeDeletedActors()
+{
+ getRenderer()->finishRendering();
+
+ // delete buffered render actors
+ for (size_t i = mDeletedRenderActors.size(); i--;)
+ {
+ mDeletedRenderActors[i]->release();
+ }
+ mDeletedRenderActors.clear();
+}
+
+void PhysXSample::onTickPreRender(float dtime)
+{
+ // delete buffered render actors
+ for (size_t i = mDeletedRenderActors.size(); i--;)
+ {
+ mDeletedRenderActors[i]->release();
+ }
+ mDeletedRenderActors.clear();
+
+#if PX_PROFILE
+ {
+#endif
+ PxSceneWriteLock scopedLock(*mScene);
+
+
+ mApplication.baseTickPreRender(dtime);
+
+ mFPS.update();
+#if PX_PROFILE
+ }
+#endif
+ if(!isPaused())
+ {
+ Stepper* stepper = getStepper();
+
+ mWaitForResults = false;
+
+ if(mScene)
+ {
+ updateRenderObjectsAsync(dtime);
+
+#if !PX_PROFILE
+ mWaitForResults = stepper->advance(mScene, dtime, mScratchBlock, SCRATCH_BLOCK_SIZE);
+
+ // tells the stepper shape data is not going to be accessed until next frame
+ // (frame ends with stepper->wait(mScene))
+ stepper->renderDone();
+
+#else
+ // in profile builds we run the whole frame sequentially
+ // simulate, wait, update render objects, render
+ {
+ mWaitForResults = stepper->advance(mScene, dtime, mScratchBlock, SCRATCH_BLOCK_SIZE);
+ stepper->renderDone();
+ if (mWaitForResults)
+ {
+ stepper->wait(mScene);
+ mSimulationTime = stepper->getSimulationTime();
+ }
+ }
+
+ // update render objects immediately
+ if (mWaitForResults)
+ {
+ bufferActiveTransforms();
+ updateRenderObjectsSync(dtime);
+ if (mOneFrameUpdate)
+ updateRenderObjectsAsync(dtime);
+ }
+#endif
+ }
+ }
+
+ // profile builds should update render actors
+ // and debug draw immediately to avoid one frame lag
+#if PX_PROFILE
+ RenderPhysX3Debug* debugRenderer = getDebugRenderer();
+ if(debugRenderer && mScene)
+ {
+ const PxRenderBuffer& debugRenderable = mScene->getRenderBuffer();
+ debugRenderer->update(debugRenderable);
+
+ updateRenderObjectsDebug(dtime);
+ }
+#endif
+
+
+ if(mPicking)
+ {
+ mPicking->tick();
+ }
+}
+
+void PhysXSample::onTickPostRender(float dtime)
+{
+#if !PX_PROFILE
+
+ if(!isPaused())
+ {
+ if(mScene && mWaitForResults)
+ {
+ Stepper* stepper = getStepper();
+ stepper->wait(mScene);
+ mSimulationTime = stepper->getSimulationTime();
+
+ bufferActiveTransforms();
+
+ // make sure that in single step mode, the render objects get updated immediately
+ if (mOneFrameUpdate)
+ {
+ updateRenderObjectsSync(dtime);
+ updateRenderObjectsAsync(dtime);
+ }
+ else
+ updateRenderObjectsSync(dtime);
+
+ }
+ }
+#else
+
+ if(!isPaused() && mScene && mWaitForResults )
+ {
+ Stepper* stepper = getStepper();
+ //stepper->wait(mScene);
+ stepper->postRender(dtime);
+ }
+
+#endif
+
+
+
+ RenderPhysX3Debug* debugRenderer = getDebugRenderer();
+ if(debugRenderer && mScene)
+ {
+ const PxRenderBuffer& debugRenderable = mScene->getRenderBuffer();
+ PX_UNUSED(debugRenderable);
+ debugRenderer->clear();
+
+#if !PX_PROFILE
+ debugRenderer->update(debugRenderable);
+ updateRenderObjectsDebug(dtime);
+#endif
+
+ renderScene();
+ }
+
+ if(mOneFrameUpdate)
+ {
+ mOneFrameUpdate = false;
+ if (!isPaused()) togglePause();
+ }
+
+#ifdef PRINT_BLOCK_COUNTERS
+ static PxU32 refMax = -1;
+ PxU32 newMax = getActiveScene().getMaxNbContactDataBlocksUsed();
+ if(refMax != newMax)
+ shdfnd::printFormatted("max blocks used: %d\n",newMax);
+ refMax = newMax;
+#endif // PRINT_BLOCK_COUNTERS
+}
+
+void PhysXSample::saveUserInputs()
+{
+ char name[256];
+ char sBuffer[512];
+
+ const char* sampleName = mApplication.mRunning->getName();
+
+ SampleUserInput* sampleUserInput = mApplication.getPlatform()->getSampleUserInput();
+ if(!sampleUserInput)
+ return;
+
+ strcpy(name,"input");
+ strcat(name,"/UserInputList.txt");
+
+ if(getSampleOutputDirManager().getFilePath(name, sBuffer, false))
+ {
+ sprintf(name, "input/%s/%sUserInputList.txt", sampleName,mApplication.getPlatform()->getPlatformName());
+
+ if(getSampleOutputDirManager().getFilePath(name, sBuffer, false))
+ {
+ SampleFramework::File* file = NULL;
+ PxToolkit::fopen_s(&file, sBuffer, "w");
+
+ if(file)
+ {
+ fputs("UserInputList:\n",file);
+ fputs("----------------------------------------\n",file);
+ const std::vector<UserInput>& ilist = sampleUserInput->getUserInputList();
+ for (size_t i = 0; i < ilist.size(); i++)
+ {
+ const UserInput& ui = ilist[i];
+ fputs(ui.m_IdName,file);
+ fputs("\n",file);
+ }
+
+ fclose(file);
+ }
+ }
+ }
+}
+
+void PhysXSample::saveInputEvents(const std::vector<const InputEvent*>& inputEvents)
+{
+ char name[256];
+ char sBuffer[512];
+
+ const char* sampleName = mApplication.mRunning->getName();
+ SampleUserInput* sampleUserInput = mApplication.getPlatform()->getSampleUserInput();
+ if(!sampleUserInput)
+ return;
+
+ strcpy(name,"input");
+ strcat(name,"/InputEventList.txt");
+
+ if(getSampleOutputDirManager().getFilePath(name, sBuffer, false))
+ {
+ sprintf(name, "input/%s/%sInputEventList.txt", sampleName,mApplication.getPlatform()->getPlatformName());
+
+ if(getSampleOutputDirManager().getFilePath(name, sBuffer, false))
+ {
+ SampleFramework::File* file = NULL;
+ PxToolkit::fopen_s(&file, sBuffer, "w");
+
+ if(file)
+ {
+ fputs("InputEventList:\n",file);
+ fputs("----------------------------------------\n",file);
+ for (size_t i = 0; i < inputEvents.size(); i++)
+ {
+ const InputEvent* inputEvent = inputEvents[i];
+
+ if(!inputEvent)
+ continue;
+
+ const std::vector<size_t>* userInputs = sampleUserInput->getUserInputs(inputEvent->m_Id);
+ const char* name = sampleUserInput->translateInputEventIdToName(inputEvent->m_Id);
+ if(userInputs && !userInputs->empty() && name)
+ {
+ fputs(name,file);
+ fputs("\n",file);
+ }
+ }
+
+ fclose(file);
+ }
+ }
+ }
+}
+
+void PhysXSample::parseSampleOutputAsset(const char* sampleName,PxU32 userInputCS, PxU32 inputEventCS)
+{
+ char name[256];
+ char sBuffer[512];
+
+ SampleUserInput* sampleUserInput = mApplication.getPlatform()->getSampleUserInput();
+ if(!sampleUserInput)
+ return;
+
+ sprintf(name, "input/%s/%sInputMapping.ods", sampleName,mApplication.getPlatform()->getPlatformName());
+ if(getSampleOutputDirManager().getFilePath(name, sBuffer, false))
+ {
+ SampleInputMappingAsset* inputAsset = NULL;
+ SampleFramework::File* fp = NULL;
+ PxToolkit::fopen_s(&fp, sBuffer, "r");
+ if(fp)
+ {
+ inputAsset = SAMPLE_NEW(SampleInputMappingAsset)(fp,sBuffer, false, userInputCS, inputEventCS);
+ if(!inputAsset->isOk())
+ {
+ DELETESINGLE(inputAsset);
+ fp = NULL;
+ }
+ }
+
+ if(inputAsset)
+ {
+ std::vector<SampleInputMapping> inputMappings;
+ for (size_t i = inputAsset->getSampleInputData().size();i--;)
+ {
+ const SampleInputData& data = inputAsset->getSampleInputData()[i];
+ size_t userInputIndex;
+ PxI32 userInputId = sampleUserInput->translateUserInputNameToId(data.m_UserInputName,userInputIndex);
+ size_t inputEventIndex;
+ PxI32 inputEventId = sampleUserInput->translateInputEventNameToId(data.m_InputEventName, inputEventIndex);
+ if(userInputId >= 0 && inputEventId >= 0)
+ {
+ SampleInputMapping mapping;
+ mapping.m_InputEventId = inputEventId;
+ mapping.m_InputEventIndex = inputEventIndex;
+ mapping.m_UserInputId = userInputId;
+ mapping.m_UserInputIndex = userInputIndex;
+ inputMappings.push_back(mapping);
+ }
+ else
+ {
+ //if we get here we read a command mapping from file that is no longer supported in code ... it should be ignored.
+ }
+ }
+
+ for (size_t i = inputMappings.size(); i--;)
+ {
+ const SampleInputMapping& mapping = inputMappings[i];
+ sampleUserInput->unregisterInputEvent(mapping.m_InputEventId);
+ }
+
+ //now I have the default keys definition left, save it to the mapping
+ const std::vector<UserInput>& userInputs = sampleUserInput->getUserInputList();
+ const std::map<physx::PxU16, std::vector<size_t> >& inputEventUserInputMap = sampleUserInput->getInputEventUserInputMap();
+ std::map<physx::PxU16, std::vector<size_t> >::const_iterator it = inputEventUserInputMap.begin();
+ std::map<physx::PxU16, std::vector<size_t> >::const_iterator itEnd = inputEventUserInputMap.end();
+ while (it != itEnd)
+ {
+ PxU16 inputEventId = it->first;
+ const std::vector<size_t>& uis = it->second;
+ for (size_t j = 0; j < uis.size(); j++)
+ {
+ const UserInput& ui = userInputs[uis[j]];
+ const char* eventName = sampleUserInput->translateInputEventIdToName(inputEventId);
+ if(eventName)
+ {
+ inputAsset->addMapping(ui.m_IdName, eventName);
+ }
+ }
+ ++it;
+ }
+
+ for (size_t i = inputMappings.size(); i--;)
+ {
+ const SampleInputMapping& mapping = inputMappings[i];
+ sampleUserInput->registerInputEvent(mapping);
+ }
+ }
+ else
+ {
+ // the file does not exist create one
+ SampleFramework::File* fp = NULL;
+ PxToolkit::fopen_s(&fp, sBuffer, "w");
+ if(fp)
+ {
+ inputAsset = SAMPLE_NEW(SampleInputMappingAsset)(fp,sBuffer,true,userInputCS, inputEventCS);
+
+ const std::vector<UserInput>& userInputs = sampleUserInput->getUserInputList();
+ const std::map<physx::PxU16, std::vector<size_t> >& inputEventUserInputMap = sampleUserInput->getInputEventUserInputMap();
+ std::map<physx::PxU16, std::vector<size_t> >::const_iterator it = inputEventUserInputMap.begin();
+ std::map<physx::PxU16, std::vector<size_t> >::const_iterator itEnd = inputEventUserInputMap.end();
+ while (it != itEnd)
+ {
+ PxU16 inputEventId = it->first;
+ const std::vector<size_t>& uis = it->second;
+ for (size_t j = 0; j < uis.size(); j++)
+ {
+ const UserInput& ui = userInputs[uis[j]];
+ const char* eventName = sampleUserInput->translateInputEventIdToName(inputEventId);
+ if(eventName)
+ {
+ inputAsset->addMapping(ui.m_IdName, eventName);
+ }
+ }
+ ++it;
+ }
+ }
+ }
+
+ if(inputAsset)
+ {
+ inputAsset->saveMappings();
+ DELETESINGLE(inputAsset);
+ }
+ }
+}
+
+void PhysXSample::prepareInputEventUserInputInfo(const char* sampleName,PxU32 &userInputCS, PxU32 &inputEventCS)
+{
+ SampleUserInput* sampleUserInput = mApplication.getPlatform()->getSampleUserInput();
+ if(!sampleUserInput)
+ return;
+
+ saveUserInputs();
+
+ std::vector<const InputEvent*> inputEvents;
+ mApplication.collectInputEvents(inputEvents);
+
+ for (size_t i = inputEvents.size(); i--;)
+ {
+ const InputEvent* ie = inputEvents[i];
+ inputEventCS += ie->m_Id;
+
+ const std::vector<size_t>* userInputs = sampleUserInput->getUserInputs(ie->m_Id);
+ if(userInputs)
+ {
+ for (size_t j = userInputs->size(); j--;)
+ {
+ const UserInput& ui = sampleUserInput->getUserInputList()[ (*userInputs)[j] ];
+ userInputCS += (ui.m_Id + ie->m_Id);
+ }
+ }
+ }
+
+ inputEventCS = inputEventCS + ((PxU16)sampleUserInput->getInputEventList().size() << 16);
+ userInputCS = userInputCS + ((PxU16)sampleUserInput->getUserInputList().size() << 16);
+
+ saveInputEvents(inputEvents);
+
+ char name[256];
+
+ strcpy(name,"input/");
+ strcat(name,mApplication.getPlatform()->getPlatformName());
+ strcat(name,"/");
+ strcat(name,sampleName);
+ strcat(name,"InputMapping.ods");
+
+ // load the additional mapping file
+ mSampleInputAsset = (SampleInputAsset*)getAsset(name, SampleAsset::ASSET_INPUT, false);
+}
+
+void PhysXSample::unregisterInputEvents()
+{
+ mApplication.getPlatform()->getSampleUserInput()->shutdown();
+}
+
+void PhysXSample::registerInputEvents(bool ignoreSaved)
+{
+ const char* sampleName = mApplication.mRunning->getName();
+
+ SampleUserInput* sampleUserInput = mApplication.getPlatform()->getSampleUserInput();
+ if(!sampleUserInput)
+ return;
+
+ PxU32 inputEventCS = 0;
+ PxU32 userInputCS = 0;
+ prepareInputEventUserInputInfo(sampleName, inputEventCS, userInputCS);
+
+ // register the additional mapping
+ if(mSampleInputAsset)
+ {
+ std::vector<SampleInputMapping> inputMappings;
+ for (size_t i = mSampleInputAsset->GetSampleInputData().size();i--;)
+ {
+ const SampleInputData& data = mSampleInputAsset->GetSampleInputData()[i];
+ size_t userInputIndex;
+ PxI32 userInputId = sampleUserInput->translateUserInputNameToId(data.m_UserInputName,userInputIndex);
+ size_t inputEventIndex;
+ PxI32 inputEventId = sampleUserInput->translateInputEventNameToId(data.m_InputEventName, inputEventIndex);
+ if(userInputId >= 0 && inputEventId >= 0)
+ {
+ SampleInputMapping mapping;
+ mapping.m_InputEventId = inputEventId;
+ mapping.m_InputEventIndex = inputEventIndex;
+ mapping.m_UserInputId = userInputId;
+ mapping.m_UserInputIndex = userInputIndex;
+ inputMappings.push_back(mapping);
+ }
+ else
+ {
+ PX_ASSERT(0);
+ }
+ }
+
+ for (size_t i = inputMappings.size(); i--;)
+ {
+ const SampleInputMapping& mapping = inputMappings[i];
+ sampleUserInput->registerInputEvent(mapping);
+ }
+ }
+
+#if !defined(RENDERER_TABLET)
+ if (!ignoreSaved)
+ parseSampleOutputAsset(sampleName, inputEventCS, userInputCS);
+#endif
+}
+
+void PhysXSample::onKeyDownEx(SampleFramework::SampleUserInput::KeyCode keyCode, PxU32 param)
+{
+}
+
+void PhysXSample::collectInputEvents(std::vector<const SampleFramework::InputEvent*>& inputEvents)
+{
+ //digital keyboard events
+ DIGITAL_INPUT_EVENT_DEF(SPAWN_DEBUG_OBJECT, WKEY_1, XKEY_1, X1KEY_1, PS3KEY_1, PS4KEY_1, AKEY_UNKNOWN, OSXKEY_1, IKEY_UNKNOWN, LINUXKEY_1, WIIUKEY_UNKNOWN );
+ DIGITAL_INPUT_EVENT_DEF(PAUSE_SAMPLE, WKEY_P, XKEY_P, X1KEY_P, PS3KEY_P, PS4KEY_P, AKEY_UNKNOWN, OSXKEY_P, IKEY_UNKNOWN, LINUXKEY_P, WIIUKEY_UNKNOWN );
+ DIGITAL_INPUT_EVENT_DEF(STEP_ONE_FRAME, WKEY_O, XKEY_O, X1KEY_O, PS3KEY_O, PS4KEY_O, AKEY_UNKNOWN, OSXKEY_O, IKEY_UNKNOWN, LINUXKEY_O, WIIUKEY_UNKNOWN );
+ DIGITAL_INPUT_EVENT_DEF(TOGGLE_VISUALIZATION, WKEY_V, XKEY_V, X1KEY_V, PS3KEY_V, PS4KEY_V, AKEY_UNKNOWN, OSXKEY_V, IKEY_UNKNOWN, LINUXKEY_V, WIIUKEY_UNKNOWN );
+ DIGITAL_INPUT_EVENT_DEF(DECREASE_DEBUG_RENDER_SCALE, WKEY_F7, XKEY_F7, X1KEY_F7, PS3KEY_F7, PS4KEY_F7, AKEY_UNKNOWN, OSXKEY_F7, IKEY_UNKNOWN, LINUXKEY_F7, WIIUKEY_UNKNOWN );
+ DIGITAL_INPUT_EVENT_DEF(INCREASE_DEBUG_RENDER_SCALE, WKEY_F8, XKEY_F8, X1KEY_F8, PS3KEY_F8, PS4KEY_F8, AKEY_UNKNOWN, OSXKEY_F8, IKEY_UNKNOWN, LINUXKEY_F8, WIIUKEY_UNKNOWN );
+ DIGITAL_INPUT_EVENT_DEF(HIDE_GRAPHICS, WKEY_G, XKEY_G, X1KEY_G, PS3KEY_G, PS4KEY_G, AKEY_UNKNOWN, OSXKEY_G, IKEY_UNKNOWN, LINUXKEY_G, WIIUKEY_UNKNOWN );
+ DIGITAL_INPUT_EVENT_DEF(WIREFRAME, WKEY_N, XKEY_N, X1KEY_N, PS3KEY_N, PS4KEY_N, AKEY_UNKNOWN, OSXKEY_N, IKEY_UNKNOWN, LINUXKEY_N, WIIUKEY_UNKNOWN );
+ DIGITAL_INPUT_EVENT_DEF(TOGGLE_PVD_CONNECTION, WKEY_F5, XKEY_F5, X1KEY_F5, PS3KEY_F5, PS4KEY_F5, AKEY_UNKNOWN, OSXKEY_F5, IKEY_UNKNOWN, LINUXKEY_F5, WIIUKEY_UNKNOWN );
+ DIGITAL_INPUT_EVENT_DEF(SHOW_HELP, WKEY_H, XKEY_H, X1KEY_H, PS3KEY_H, PS4KEY_H, AKEY_UNKNOWN, OSXKEY_H, IKEY_UNKNOWN, LINUXKEY_H, WIIUKEY_UNKNOWN );
+ DIGITAL_INPUT_EVENT_DEF(SHOW_DESCRIPTION, WKEY_F, XKEY_F, X1KEY_F, PS3KEY_F, PS4KEY_F, AKEY_UNKNOWN, OSXKEY_F, IKEY_UNKNOWN, LINUXKEY_F, WIIUKEY_UNKNOWN );
+ DIGITAL_INPUT_EVENT_DEF(VARIABLE_TIMESTEP, WKEY_T, XKEY_T, X1KEY_T, PS3KEY_T, PS4KEY_T, AKEY_UNKNOWN, OSXKEY_T, IKEY_UNKNOWN, LINUXKEY_T, WIIUKEY_UNKNOWN );
+ DIGITAL_INPUT_EVENT_DEF(NEXT_PAGE, WKEY_NEXT, XKEY_UNKNOWN, X1KEY_UNKNOWN, PS3KEY_NEXT, PS4KEY_NEXT, AKEY_UNKNOWN, OSXKEY_RIGHT, IKEY_UNKNOWN, LINUXKEY_NEXT, WIIUKEY_UNKNOWN );
+ DIGITAL_INPUT_EVENT_DEF(PREVIOUS_PAGE, WKEY_PRIOR, XKEY_UNKNOWN, X1KEY_UNKNOWN, PS3KEY_PRIOR, PS4KEY_PRIOR, AKEY_UNKNOWN, OSXKEY_LEFT, IKEY_UNKNOWN, LINUXKEY_PRIOR, WIIUKEY_UNKNOWN );
+ DIGITAL_INPUT_EVENT_DEF(PROFILE_ONLY_PVD, WKEY_9, XKEY_UNKNOWN, X1KEY_UNKNOWN, PS3KEY_UNKNOWN, PS4KEY_UNKNOWN, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, WIIUKEY_UNKNOWN );
+ //DIGITAL_INPUT_EVENT_DEF(PAUSE_SAMPLE, WKEY_P, XKEY_UNKNOWN, X1KEY_UNKNOWN, PS3KEY_UNKNOWN, PS4KEY_UNKNOWN, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN);
+ //DIGITAL_INPUT_EVENT_DEF(STEP_ONE_FRAME, WKEY_O, XKEY_UNKNOWN, X1KEY_UNKNOWN, PS3KEY_UNKNOWN, PS4KEY_UNKNOWN, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN);
+
+ //digital gamepad events
+ DIGITAL_INPUT_EVENT_DEF(SHOW_HELP, GAMEPAD_SELECT, GAMEPAD_SELECT, GAMEPAD_SELECT, GAMEPAD_SELECT, GAMEPAD_SELECT, AKEY_UNKNOWN, GAMEPAD_SELECT, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_SELECT);
+ DIGITAL_INPUT_EVENT_DEF(SPAWN_DEBUG_OBJECT, GAMEPAD_NORTH, GAMEPAD_NORTH, GAMEPAD_NORTH, GAMEPAD_NORTH, GAMEPAD_NORTH, AKEY_UNKNOWN, GAMEPAD_NORTH, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_NORTH);
+
+ //digital mouse events (are registered in the individual samples as needed)
+
+ //touch events (reserve first 4 buttons for common use, individual samples start from 5)
+ TOUCH_INPUT_EVENT_DEF(PAUSE_SAMPLE, "Pause", ABUTTON_1, IBUTTON_1);
+ TOUCH_INPUT_EVENT_DEF(STEP_ONE_FRAME, "Single Step", ABUTTON_2, IBUTTON_2);
+}
+
+void PhysXSample::onAnalogInputEvent(const SampleFramework::InputEvent& , float val)
+{
+}
+
+void PhysXSample::onDigitalInputEvent(const SampleFramework::InputEvent& ie, bool val)
+{
+ if (!mScene) return;
+
+ if (val)
+ {
+ if (mShowExtendedHelp)
+ {
+ switch (ie.m_Id)
+ {
+ case NEXT_PAGE:
+ {
+ mExtendedHelpPage++;
+ }
+ break;
+ case PREVIOUS_PAGE:
+ {
+ if(mExtendedHelpPage)
+ mExtendedHelpPage--;
+ }
+ break;
+ }
+ return;
+ }
+
+ switch (ie.m_Id)
+ {
+ case SPAWN_DEBUG_OBJECT:
+ spawnDebugObject();
+ break;
+ case PAUSE_SAMPLE:
+ togglePause();
+ break;
+ case STEP_ONE_FRAME:
+ mOneFrameUpdate = !mOneFrameUpdate;
+ break;
+ case TOGGLE_VISUALIZATION:
+ toggleVisualizationParam(*mScene, PxVisualizationParameter::eSCALE);
+ break;
+ case DECREASE_DEBUG_RENDER_SCALE:
+ {
+ mDebugRenderScale -= 0.1f;
+ mDebugRenderScale = PxMax(mDebugRenderScale, 0.f);
+ mScene->setVisualizationParameter(PxVisualizationParameter::eSCALE, mDebugRenderScale);
+ break;
+ }
+ case INCREASE_DEBUG_RENDER_SCALE:
+ {
+ mDebugRenderScale += 0.1f;
+ mScene->setVisualizationParameter(PxVisualizationParameter::eSCALE, mDebugRenderScale);
+ break;
+ }
+ case HIDE_GRAPHICS:
+ mHideGraphics = !mHideGraphics;
+ break;
+ case WIREFRAME:
+ {
+ mWireFrame = !mWireFrame;
+ break;
+ }
+ case TOGGLE_PVD_CONNECTION:
+ {
+ togglePvdConnection();
+ break;
+ }
+ case SHOW_HELP:
+ mShowHelp = !mShowHelp;
+ if(mShowHelp) mShowDescription=false;
+ break;
+ case SHOW_DESCRIPTION:
+ mShowDescription = !mShowDescription;
+ if(mShowDescription) mShowHelp=false;
+ break;
+ case VARIABLE_TIMESTEP:
+ mStepperType = (mStepperType == VARIABLE_STEPPER) ? FIXED_STEPPER : VARIABLE_STEPPER;
+ //mUseFixedStepper = !mUseFixedStepper;
+ mFixedStepper.reset();
+ mVariableStepper.reset();
+ break;
+ case DELETE_PICKED:
+ if(mPicked && mPicking)
+ {
+ PxActor* pickedActor = mPicking->letGo();
+ if(pickedActor)
+ pickedActor->release();
+ }
+ break;
+ case PICKUP:
+ {
+ if(mPicking)
+ {
+ mPicked = true;
+ PxU32 width;
+ PxU32 height;
+ mApplication.getPlatform()->getWindowSize(width, height);
+ mPicking->moveCursor(width/2,height/2);
+ mPicking->lazyPick();
+ }
+ }
+ break;
+ case PROFILE_ONLY_PVD:
+ if (mPvdParams.useFullPvdConnection)
+ {
+ if(mPvd)
+ {
+ mPvd->disconnect();
+ mPvdParams.useFullPvdConnection = false;
+ mPvd->connect(*mTransport,physx::PxPvdInstrumentationFlag::ePROFILE);
+ }
+ }
+ break;
+ default: break;
+ }
+ }
+ else
+ {
+ if (mShowExtendedHelp)
+ {
+ return;
+ }
+
+ if (ie.m_Id == PICKUP)
+ {
+ if(mPicking)
+ {
+ mPicked = false;
+ mPicking->letGo();
+ }
+ }
+ }
+}
+
+void PhysXSample::toggleFlyCamera()
+{
+ mIsFlyCamera = !mIsFlyCamera;
+ if (mIsFlyCamera)
+ {
+ mSavedCameraController = getCurrentCameraController();
+ mApplication.saveCameraState();
+ mFlyCameraController.init(getCamera().getViewMatrix());
+ mFlyCameraController.setMouseLookOnMouseButton(false);
+ mFlyCameraController.setMouseSensitivity(0.2f);
+ setCameraController(&mFlyCameraController);
+ }
+ else
+ {
+ mApplication.restoreCameraState();
+ setCameraController(mSavedCameraController);
+ }
+}
+
+void PhysXSample::togglePause()
+{
+ //unregisterInputEvents();
+ mPause = !mPause;
+ if (mEnableAutoFlyCamera)
+ {
+ if (mPause)
+ {
+ mSavedCameraController = getCurrentCameraController();
+ mApplication.saveCameraState();
+ mFlyCameraController.init(getCamera().getViewMatrix());
+ setCameraController(&mFlyCameraController);
+ }
+ else
+ {
+ mApplication.restoreCameraState();
+ setCameraController(mSavedCameraController);
+ }
+ }
+ //registerInputEvents(true);
+}
+
+void PhysXSample::showExtendedInputEventHelp(PxU32 x, PxU32 y)
+{
+ const PxReal scale = 0.5f;
+ const PxReal shadowOffset = 6.0f;
+ const RendererColor textColor(255, 255, 255, 255);
+
+ Renderer* renderer = getRenderer();
+ const PxU32 yInc = 18;
+ char message[512];
+
+ PxU32 width = 0;
+ PxU32 height = 0;
+ renderer->getWindowSize(width, height);
+ y += yInc;
+
+ PxU16 numIe = (height - y)/yInc - 8;
+
+ const std::vector<InputEvent> inputEventList = getApplication().getPlatform()->getSampleUserInput()->getInputEventList();
+ const std::vector<InputEventName> inputEventNameList = getApplication().getPlatform()->getSampleUserInput()->getInputEventNameList();
+
+ size_t maxHelpPage = inputEventList.size()/numIe;
+ if(maxHelpPage < mExtendedHelpPage)
+ mExtendedHelpPage = (PxU8) maxHelpPage;
+
+ PxU16 printed = 0;
+ PxU16 startPrint = 0;
+ for (size_t i = 0; i < inputEventList.size(); i++)
+ {
+ const InputEvent& ie = inputEventList[i];
+ const char* msg = mApplication.inputInfoMsg("Press "," to ", ie.m_Id, -1);
+ if(msg)
+ {
+ startPrint++;
+ if(startPrint <= numIe*mExtendedHelpPage)
+ continue;
+
+ strcpy(message,msg);
+ strcat(message, inputEventNameList[i].m_Name);
+ renderer->print(x, y, message, scale, shadowOffset, textColor);
+ y += yInc;
+
+ printed++;
+ if(printed >= numIe)
+ {
+ break;
+ }
+ }
+ }
+
+ if(printed == 0)
+ {
+ if(mExtendedHelpPage)
+ mExtendedHelpPage--;
+ }
+
+ y += yInc;
+ const char* msg = mApplication.inputInfoMsg("Press "," to show next/previous page", NEXT_PAGE, PREVIOUS_PAGE);
+ if(msg)
+ renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+RenderBaseActor* PhysXSample::createRenderBoxFromShape(PxRigidActor* actor, PxShape* shape, RenderMaterial* material, const PxReal* uvs)
+{
+ RenderBaseActor* shapeRenderActor = NULL;
+ Renderer* renderer = getRenderer();
+ PX_ASSERT(renderer);
+
+ PxGeometryType::Enum geomType = shape->getGeometryType();
+ PX_ASSERT(geomType==PxGeometryType::eBOX);
+ switch(geomType)
+ {
+ case PxGeometryType::eBOX:
+ {
+ // Get physics geometry
+ PxBoxGeometry geometry;
+ bool status = shape->getBoxGeometry(geometry);
+ PX_ASSERT(status);
+ PX_UNUSED(status);
+ // Create render object
+ shapeRenderActor = SAMPLE_NEW(RenderBoxActor)(*renderer, geometry.halfExtents, uvs);
+ }
+ break;
+ default: {}
+ };
+
+ if(shapeRenderActor)
+ {
+ link(shapeRenderActor, shape, actor);
+ mRenderActors.push_back(shapeRenderActor);
+ shapeRenderActor->setRenderMaterial(material);
+ shapeRenderActor->setEnableCameraCull(true);
+ }
+ return shapeRenderActor;
+}
+
+
+RenderBaseActor* PhysXSample::createRenderObjectFromShape(PxRigidActor* actor, PxShape* shape, RenderMaterial* material)
+{
+ PX_ASSERT(getRenderer());
+
+ RenderBaseActor* shapeRenderActor = NULL;
+ Renderer& renderer = *getRenderer();
+
+ PxGeometryHolder geom = shape->getGeometry();
+
+ switch(geom.getType())
+ {
+ case PxGeometryType::eSPHERE:
+ shapeRenderActor = SAMPLE_NEW(RenderSphereActor)(renderer, geom.sphere().radius);
+ break;
+ case PxGeometryType::ePLANE:
+ shapeRenderActor = SAMPLE_NEW(RenderGridActor)(renderer, 50, 1.f, PxShapeExt::getGlobalPose(*shape, *actor).q);
+ break;
+ case PxGeometryType::eCAPSULE:
+ shapeRenderActor = SAMPLE_NEW(RenderCapsuleActor)(renderer, geom.capsule().radius, geom.capsule().halfHeight);
+ break;
+ case PxGeometryType::eBOX:
+ shapeRenderActor = SAMPLE_NEW(RenderBoxActor)(renderer, geom.box().halfExtents);
+ break;
+ case PxGeometryType::eCONVEXMESH:
+ {
+ PxConvexMesh* convexMesh = geom.convexMesh().convexMesh;
+
+ // ### doesn't support scale
+ PxU32 nbVerts = convexMesh->getNbVertices();
+ PX_UNUSED(nbVerts);
+ const PxVec3* convexVerts = convexMesh->getVertices();
+ const PxU8* indexBuffer = convexMesh->getIndexBuffer();
+ PxU32 nbPolygons = convexMesh->getNbPolygons();
+
+ PxU32 totalNbTris = 0;
+ PxU32 totalNbVerts = 0;
+ for(PxU32 i=0;i<nbPolygons;i++)
+ {
+ PxHullPolygon data;
+ bool status = convexMesh->getPolygonData(i, data);
+ PX_ASSERT(status);
+ PX_UNUSED(status);
+ totalNbVerts += data.mNbVerts;
+ totalNbTris += data.mNbVerts - 2;
+ }
+
+ PxVec3Alloc* allocVerts = SAMPLE_NEW(PxVec3Alloc)[totalNbVerts];
+ PxVec3Alloc* allocNormals = SAMPLE_NEW(PxVec3Alloc)[totalNbVerts];
+ PxReal* UVs = (PxReal*)SAMPLE_ALLOC(sizeof(PxReal)*(totalNbVerts * 2));
+ PxU16* faces = (PxU16*)SAMPLE_ALLOC(sizeof(PxU16)*totalNbTris*3);
+
+ PxU16* triangles = faces;
+ PxVec3* vertices = allocVerts,
+ * normals = allocNormals;
+
+ PxU32 offset = 0;
+ for(PxU32 i=0;i<nbPolygons;i++)
+ {
+ PxHullPolygon face;
+ bool status = convexMesh->getPolygonData(i, face);
+ PX_ASSERT(status);
+ PX_UNUSED(status);
+
+ const PxU8* faceIndices = indexBuffer+face.mIndexBase;
+ for(PxU32 j=0;j<face.mNbVerts;j++)
+ {
+ vertices[offset+j] = convexVerts[faceIndices[j]];
+ normals[offset+j] = PxVec3(face.mPlane[0], face.mPlane[1], face.mPlane[2]);
+ }
+
+ for(PxU32 j=2;j<face.mNbVerts;j++)
+ {
+ *triangles++ = PxU16(offset);
+ *triangles++ = PxU16(offset+j);
+ *triangles++ = PxU16(offset+j-1);
+ }
+
+ offset += face.mNbVerts;
+ }
+
+ // prepare UVs for convex:
+ // filling like this
+ // vertice #0 - 0,0
+ // vertice #1 - 0,1
+ // vertice #2 - 1,0
+ // vertice #3 - 0,0
+ // ...
+ for(PxU32 i = 0; i < totalNbVerts; ++i)
+ {
+ PxU32 c = i % 3;
+ if(c == 0)
+ {
+ UVs[2 * i] = 0.0f;
+ UVs[2 * i + 1] = 0.0f;
+ }
+ else if(c == 1)
+ {
+ UVs[2 * i] = 0.0f;
+ UVs[2 * i + 1] = 1.0f;
+ }
+ else if(c == 2)
+ {
+ UVs[2 * i] = 1.0f;
+ UVs[2 * i + 1] = 0.0f;
+ }
+ }
+
+ PX_ASSERT(offset==totalNbVerts);
+ shapeRenderActor = SAMPLE_NEW(RenderMeshActor)(renderer, vertices, totalNbVerts, normals, UVs, faces, NULL, totalNbTris);
+ shapeRenderActor->setMeshScale(geom.convexMesh().scale);
+
+ SAMPLE_FREE(faces);
+ SAMPLE_FREE(UVs);
+ DELETEARRAY(allocVerts);
+ DELETEARRAY(allocNormals);
+ }
+ break;
+ case PxGeometryType::eTRIANGLEMESH:
+ {
+ // Get physics geometry
+ PxTriangleMesh* tm = geom.triangleMesh().triangleMesh;
+
+ const PxU32 nbVerts = tm->getNbVertices();
+ const PxVec3* verts = tm->getVertices();
+ const PxU32 nbTris = tm->getNbTriangles();
+ const void* tris = tm->getTriangles();
+ const bool has16bitIndices = tm->getTriangleMeshFlags() & PxTriangleMeshFlag::e16_BIT_INDICES ? true : false;
+ const PxU16* faces16 = has16bitIndices ? (const PxU16*)tris : NULL;
+ const PxU32* faces32 = has16bitIndices ? NULL : (const PxU32*)tris;
+ shapeRenderActor = SAMPLE_NEW(RenderMeshActor)(renderer, verts, nbVerts, NULL, NULL, faces16, faces32, nbTris, true);
+ shapeRenderActor->setMeshScale(geom.triangleMesh().scale);
+
+ if (!material)
+ material = mManagedMaterials[MATERIAL_FLAT];
+ }
+ break;
+ case PxGeometryType::eHEIGHTFIELD:
+ {
+ // Get physics geometry
+ const PxHeightFieldGeometry& geometry = geom.heightField();
+
+ const PxReal rs = geometry.rowScale;
+ const PxReal hs = geometry.heightScale;
+ const PxReal cs = geometry.columnScale;
+
+ // Create render object
+ PxHeightField* hf = geometry.heightField;
+ const PxU32 nbCols = hf->getNbColumns();
+ const PxU32 nbRows = hf->getNbRows();
+ const PxU32 nbVerts = nbRows * nbCols;
+ const PxU32 nbFaces = (nbCols - 1) * (nbRows - 1) * 2;
+
+ PxHeightFieldSample* sampleBuffer = new PxHeightFieldSample[nbVerts];
+ hf->saveCells(sampleBuffer, nbVerts * sizeof(PxHeightFieldSample));
+
+ PxVec3* vertexes = new PxVec3[nbVerts];
+ for(PxU32 i = 0; i < nbRows; i++)
+ {
+ for(PxU32 j = 0; j < nbCols; j++)
+ {
+ vertexes[i * nbCols + j] = PxVec3(PxReal(i) * rs, PxReal(sampleBuffer[j + (i*nbCols)].height) * hs, PxReal(j) * cs);
+ }
+ }
+
+ PxU32* indices = (PxU32*)SAMPLE_ALLOC(sizeof(PxU32) * nbFaces * 3);
+ for(PxU32 i = 0; i < (nbCols - 1); ++i)
+ {
+ for(PxU32 j = 0; j < (nbRows - 1); ++j)
+ {
+ PxU8 tessFlag = sampleBuffer[i+j*nbCols].tessFlag();
+ PxU32 i0 = j*nbCols + i;
+ PxU32 i1 = j*nbCols + i + 1;
+ PxU32 i2 = (j+1) * nbCols + i;
+ PxU32 i3 = (j+1) * nbCols + i+ 1;
+ // i2---i3
+ // | |
+ // | |
+ // i0---i1
+ // this is really a corner vertex index, not triangle index
+ PxU32 mat0 = hf->getTriangleMaterialIndex((j*nbCols+i)*2);
+ PxU32 mat1 = hf->getTriangleMaterialIndex((j*nbCols+i)*2+1);
+ bool hole0 = (mat0 == PxHeightFieldMaterial::eHOLE);
+ bool hole1 = (mat1 == PxHeightFieldMaterial::eHOLE);
+ // first triangle
+ indices[6 * (i * (nbRows - 1) + j) + 0] = hole0 ? i0 : i2; // duplicate i0 to make a hole
+ indices[6 * (i * (nbRows - 1) + j) + 1] = i0;
+ indices[6 * (i * (nbRows - 1) + j) + 2] = tessFlag ? i3 : i1;
+ // second triangle
+ indices[6 * (i * (nbRows - 1) + j) + 3] = hole1 ? i1 : i3; // duplicate i1 to make a hole
+ indices[6 * (i * (nbRows - 1) + j) + 4] = tessFlag ? i0 : i2;
+ indices[6 * (i * (nbRows - 1) + j) + 5] = i1;
+ }
+ }
+
+ PxU16* indices_16bit = (PxU16*)SAMPLE_ALLOC(sizeof(PxU16) * nbFaces * 3);
+ for(PxU32 i=0; i< nbFaces; i++)
+ {
+ indices_16bit[i*3+0] = indices[i*3+0];
+ indices_16bit[i*3+1] = indices[i*3+2];
+ indices_16bit[i*3+2] = indices[i*3+1];
+ }
+
+ shapeRenderActor = SAMPLE_NEW(RenderMeshActor)(renderer, vertexes, nbVerts, NULL, NULL, indices_16bit, NULL, nbFaces);
+ SAMPLE_FREE(indices_16bit);
+ SAMPLE_FREE(indices);
+ DELETEARRAY(sampleBuffer);
+ DELETEARRAY(vertexes);
+
+ if (!material)
+ material = mManagedMaterials[MATERIAL_FLAT];
+ }
+ break;
+ default: {}
+ };
+
+ if(shapeRenderActor)
+ {
+ link(shapeRenderActor, shape, actor);
+ mRenderActors.push_back(shapeRenderActor);
+ shapeRenderActor->setRenderMaterial(material);
+ shapeRenderActor->setEnableCameraCull(true);
+ }
+ return shapeRenderActor;
+}
+
+void PhysXSample::updateRenderObjectsFromRigidActor(PxRigidActor& actor, RenderMaterial* mat)
+{
+ PxU32 nbShapes = actor.getNbShapes();
+ if(nbShapes > 0)
+ {
+ const PxU32 nbShapesOnStack = 8;
+ PxShape* shapesOnStack[nbShapesOnStack], **shapes = &shapesOnStack[0];
+ if(nbShapes > nbShapesOnStack)
+ shapes = new PxShape*[nbShapes];
+ actor.getShapes(shapes, nbShapes);
+
+ for(PxU32 i = 0; i < nbShapes; ++i)
+ {
+ RenderBaseActor* renderActor = getRenderActor(&actor, shapes[i]);
+ if(renderActor != NULL)
+ {
+ renderActor->mActive = true;
+ if (mat != NULL)
+ renderActor->setRenderMaterial(mat);
+ }
+ else
+ createRenderObjectFromShape(&actor, shapes[i], mat);
+ }
+
+ if(nbShapes > nbShapesOnStack)
+ delete[] shapes;
+ }
+}
+
+void PhysXSample::createRenderObjectsFromScene()
+{
+ PxScene& scene = getActiveScene();
+
+ PxActorTypeFlags types = PxActorTypeFlag::eRIGID_STATIC | PxActorTypeFlag::eRIGID_DYNAMIC;
+
+#if PX_USE_PARTICLE_SYSTEM_API
+ types |= PxActorTypeFlag::ePARTICLE_SYSTEM | PxActorTypeFlag::ePARTICLE_FLUID;
+#endif
+
+#if PX_USE_CLOTH_API
+ types |= PxActorTypeFlag::eCLOTH;
+#endif
+
+ PxU32 nbActors = scene.getNbActors(types);
+ if(nbActors)
+ {
+ PxActor** actors = new PxActor* [nbActors];
+ scene.getActors(types, actors, nbActors);
+ for(PxU32 i = 0; i < nbActors; ++i)
+ {
+ switch (actors[i]->getType())
+ {
+ case PxActorType::eRIGID_STATIC:
+ case PxActorType::eRIGID_DYNAMIC:
+ updateRenderObjectsFromRigidActor(*reinterpret_cast<PxRigidActor*>(actors[i]));
+ break;
+#if PX_USE_PARTICLE_SYSTEM_API
+ case PxActorType::ePARTICLE_SYSTEM:
+ case PxActorType::ePARTICLE_FLUID:
+ // updateRenderObjectsFromRigidActor(*reinterpret_cast<PxRigidActor*>(actors[i]));
+ // break;
+#endif
+#if PX_USE_CLOTH_API
+ case PxActorType::eCLOTH:
+#endif
+ default:
+ break;
+ }
+ }
+ delete[] actors;
+ }
+
+ PxU32 nbArticulations = scene.getNbArticulations();
+ if(nbArticulations > 0)
+ {
+ PxArticulation** articulations = new PxArticulation* [nbArticulations];
+ scene.getArticulations(articulations, nbArticulations);
+ for(PxU32 i=0; i < nbArticulations; i++)
+ {
+ updateRenderObjectsFromArticulation(*articulations[i]);
+ }
+ delete[] articulations;
+ }
+}
+
+void PhysXSample::updateRenderObjectsFromArticulation(PxArticulation& articulation)
+{
+ SampleInlineArray<PxArticulationLink*,20> links;
+ links.resize(articulation.getNbLinks());
+ articulation.getLinks(links.begin(), links.size());
+
+ for(PxU32 i=0; i < links.size(); i++)
+ {
+ updateRenderObjectsFromRigidActor(*links[i]);
+ }
+}
+void PhysXSample::createRenderObjectsFromActor(PxRigidActor* rigidActor, RenderMaterial* material)
+{
+ PX_ASSERT(rigidActor);
+
+ PxU32 nbShapes = rigidActor->getNbShapes();
+ if(!nbShapes)
+ return;
+
+ PxShape** shapes = (PxShape**)SAMPLE_ALLOC(sizeof(PxShape*)*nbShapes);
+ PxU32 nb = rigidActor->getShapes(shapes, nbShapes);
+ PX_ASSERT(nb==nbShapes);
+ PX_UNUSED(nb);
+ for(PxU32 i=0;i<nbShapes;i++)
+ {
+ createRenderObjectFromShape(rigidActor, shapes[i], material);
+ }
+ SAMPLE_FREE(shapes);
+}
+
+void PhysXSample::updateRenderObjectsDebug(float dtime)
+{
+ RenderPhysX3Debug* debugRenderer = getDebugRenderer();
+ if(debugRenderer && mScene)
+ {
+ for(PxU32 i = 0; i < mRenderActors.size(); ++i)
+ {
+ if (mRenderActors[i]->getEnableDebugRender())
+ mRenderActors[i]->drawDebug(debugRenderer);
+ }
+ getCamera().drawDebug(debugRenderer);
+
+#ifdef VISUALIZE_PICKING_RAYS
+ if(mPicking)
+ {
+ const std::vector<Picking::Ray>& rays = mPicking->getRays();
+ PxU32 nbRays = rays.size();
+ const RendererColor color(255, 0, 0);
+ for(PxU32 i=0;i<nbRays;i++)
+ {
+ debugRenderer->addLine(rays[i].origin, rays[i].origin + rays[i].dir * 1000.0f, color);
+ }
+ }
+#endif
+#ifdef VISUALIZE_PICKING_TRIANGLES
+ if(mPicking && mPicking->pickedTriangleIsValid())
+ {
+ PxTriangle touchedTri = mPicking->getPickedTriangle();
+ RendererColor color(255, 255, 255);
+ debugRenderer->addLine(touchedTri.verts[0], touchedTri.verts[1], color);
+ debugRenderer->addLine(touchedTri.verts[1], touchedTri.verts[2], color);
+ debugRenderer->addLine(touchedTri.verts[2], touchedTri.verts[0], color);
+ for(PxU32 i=0;i<3;i++)
+ {
+ if(mPicking->pickedTriangleAdjacentIsValid(i))
+ {
+ touchedTri = mPicking->getPickedTriangleAdjacent(i);
+ if(i==0)
+ color = RendererColor(255, 0, 0);
+ else if(i==1)
+ color = RendererColor(0, 255, 0);
+ else if(i==2)
+ color = RendererColor(0, 0, 255);
+ debugRenderer->addLine(touchedTri.verts[0], touchedTri.verts[1], color);
+ debugRenderer->addLine(touchedTri.verts[1], touchedTri.verts[2], color);
+ debugRenderer->addLine(touchedTri.verts[2], touchedTri.verts[0], color);
+ }
+ }
+ }
+#endif
+ }
+}
+
+void PhysXSample::initRenderObjects()
+{
+ PxSceneWriteLock scopedLock(*mScene);
+ for (PxU32 i = 0; i < mRenderActors.size(); ++i)
+ {
+ mRenderActors[i]->update(0.0f);
+ }
+}
+
+void PhysXSample::updateRenderObjectsSync(float dtime)
+{
+ PxSceneWriteLock scopedLock(*mScene);
+#if PX_USE_CLOTH_API
+
+#if defined(RENDERER_ENABLE_CUDA_INTEROP)
+
+ // map interop resources
+ shdfnd::Array<RendererClothShape*> shapes;
+
+ if (mCudaContextManager)
+ {
+ for(PxU32 i = 0; i < mRenderClothActors.size(); ++i)
+ {
+ if (mRenderClothActors[i]->getCloth()->getClothFlags()&PxClothFlag::eGPU &&
+ mRenderClothActors[i]->getRenderClothShape()->isInteropEnabled())
+ {
+ shapes.pushBack(mRenderClothActors[i]->getRenderClothShape());
+ }
+ }
+
+ if (shapes.size())
+ {
+ mCudaContextManager->acquireContext();
+ RendererClothShape::mapShapes(&shapes[0], shapes.size());
+ }
+ }
+#endif // RENDERER_ENABLE_CUDA_INTEROP
+
+ // update shapes
+ for(PxU32 i = 0; i < mRenderClothActors.size(); ++i)
+ mRenderClothActors[i]->update(dtime);
+
+#if defined(RENDERER_ENABLE_CUDA_INTEROP)
+
+ // unmap interop resources
+ if (mCudaContextManager && shapes.size())
+ {
+ RendererClothShape::unmapShapes(&shapes[0], shapes.size());
+ mCudaContextManager->releaseContext();
+ }
+
+#endif // RENDERER_ENABLE_CUDA_INTEROP
+
+#endif // PX_USE_CLOTH_API
+
+#if PX_USE_PARTICLE_SYSTEM_API
+ for(PxU32 i = 0; i < mRenderParticleSystemActors.size(); ++i)
+ mRenderParticleSystemActors[i]->update(dtime);
+#endif // PX_USE_PARTICLE_SYSTEM_API
+}
+
+void PhysXSample::updateRenderObjectsAsync(float dtime)
+{
+ PX_PROFILE_ZONE("updateRenderObjectsAsync", 0);
+ if(mActiveTransformCount)
+ {
+ PxSceneWriteLock scopedLock(*mScene);
+ PxU32 nbActiveTransforms = mActiveTransformCount;
+ PxActiveTransform* currentTransform = mBufferedActiveTransforms;
+ while(nbActiveTransforms--)
+ {
+ const PxActiveTransform& activeTransform = *currentTransform++;
+ PxActor* actor = activeTransform.actor;
+
+ // Check that actor is not a deleted actor
+ bool isDeleted = false;
+ for (PxU32 i=0; i < mDeletedActors.size(); i++)
+ {
+ if (mDeletedActors[i] == actor)
+ {
+ isDeleted = true;
+ break;
+ }
+ }
+ if (isDeleted) continue;
+
+ const PxType actorType = actor->getConcreteType();
+ if(actorType==PxConcreteType::eRIGID_DYNAMIC || actorType==PxConcreteType::eRIGID_STATIC
+ || actorType == PxConcreteType::eARTICULATION_LINK || actorType == PxConcreteType::eARTICULATION_JOINT)
+ {
+ PxRigidActor* rigidActor = static_cast<PxRigidActor*>(actor);
+ PxU32 nbShapes = rigidActor->getNbShapes();
+ for(PxU32 i=0;i<nbShapes;i++)
+ {
+ PxShape* shape;
+ PxU32 n = rigidActor->getShapes(&shape, 1, i);
+ PX_ASSERT(n==1);
+ PX_UNUSED(n);
+ RenderBaseActor* renderActor = getRenderActor(rigidActor, shape);
+ if (NULL != renderActor)
+ renderActor->update(dtime);
+ }
+ }
+ }
+ mActiveTransformCount = 0;
+ mDeletedActors.clear();
+ }
+}
+
+void PhysXSample::bufferActiveTransforms()
+{
+ PxSceneReadLock scopedLock(*mScene);
+ // buffer active transforms to perform render object update parallel to simulation
+
+ const PxActiveTransform* activeTransforms = mScene->getActiveTransforms(mActiveTransformCount);
+ if(mActiveTransformCapacity < mActiveTransformCount)
+ {
+ SAMPLE_FREE(mBufferedActiveTransforms);
+ mActiveTransformCapacity = (PxU32)(mActiveTransformCount * 1.5f);
+ mBufferedActiveTransforms = (PxActiveTransform*)SAMPLE_ALLOC(sizeof(PxActiveTransform) * mActiveTransformCapacity);
+ }
+ if(mActiveTransformCount)
+ PxMemCopy(mBufferedActiveTransforms, activeTransforms, sizeof(PxActiveTransform) * mActiveTransformCount);
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+#if PX_USE_CLOTH_API
+
+PxCloth* PhysXSample::createClothFromMeshDesc(
+ const PxClothMeshDesc& meshDesc, const PxTransform& pose, const PxVec3& gravityDir, const PxVec2* uv, const char* textureFile, PxReal scale)
+{
+ PxClothFabric* clothFabric = PxClothFabricCreate(getPhysics(), meshDesc, gravityDir);
+ PX_ASSERT(meshDesc.points.stride == sizeof(PxVec4));
+
+ // create the cloth actor
+ const PxClothParticle* particles = (const PxClothParticle*)meshDesc.points.data;
+ PxCloth* cloth = getPhysics().createCloth( pose, *clothFabric, particles, PxClothFlags());
+ PX_ASSERT(cloth);
+
+ cloth->setSolverFrequency(60.0f); // don't know how to get target simulation frequency, just hardcode for now
+
+ // add this cloth into the scene
+ getActiveScene().addActor(*cloth);
+
+ // create render material
+ RenderMaterial* clothMaterial = createRenderMaterialFromTextureFile(textureFile);
+
+ // create the render object in sample framework
+ createRenderObjectsFromCloth(*cloth, meshDesc, clothMaterial, uv, true, scale);
+
+ return cloth;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// create cloth from obj file
+PxCloth* PhysXSample::createClothFromObj(
+ const char* objFileName, const PxTransform& pose, const char* textureFile)
+{
+ // create a mesh grid
+ SampleArray<PxVec4> vertices;
+ SampleArray<PxU32> primitives;
+ SampleArray<PxVec2> uvs;
+ PxClothMeshDesc meshDesc = Test::ClothHelpers::createMeshFromObj(objFileName, 1.0f,
+ PxQuat(PxIdentity), PxVec3(0.0f), vertices, primitives, uvs);
+
+ return createClothFromMeshDesc(meshDesc, pose, PxVec3(0,0,-1), uvs.begin(), textureFile);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// create cloth grid in XZ plane
+PxCloth* PhysXSample::createGridCloth(
+ PxReal sizeX, PxReal sizeZ, PxU32 numX, PxU32 numZ,
+ const PxTransform& pose, const char* textureFile)
+{
+ // create a mesh grid
+ SampleArray<PxVec4> vertices;
+ SampleArray<PxU32> primitives;
+ SampleArray<PxVec2> uvs;
+ PxClothMeshDesc meshDesc = Test::ClothHelpers::createMeshGrid(PxVec3(sizeX, 0, 0),
+ PxVec3(0, 0, sizeZ), numX, numZ, vertices, primitives, uvs);
+
+ return createClothFromMeshDesc(meshDesc, pose, PxVec3(0,0,-1), uvs.begin(), textureFile);
+}
+
+#endif // PX_USE_CLOTH_API
+
+///////////////////////////////////////////////////////////////////////////////
+RenderMaterial* PhysXSample::createRenderMaterialFromTextureFile(const char* filename)
+{
+ RenderMaterial* material = NULL;
+ if (!filename)
+ return NULL;
+
+ RAWTexture data;
+ data.mName = filename;
+ RenderTexture* texture = createRenderTextureFromRawTexture(data);
+ material = SAMPLE_NEW(RenderMaterial)(*getRenderer(), PxVec3(0.7f, 0.7f, 0.7f), 1.0f, true, MATERIAL_CLOTH, texture);
+ mRenderMaterials.push_back(material);
+
+ return material;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+#if PX_USE_CLOTH_API
+
+void PhysXSample::createRenderObjectsFromCloth(const PxCloth& cloth, const PxClothMeshDesc& meshDesc, RenderMaterial* material, const PxVec2* uv, bool enableDebugRender, PxReal scale)
+{
+ RenderClothActor* clothActor = SAMPLE_NEW (RenderClothActor)
+ (*getRenderer(), cloth, meshDesc,uv, scale );
+ if(!clothActor)
+ return;
+
+ if (material)
+ clothActor->setRenderMaterial(material);
+
+ mRenderClothActors.push_back(clothActor);
+ mRenderActors.push_back(clothActor);
+}
+
+void PhysXSample::removeRenderClothActor(RenderClothActor& renderActor)
+{
+ std::vector<RenderBaseActor*>::iterator baseActorIter = std::find(mRenderActors.begin(), mRenderActors.end(), (RenderBaseActor*)(&renderActor));
+ if(baseActorIter != mRenderActors.end())
+ mRenderActors.erase(baseActorIter);
+
+ std::vector<RenderClothActor*>::iterator clothActorIter = std::find(mRenderClothActors.begin(), mRenderClothActors.end(), &renderActor);
+ if(clothActorIter != mRenderClothActors.end())
+ mRenderClothActors.erase(clothActorIter);
+}
+
+#endif // PX_USE_CLOTH_API
+
+///////////////////////////////////////////////////////////////////////////////
+
+PxRigidActor* PhysXSample::createGrid(RenderMaterial* material)
+{
+ PxSceneWriteLock scopedLock(*mScene);
+ Renderer* renderer = getRenderer();
+ PX_ASSERT(renderer);
+
+ PxRigidStatic* plane = PxCreatePlane(*mPhysics, PxPlane(PxVec3(0,1,0), 0), *mMaterial);
+ if(!plane)
+ fatalError("create plane failed!");
+
+ mScene->addActor(*plane);
+
+ PxShape* shape;
+ plane->getShapes(&shape, 1);
+
+ RenderGridActor* actor = SAMPLE_NEW(RenderGridActor)(*renderer, 20, 10.0f);
+ link(actor, shape, plane);
+ actor->setTransform(PxTransform(PxIdentity));
+ mRenderActors.push_back(actor);
+ actor->setRenderMaterial(material);
+ return plane;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void PhysXSample::spawnDebugObject()
+{
+ PxSceneWriteLock scopedLock(*mScene);
+ PxU32 types = getDebugObjectTypes();
+
+ if (!types)
+ return;
+
+ //select legal type
+ while ((mDebugObjectType & types) == 0)
+ mDebugObjectType = (mDebugObjectType << 1) ? 0 : 1;
+
+ if ((mDebugObjectType & DEBUG_OBJECT_ALL) == 0)
+ return;
+
+ const PxVec3 pos = getCamera().getPos();
+ const PxVec3 vel = getCamera().getViewDir() * getDebugObjectsVelocity();
+
+ PxRigidDynamic* actor = NULL;
+
+ switch (mDebugObjectType)
+ {
+ case DEBUG_OBJECT_SPHERE:
+ actor = createSphere(pos, getDebugSphereObjectRadius(), &vel, mManagedMaterials[MATERIAL_GREEN], mDefaultDensity);
+ break;
+ case DEBUG_OBJECT_BOX:
+ actor = createBox(pos, getDebugBoxObjectExtents(), &vel, mManagedMaterials[MATERIAL_RED], mDefaultDensity);
+ break;
+ case DEBUG_OBJECT_CAPSULE:
+ actor = createCapsule(pos, getDebugCapsuleObjectRadius(), getDebugCapsuleObjectHalfHeight(), &vel, mManagedMaterials[MATERIAL_BLUE], mDefaultDensity);
+ break;
+ case DEBUG_OBJECT_CONVEX:
+ actor = createConvex(pos, &vel, mManagedMaterials[MATERIAL_YELLOW], mDefaultDensity);
+ break;
+ case DEBUG_OBJECT_COMPOUND:
+ actor = createTestCompound(pos, 320, 0.1f, 2.0f, &vel, NULL, mDefaultDensity, true);
+ break;
+ }
+
+ if (actor)
+ onDebugObjectCreation(actor);
+
+ //switch type
+ mDebugObjectType = mDebugObjectType << 1;
+ while ((mDebugObjectType & types) == 0)
+ mDebugObjectType = (mDebugObjectType << 1) ? 0 : 1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+PxRigidDynamic* PhysXSample::createBox(const PxVec3& pos, const PxVec3& dims, const PxVec3* linVel, RenderMaterial* material, PxReal density)
+{
+ PxSceneWriteLock scopedLock(*mScene);
+ PxRigidDynamic* box = PxCreateDynamic(*mPhysics, PxTransform(pos), PxBoxGeometry(dims), *mMaterial, density);
+ PX_ASSERT(box);
+
+ SetupDefaultRigidDynamic(*box);
+ mScene->addActor(*box);
+ addPhysicsActors(box);
+
+ if(linVel)
+ box->setLinearVelocity(*linVel);
+
+ createRenderObjectsFromActor(box, material);
+
+ return box;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+PxRigidDynamic* PhysXSample::createSphere(const PxVec3& pos, PxReal radius, const PxVec3* linVel, RenderMaterial* material, PxReal density)
+{
+ PxSceneWriteLock scopedLock(*mScene);
+ PxRigidDynamic* sphere = PxCreateDynamic(*mPhysics, PxTransform(pos), PxSphereGeometry(radius), *mMaterial, density);
+ PX_ASSERT(sphere);
+
+ SetupDefaultRigidDynamic(*sphere);
+ mScene->addActor(*sphere);
+ addPhysicsActors(sphere);
+
+ if(linVel)
+ sphere->setLinearVelocity(*linVel);
+
+ createRenderObjectsFromActor(sphere, material);
+
+ return sphere;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+PxRigidDynamic* PhysXSample::createCapsule(const PxVec3& pos, PxReal radius, PxReal halfHeight, const PxVec3* linVel, RenderMaterial* material, PxReal density)
+{
+ PxSceneWriteLock scopedLock(*mScene);
+ const PxQuat rot = PxQuat(PxIdentity);
+ PX_UNUSED(rot);
+
+ PxRigidDynamic* capsule = PxCreateDynamic(*mPhysics, PxTransform(pos), PxCapsuleGeometry(radius, halfHeight), *mMaterial, density);
+ PX_ASSERT(capsule);
+
+ SetupDefaultRigidDynamic(*capsule);
+ mScene->addActor(*capsule);
+ addPhysicsActors(capsule);
+
+ if(linVel)
+ capsule->setLinearVelocity(*linVel);
+
+ createRenderObjectsFromActor(capsule, material);
+
+ return capsule;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+PxRigidDynamic* PhysXSample::createConvex(const PxVec3& pos, const PxVec3* linVel, RenderMaterial* material, PxReal density)
+{
+ PxSceneWriteLock scopedLock(*mScene);
+ PxConvexMesh* convexMesh = GenerateConvex(*mPhysics, *mCooking, getDebugConvexObjectScale(), false, true);
+ PX_ASSERT(convexMesh);
+
+ PxRigidDynamic* convex = PxCreateDynamic(*mPhysics, PxTransform(pos), PxConvexMeshGeometry(convexMesh), *mMaterial, density);
+ PX_ASSERT(convex);
+
+ SetupDefaultRigidDynamic(*convex);
+ mScene->addActor(*convex);
+ addPhysicsActors(convex);
+
+ if(linVel)
+ convex->setLinearVelocity(*linVel);
+
+ createRenderObjectsFromActor(convex, material);
+
+ return convex;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+PxRigidDynamic* PhysXSample::createCompound(const PxVec3& pos, const std::vector<PxTransform>& localPoses, const std::vector<const PxGeometry*>& geometries, const PxVec3* linVel, RenderMaterial* material, PxReal density)
+{
+ PxSceneWriteLock scopedLock(*mScene);
+ PxRigidDynamic* compound = GenerateCompound(*mPhysics, mScene, mMaterial, pos, PxQuat(PxIdentity), localPoses, geometries, false, density);
+
+ addPhysicsActors(compound);
+ if(linVel)
+ compound->setLinearVelocity(*linVel);
+
+ createRenderObjectsFromActor(compound, material);
+
+ return compound;
+}
+
+PxRigidDynamic* PhysXSample::createTestCompound(const PxVec3& pos, PxU32 nbBoxes, float boxSize, float amplitude, const PxVec3* vel, RenderMaterial* material, PxReal density, bool makeSureVolumeEmpty)
+{
+ PxSceneWriteLock scopedLock(*mScene);
+ if (makeSureVolumeEmpty)
+ {
+ // Kai: a little bigger than amplitude + boxSize * sqrt(3)
+ PxSphereGeometry geometry(amplitude + boxSize + boxSize);
+ PxTransform pose(pos);
+ PxOverlapBuffer buf;
+ getActiveScene().overlap(geometry, pose, buf,
+ PxQueryFilterData(PxQueryFlag::eANY_HIT|PxQueryFlag::eSTATIC|PxQueryFlag::eDYNAMIC));
+ if (buf.hasBlock) {
+// shdfnd::printFormatted("desination volume is not empty!!!\n");
+ return NULL;
+ }
+ }
+
+ std::vector<PxTransform> localPoses;
+ std::vector<const PxGeometry*> geometries;
+
+ PxToolkit::BasicRandom rnd(42);
+
+ PxBoxGeometryAlloc* geoms = SAMPLE_NEW(PxBoxGeometryAlloc)[nbBoxes];
+
+ for(PxU32 i=0;i<nbBoxes;i++)
+ {
+ geoms[i].halfExtents = PxVec3(boxSize);
+
+ PxTransform localPose;
+ rnd.unitRandomPt(localPose.p);
+ localPose.p.normalize();
+ localPose.p *= amplitude;
+ rnd.unitRandomQuat(localPose.q);
+
+ localPoses.push_back(localPose);
+ geometries.push_back(&geoms[i]);
+ }
+ PxRigidDynamic* actor = createCompound(pos, localPoses, geometries, vel, material, density);
+ DELETEARRAY(geoms);
+ return actor;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+struct FindRenderActor
+{
+ FindRenderActor(PxShape* pxShape): mPxShape(pxShape) {}
+ bool operator() (const RenderBaseActor* actor) { return actor->getPhysicsShape() == mPxShape; }
+ PxShape* mPxShape;
+};
+
+void PhysXSample::removeRenderObject(RenderBaseActor* renderActor)
+{
+ std::vector<RenderBaseActor*>::iterator renderIter = std::find(mRenderActors.begin(), mRenderActors.end(), renderActor);
+ if(renderIter != mRenderActors.end())
+ {
+ // ######### PT: TODO: unlink call missing here!!!
+ mDeletedRenderActors.push_back((*renderIter));
+ mRenderActors.erase(renderIter);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+void PhysXSample::removeRenderActorsFromPhysicsActor(const PxRigidActor* actor)
+{
+ const PxU32 numShapes = actor->getNbShapes();
+ PxShape** shapes = (PxShape**)SAMPLE_ALLOC(sizeof(PxShape*)*numShapes);
+ actor->getShapes(shapes, numShapes);
+ for(PxU32 i = 0; i < numShapes; i++)
+ {
+ PxShape* shape = shapes[i];
+ FindRenderActor findRenderActor(shape);
+ std::vector<RenderBaseActor*>::iterator renderIter = std::find_if(mRenderActors.begin(), mRenderActors.end(), findRenderActor);
+ if(renderIter != mRenderActors.end())
+ {
+ unlink((*renderIter), shape, const_cast<PxRigidActor*>(actor));
+ mDeletedRenderActors.push_back((*renderIter));
+ mRenderActors.erase(renderIter);
+ }
+ }
+
+ // check if the actor is in the active transform list and remove
+ if(actor->getType() == PxActorType::eRIGID_DYNAMIC)
+ {
+ for(PxU32 i=0; i < mActiveTransformCount; i++)
+ {
+ if(mBufferedActiveTransforms[i].actor == actor)
+ {
+ mBufferedActiveTransforms[i] = mBufferedActiveTransforms[mActiveTransformCount-1];
+ mActiveTransformCount--;
+ break;
+ }
+ }
+ mDeletedActors.push_back(const_cast<PxRigidActor*>(actor));
+ }
+
+ SAMPLE_FREE(shapes);
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+void PhysXSample::removeActor(PxRigidActor* actor)
+{
+ removeRenderActorsFromPhysicsActor(actor);
+
+ std::vector<PxRigidActor*>::iterator actorIter = std::find(mPhysicsActors.begin(), mPhysicsActors.end(), actor);
+ if(actorIter != mPhysicsActors.end())
+ {
+ mPhysicsActors.erase(actorIter);
+ actor->release();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SampleFramework::SampleAsset* PhysXSample::getAsset(const char* relativePath, SampleFramework::SampleAsset::Type type, bool abortOnError)
+{
+ SampleFramework::SampleAsset* asset = mApplication.getAssetManager()->getAsset(relativePath, type);
+ if (NULL == asset && abortOnError)
+ {
+ std::string msg = "Error while getting material asset ";
+ msg += relativePath;
+ msg += "\n";
+ fatalError(msg.c_str());
+ }
+ return asset;
+}
+
+void PhysXSample::importRAWFile(const char* relativePath, PxReal scale, bool recook)
+{
+ mMeshTag = 0;
+ mFilename = relativePath;
+ mScale = scale;
+
+ const bool saved = gRecook;
+ if(!gRecook && recook)
+ gRecook = true;
+
+ bool status = loadRAWfile(getSampleMediaFilename(mFilename), *this, scale);
+ if (!status)
+ {
+ std::string msg = "Sample can not load file ";
+ msg += getSampleMediaFilename(mFilename);
+ msg += "\n";
+ fatalError(msg.c_str());
+ }
+
+ gRecook = saved;
+}
+
+#if PX_USE_PARTICLE_SYSTEM_API
+
+RenderParticleSystemActor* PhysXSample::createRenderObjectFromParticleSystem(ParticleSystem& ps, RenderMaterial* material, bool useMeshInstancing, bool useFading, PxReal fadingPeriod, PxReal instancingScale)
+{
+ RenderParticleSystemActor* renderActor = SAMPLE_NEW(RenderParticleSystemActor)(*getRenderer(), &ps, useMeshInstancing, useFading, fadingPeriod, instancingScale);
+ if(material) renderActor->setRenderMaterial(material);
+
+ mRenderActors.push_back(renderActor);
+ mRenderParticleSystemActors.push_back(renderActor);
+ return renderActor;
+}
+
+void PhysXSample::addRenderParticleSystemActor(RenderParticleSystemActor& renderActor)
+{
+ mRenderActors.push_back(&renderActor);
+ mRenderParticleSystemActors.push_back(&renderActor);
+}
+
+void PhysXSample::removeRenderParticleSystemActor(RenderParticleSystemActor& renderActor)
+{
+ std::vector<RenderBaseActor*>::iterator baseActorIter = std::find(mRenderActors.begin(), mRenderActors.end(), (RenderBaseActor*)(&renderActor));
+ if(baseActorIter != mRenderActors.end())
+ mRenderActors.erase(baseActorIter);
+
+ std::vector<RenderParticleSystemActor*>::iterator psActorIter = std::find(mRenderParticleSystemActors.begin(), mRenderParticleSystemActors.end(), &renderActor);
+ if(psActorIter != mRenderParticleSystemActors.end())
+ mRenderParticleSystemActors.erase(psActorIter);
+}
+
+void PhysXSample::project(const PxVec3& v, int& x, int& y, float& depth)
+{
+ mPicking->project(v, x, y, depth);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+#if PX_USE_CLOTH_API
+#endif // PX_USE_CLOTH_API
+
+
+#endif // PX_USE_PARTICLE_SYSTEM_API
+
diff --git a/PhysX_3.4/Samples/SampleBase/PhysXSample.h b/PhysX_3.4/Samples/SampleBase/PhysXSample.h
new file mode 100644
index 00000000..567b715f
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/PhysXSample.h
@@ -0,0 +1,364 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+
+#ifndef PHYSX_SAMPLE_H
+#define PHYSX_SAMPLE_H
+
+#include "PhysXSampleApplication.h"
+#include "SampleStepper.h"
+#include "SampleDirManager.h"
+#include "PxPhysicsAPI.h"
+#include "extensions/PxExtensionsAPI.h"
+#include "RenderParticleSystemActor.h"
+#include "RenderClothActor.h"
+
+namespace SampleFramework
+{
+ class SampleInputAsset;
+}
+
+namespace physx
+{
+ class Picking;
+}
+
+struct PhysXShape
+{
+ PxRigidActor* mActor;
+ PxShape* mShape;
+
+ PhysXShape(PxRigidActor* actor, PxShape* shape) : mActor(actor), mShape(shape) {}
+ PhysXShape(const PhysXShape& shape) : mActor(shape.mActor), mShape(shape.mShape) {}
+ bool operator<(const PhysXShape& shape) const { return mActor == shape.mActor ? mShape < shape.mShape : mActor < shape.mActor; }
+};
+
+enum StepperType
+{
+ DEFAULT_STEPPER,
+ FIXED_STEPPER,
+ VARIABLE_STEPPER
+};
+
+class PhysXSample : public RAWImportCallback
+ , public SampleAllocateable
+ , public PxDeletionListener
+{
+ typedef std::map<PhysXShape, RenderBaseActor*> PhysXShapeToRenderActorMap;
+
+public:
+ PhysXSample(PhysXSampleApplication& app, PxU32 maxSubSteps=8);
+ virtual ~PhysXSample();
+
+public:
+ void render();
+ void displayFPS();
+
+ SampleFramework::SampleAsset* getAsset(const char* relativePath, SampleFramework::SampleAsset::Type type, bool abortOnError = true);
+ void importRAWFile(const char* relativePath, PxReal scale, bool recook=false);
+ void removeActor(PxRigidActor* actor);
+ void removeRenderObject(RenderBaseActor *renderAcotr);
+#if PX_USE_CLOTH_API
+ void createRenderObjectsFromCloth(const PxCloth& cloth, const PxClothMeshDesc &meshDesc, RenderMaterial* material = NULL, const PxVec2* uvs = NULL, bool enableDebugRender = true, PxReal scale = 1.0f);
+ void removeRenderClothActor(RenderClothActor& renderActor);
+#endif
+ void createRenderObjectsFromActor(PxRigidActor* actor, RenderMaterial* material=NULL);
+ RenderBaseActor* createRenderBoxFromShape(PxRigidActor* actor, PxShape* shape, RenderMaterial* material=NULL, const PxReal* uvs=NULL);
+ RenderBaseActor* createRenderObjectFromShape(PxRigidActor* actor, PxShape* shape, RenderMaterial* material=NULL);
+ RenderMeshActor* createRenderMeshFromRawMesh(const RAWMesh& data, PxShape* shape = NULL);
+ RenderTexture* createRenderTextureFromRawTexture(const RAWTexture& data);
+ RenderMaterial* createRenderMaterialFromTextureFile(const char* filename);
+ PxCloth* createClothFromMeshDesc(const PxClothMeshDesc &meshDesc, const PxTransform &pose, const PxVec3& gravityDir = PxVec3(0,0,-1),
+ const PxVec2* uv = 0, const char *textureFile = 0, PxReal scale = 1.0f);
+ PxCloth* createClothFromObj(const char *objFileName, const PxTransform& pose, const char* textureFileName);
+ PxCloth* createGridCloth(PxReal sizeX, PxReal sizeY, PxU32 numX, PxU32 numY, const PxTransform &pose, const char* filename = NULL);
+ PxRigidActor* createGrid(RenderMaterial* material=NULL);
+ PxRigidDynamic* createBox(const PxVec3& pos, const PxVec3& dims, const PxVec3* linVel=NULL, RenderMaterial* material=NULL, PxReal density=1.0f);
+ PxRigidDynamic* createSphere(const PxVec3& pos, PxReal radius, const PxVec3* linVel=NULL, RenderMaterial* material=NULL, PxReal density=1.0f);
+ PxRigidDynamic* createCapsule(const PxVec3& pos, PxReal radius, PxReal halfHeight, const PxVec3* linVel=NULL, RenderMaterial* material=NULL, PxReal density=1.0f);
+ PxRigidDynamic* createConvex(const PxVec3& pos, const PxVec3* linVel=NULL, RenderMaterial* material=NULL, PxReal density=1.0f);
+ PxRigidDynamic* createCompound(const PxVec3& pos, const std::vector<PxTransform>& localPoses, const std::vector<const PxGeometry*>& geometries, const PxVec3* linVel=NULL, RenderMaterial* material=NULL, PxReal density=1.0f);
+ PxRigidDynamic* createTestCompound(const PxVec3& pos, PxU32 nbBoxes, float boxSize, float amplitude, const PxVec3* linVel, RenderMaterial* material, PxReal density, bool makeSureVolumeEmpty = false);
+#if PX_USE_PARTICLE_SYSTEM_API
+ RenderParticleSystemActor* createRenderObjectFromParticleSystem(ParticleSystem& ps, RenderMaterial* material = NULL,
+ bool useMeshInstancing = false, bool useFading = false, PxReal fadingPeriod = 1.0f, PxReal instancingScale = 1.0f);
+#endif
+ void createRenderObjectsFromScene();
+
+ void addRenderParticleSystemActor(RenderParticleSystemActor& renderActor);
+ void removeRenderParticleSystemActor(RenderParticleSystemActor& renderActor);
+
+ void setSubStepper(const PxReal stepSize, const PxU32 maxSteps) { getStepper()->setSubStepper(stepSize, maxSteps); }
+ void togglePause();
+ void toggleFlyCamera();
+ void initRenderObjects();
+
+ // project from world coords to screen coords (can be used for text rendering)
+ void project(const PxVec3& v, int& x, int& y, float& depth);
+
+public:
+ virtual void onInit();
+ virtual void onInit(bool restart) { onInit(); }
+ virtual void onShutdown();
+
+ // called after simulate() has completed
+ virtual void onSubstep(float dtime) {}
+
+ // called after simulate() has completed, but before fetchResult() is called
+ virtual void onSubstepPreFetchResult() {}
+
+ // called before simulate() is called
+ virtual void onSubstepSetup(float dtime, PxBaseTask* cont) {}
+ // called after simulate() has started
+ virtual void onSubstepStart(float dtime) {}
+
+ virtual void onTickPreRender(float dtime);
+ virtual void customizeRender() {}
+ virtual void helpRender(PxU32 x, PxU32 y, PxU8 textAlpha) {}
+ virtual void descriptionRender(PxU32 x, PxU32 y, PxU8 textAlpha) {}
+ virtual void onTickPostRender(float dtime);
+
+ virtual void onAnalogInputEvent(const SampleFramework::InputEvent& , float val);
+ virtual void onDigitalInputEvent(const SampleFramework::InputEvent& , bool val);
+ virtual void onPointerInputEvent(const SampleFramework::InputEvent& ie, PxU32 x, PxU32 y, PxReal dx, PxReal dy, bool val);
+
+ virtual void onKeyDownEx(SampleFramework::SampleUserInput::KeyCode keyCode, PxU32 param);
+
+ virtual void onResize(PxU32 width, PxU32 height);
+
+ virtual void newMaterial(const RAWMaterial&);
+ virtual void newMesh(const RAWMesh&);
+ virtual void newShape(const RAWShape&);
+ virtual void newHelper(const RAWHelper&);
+ virtual void newTexture(const RAWTexture&);
+ void unregisterInputEvents();
+ void registerInputEvents(bool ignoreSaved = false);
+ virtual void collectInputEvents(std::vector<const SampleFramework::InputEvent*>& inputEvents);
+ virtual SampleFramework::SampleDirManager& getSampleOutputDirManager();
+
+ // delete listener
+ virtual void onRelease(const PxBase* observed, void* userData, PxDeletionEventFlag::Enum deletionEvent);
+
+
+protected:
+ // Let samples override this
+ virtual void getDefaultSceneDesc(PxSceneDesc&) {}
+ virtual void customizeSceneDesc(PxSceneDesc&) {}
+ virtual void customizeTolerances(PxTolerancesScale&) {}
+ virtual void renderScene() {}
+ // this lets samples customize the debug objects
+ enum DebugObjectType
+ {
+ DEBUG_OBJECT_BOX = (1 << 0),
+ DEBUG_OBJECT_SPHERE = (1 << 1),
+ DEBUG_OBJECT_CAPSULE = (1 << 2),
+ DEBUG_OBJECT_CONVEX = (1 << 3),
+ DEBUG_OBJECT_COMPOUND = (1 << 4),
+ DEBUG_OBJECT_ALL = (DEBUG_OBJECT_BOX | DEBUG_OBJECT_SPHERE | DEBUG_OBJECT_CAPSULE | DEBUG_OBJECT_CONVEX | DEBUG_OBJECT_COMPOUND)
+ };
+ virtual PxU32 getDebugObjectTypes() const { return DEBUG_OBJECT_ALL; }
+ virtual PxReal getDebugObjectsVelocity() const { return 20.0f; }
+ virtual PxVec3 getDebugBoxObjectExtents() const { return PxVec3(0.3f, 0.3f, 1.0f); }
+ virtual PxReal getDebugSphereObjectRadius() const { return 0.3f; }
+ virtual PxReal getDebugCapsuleObjectRadius() const { return 0.3f; }
+ virtual PxReal getDebugCapsuleObjectHalfHeight() const { return 1.0f; }
+ virtual PxReal getDebugConvexObjectScale() const { return 0.3f; }
+ virtual void onDebugObjectCreation(PxRigidDynamic* actor){ }
+ Stepper* getStepper();
+
+ void prepareInputEventUserInputInfo(const char* sampleName,PxU32 &userInputCS, PxU32 &inputEventCS);
+
+private:
+ ///////////////////////////////////////////////////////////////////////////////
+
+ PhysXSample& operator= (const PhysXSample&);
+
+public: // Helpers from PhysXSampleApplication
+ PX_FORCE_INLINE void fatalError(const char* msg) { mApplication.fatalError(msg); }
+ PX_FORCE_INLINE void setCameraController(CameraController* c) { mApplication.setCameraController(c); }
+
+ PX_FORCE_INLINE void toggleVisualizationParam(PxScene& scene, PxVisualizationParameter::Enum param)
+ {
+ PxSceneWriteLock scopedLock(scene);
+ const bool visualization = scene.getVisualizationParameter(param) == 1.0f;
+ scene.setVisualizationParameter(param, visualization ? 0.0f : 1.0f);
+ mApplication.refreshVisualizationMenuState(param);
+ }
+
+public: // getter & setter
+ PX_FORCE_INLINE void setDefaultMaterial(PxMaterial* material) { mMaterial = material; }
+ PX_FORCE_INLINE void setFilename(const char* name) { mFilename = name; }
+
+ PX_FORCE_INLINE PhysXSampleApplication& getApplication() const { return mApplication; }
+ PX_FORCE_INLINE PxPhysics& getPhysics() const { return *mPhysics; }
+ PX_FORCE_INLINE PxCooking& getCooking() const { return *mCooking; }
+ PX_FORCE_INLINE PxScene& getActiveScene() const { return *mScene; }
+ PX_FORCE_INLINE PxMaterial& getDefaultMaterial() const { return *mMaterial; }
+ RenderMaterial* getMaterial(PxU32 materialID);
+
+ PX_FORCE_INLINE Camera& getCamera() const { return mApplication.getCamera(); }
+ PX_FORCE_INLINE SampleRenderer::Renderer* getRenderer() const { return mApplication.getRenderer(); }
+ PX_FORCE_INLINE RenderPhysX3Debug* getDebugRenderer() const { return mApplication.getDebugRenderer(); }
+ PX_FORCE_INLINE Console* getConsole() const { return mApplication.mConsole; }
+ PX_FORCE_INLINE CameraController* getCurrentCameraController() const { return mApplication.mCurrentCameraController; }
+ PX_FORCE_INLINE DefaultCameraController& getDefaultCameraController() const { return mCameraController; }
+ PX_FORCE_INLINE const PxMat44& getEyeTransform(void) const { return mApplication.m_worldToView.getInverseTransform();}
+ PX_FORCE_INLINE PxReal getSimulationTime() const { return mSimulationTime; }
+ PX_FORCE_INLINE PxReal getDebugRenderScale() const { return mDebugRenderScale; }
+
+ PX_FORCE_INLINE bool isPaused() const { return mApplication.isPaused(); }
+ PX_FORCE_INLINE bool isConnectedPvd() const { return mPvd ? mPvd->isConnected() : false; }
+#if PX_SUPPORT_GPU_PHYSX
+ PX_FORCE_INLINE bool isGpuSupported() const { return mCudaContextManager && mCudaContextManager->contextIsValid(); }
+#else
+ PX_FORCE_INLINE bool isGpuSupported() const { return false; }
+#endif
+ PX_FORCE_INLINE void setMenuExpandState(bool menuExpand) { mApplication.mMenuExpand = menuExpand; }
+ PX_FORCE_INLINE void setEyeTransform(const PxVec3& pos, const PxVec3& rot) {mApplication.setEyeTransform(pos, rot); }
+ PX_FORCE_INLINE void resetExtendedHelpText() { mExtendedHelpPage = 0; }
+ PX_FORCE_INLINE void addPhysicsActors(PxRigidActor* actor) { mPhysicsActors.push_back(actor); }
+ void unlink(RenderBaseActor* renderActor, PxShape* shape, PxRigidActor* actor);
+ void link(RenderBaseActor* renderActor, PxShape* shape, PxRigidActor* actor);
+ RenderBaseActor* getRenderActor(PxRigidActor* actor, PxShape* shape);
+ const char* getSampleOutputFilePath(const char* inFilePath, const char* outExtension);
+ void showExtendedInputEventHelp(PxU32 x, PxU32 y);
+
+ void freeDeletedActors();
+ PX_FORCE_INLINE StepperType getStepperType() const { return mStepperType; }
+
+protected:
+ void updateRenderObjectsFromRigidActor(PxRigidActor& actor, RenderMaterial* mat = NULL);
+ void updateRenderObjectsFromArticulation(PxArticulation& articulation);
+
+protected:
+ void togglePvdConnection();
+ void createPvdConnection();
+
+ void bufferActiveTransforms();
+ void updateRenderObjectsDebug(float dtime); // update of render actors debug draw information, will be called while the simulation is NOT running
+ void updateRenderObjectsSync(float dtime); // update of render objects while the simulation is NOT running (for particles, cloth etc. because data is not double buffered)
+ void updateRenderObjectsAsync(float dtime); // update of render objects, potentially while the simulation is running (for rigid bodies etc. because data is double buffered)
+
+ void saveUserInputs();
+ void saveInputEvents(const std::vector<const SampleFramework::InputEvent*>& );
+ void parseSampleOutputAsset(const char* sampleName, PxU32 , PxU32 );
+ void spawnDebugObject();
+ void removeRenderActorsFromPhysicsActor(const PxRigidActor* actor);
+
+protected: // configurations
+ bool mInitialDebugRender;
+ bool mCreateCudaCtxManager;
+ bool mCreateGroundPlane;
+ StepperType mStepperType;
+ PxU32 mMaxNumSubSteps;
+ PxU32 mNbThreads;
+ PxReal mDefaultDensity;
+
+protected: // control
+ bool mDisplayFPS;
+
+ bool& mPause;
+ bool& mOneFrameUpdate;
+ bool& mShowHelp;
+ bool& mShowDescription;
+ bool& mShowExtendedHelp;
+ bool mHideGraphics;
+ bool mEnableAutoFlyCamera;
+
+ DefaultCameraController& mCameraController;
+ DefaultCameraController mFlyCameraController;
+ PhysXSampleApplication::PvdParameters& mPvdParams;
+
+protected:
+ PhysXSampleApplication& mApplication;
+ PxFoundation* mFoundation;
+ PxPhysics* mPhysics;
+ PxCooking* mCooking;
+ PxScene* mScene;
+ PxMaterial* mMaterial;
+ PxDefaultCpuDispatcher* mCpuDispatcher;
+ physx::PxPvd* mPvd;
+ physx::PxPvdTransport* mTransport;
+ physx::PxPvdInstrumentationFlags mPvdFlags;
+
+#if PX_SUPPORT_GPU_PHYSX
+ PxCudaContextManager* mCudaContextManager;
+#endif
+
+ std::vector<PxRigidActor*> mPhysicsActors;
+ std::vector<RenderBaseActor*> mDeletedRenderActors;
+ std::vector<RenderBaseActor*> mRenderActors;
+ std::vector<RenderParticleSystemActor*> mRenderParticleSystemActors;
+ std::vector<RenderClothActor*> mRenderClothActors;
+
+
+ std::vector<RenderTexture*> mRenderTextures;
+ std::vector<SampleFramework::SampleAsset*> mManagedAssets;
+ std::vector<RenderMaterial*> mRenderMaterials;
+
+ RenderMaterial* (&mManagedMaterials)[MATERIAL_COUNT];
+
+ SampleFramework::SampleInputAsset* mSampleInputAsset;
+
+ PxActiveTransform* mBufferedActiveTransforms;
+ std::vector<PxActor*> mDeletedActors;
+ PxU32 mActiveTransformCount;
+ PxU32 mActiveTransformCapacity;
+ bool mIsFlyCamera;
+ PhysXShapeToRenderActorMap mPhysXShapeToRenderActorMap;
+
+private:
+ PxU32 mMeshTag;
+ const char* mFilename;
+ PxReal mScale;
+
+ PxReal mDebugRenderScale;
+protected:
+ bool mWaitForResults;
+private:
+ PxToolkit::FPS mFPS;
+
+ CameraController* mSavedCameraController;
+
+ DebugStepper mDebugStepper;
+ FixedStepper mFixedStepper;
+ VariableStepper mVariableStepper;
+ bool mWireFrame;
+
+ PxReal mSimulationTime;
+ Picking* mPicking;
+ bool mPicked;
+ physx::PxU8 mExtendedHelpPage;
+ physx::PxU32 mDebugObjectType;
+
+ static const PxU32 SCRATCH_BLOCK_SIZE = 1024*128;
+ void* mScratchBlock;
+};
+
+PxToolkit::BasicRandom& getSampleRandom();
+PxErrorCallback& getSampleErrorCallback();
+
+#endif // PHYSX_SAMPLE_H
diff --git a/PhysX_3.4/Samples/SampleBase/PhysXSampleApplication.cpp b/PhysX_3.4/Samples/SampleBase/PhysXSampleApplication.cpp
new file mode 100644
index 00000000..89088c55
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/PhysXSampleApplication.cpp
@@ -0,0 +1,1513 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "PhysXSampleApplication.h"
+
+#include "PxTkNamespaceMangle.h"
+#include "PxTkStream.h"
+
+#include "RendererMemoryMacros.h"
+#include "SampleUtils.h"
+#include "SampleStepper.h"
+#include "SampleActor.h"
+#include "SampleCommandLine.h"
+#include "SampleConsole.h"
+#include "SampleAllocator.h"
+#include "SampleAllocatorSDKClasses.h"
+
+#include "SamplePlatform.h"
+
+#include "Renderer.h"
+#include "RendererDirectionalLightDesc.h"
+
+#include "RenderBoxActor.h"
+#include "RenderSphereActor.h"
+#include "RenderCapsuleActor.h"
+#include "RenderMeshActor.h"
+#include "RenderGridActor.h"
+#include "RenderMaterial.h"
+#include "RenderTexture.h"
+#include "RenderPhysX3Debug.h"
+
+#include "PxPhysicsAPI.h"
+#include "extensions/PxExtensionsAPI.h"
+#include "PxTkFile.h"
+#include "task/PxTask.h"
+#include "PxToolkit.h"
+#include "extensions/PxDefaultSimulationFilterShader.h"
+#include "PxFiltering.h"
+
+#include "SampleBaseInputEventIds.h"
+
+#include <algorithm>
+#include "PxTkBmpLoader.h"
+#include <ctype.h>
+
+#include "PhysXSample.h"
+#include "TestGroup.h"
+
+#include <SampleUserInputIds.h>
+#include "SampleUserInputDefines.h"
+
+#include "InputEventBuffer.h"
+
+using namespace physx;
+using namespace SampleRenderer;
+using namespace SampleFramework;
+using namespace PxToolkit;
+
+#define SCREEN_WIDTH 800
+#define SCREEN_HEIGHT 600
+//#define SCREEN_WIDTH 1024
+//#define SCREEN_HEIGHT 768
+#define CAMERA_FOV 70.0f
+#define CAMERA_NEAR 0.1f
+#define CAMERA_FAR 10000.0f
+
+#if PX_PS4
+unsigned int sceLibcHeapExtendedAlloc = 1; /* Switch to dynamic allocation */
+size_t sceLibcHeapSize = SCE_LIBC_HEAP_SIZE_EXTENDED_ALLOC_NO_LIMIT; /* no upper limit for heap area */
+#endif
+
+#define SAMPLE_FRAMEWORK_MEDIA_DIR "media"
+
+static char gSampleMediaFolder[512];
+
+///////////////////////////////////////////////////////////////////////////////
+
+static PhysXSampleApplication* gBase = NULL;
+static void gNearPlane(Console* console, const char* text, void* userData)
+{
+ if(!text)
+ {
+ console->out("Usage: nearplane <float>");
+ return;
+ }
+
+ const float val = (float)::atof(text);
+ gBase->getCamera().setNearPlane(val);
+}
+
+static void gFarPlane(Console* console, const char* text, void* userData)
+{
+ if(!text)
+ {
+ console->out("Usage: farplane <float>");
+ return;
+ }
+
+ const float val = (float)::atof(text);
+ gBase->getCamera().setFarPlane(val);
+}
+
+static void gDrawCameraDebug(Console* console, const char* text, void* userData)
+{
+ gBase->getCamera().mDrawDebugData = !gBase->getCamera().mDrawDebugData;
+}
+
+static void gFreezeFrustum(Console* console, const char* text, void* userData)
+{
+ gBase->getCamera().mFreezeFrustum = !gBase->getCamera().mFreezeFrustum;
+}
+
+static void gVFC(Console* console, const char* text, void* userData)
+{
+ gBase->getCamera().mPerformVFC = !gBase->getCamera().mPerformVFC;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+PhysXSampleApplication::PhysXSampleApplication(const SampleCommandLine& cmdline) :
+ SampleApplication (cmdline, SAMPLE_FRAMEWORK_MEDIA_DIR),
+ mTextAlphaHelp (0.0f),
+ mTextAlphaDesc (0.0f),
+ mMenuType (MenuType::TESTS),
+ mMenuVisualizationsIndexSelected (0),
+ mIsCloseRequested (false),
+ mDebugRenderer (NULL),
+ mPause (false),
+ mOneFrameUpdate (false),
+ mSwitchSample (false),
+ mShowHelp (false),
+ mShowDescription (false),
+ mShowExtendedHelp (false),
+ mHideMouseCursor (false),
+ mDrawScreenQuad (true),
+ mMenuExpand (false),
+ mRunning (NULL),
+ mSelected (NULL),
+ mSample (NULL),
+ mDefaultSamplePath (NULL)
+{
+ mConsole = SAMPLE_NEW(Console)(getPlatform());
+ mInputEventBuffer = SAMPLE_NEW(InputEventBuffer)(*this);
+ if(mConsole)
+ {
+ gBase = this;
+ mConsole->addCmd("nearplane", gNearPlane);
+ mConsole->addCmd("farplane", gFarPlane);
+ mConsole->addCmd("drawcameradebug", gDrawCameraDebug);
+ mConsole->addCmd("freezefrustum", gFreezeFrustum);
+ mConsole->addCmd("vfc", gVFC);
+ }
+
+ mScreenQuadTopColor = RendererColor(0x00, 0x00, 0x80);
+ mScreenQuadBottomColor = RendererColor(0xff, 0xf0, 0xf0);
+
+ // Projection
+ mCamera.setFOV(CAMERA_FOV);
+ mCamera.setNearPlane(CAMERA_NEAR);
+ mCamera.setFarPlane(CAMERA_FAR);
+ mCamera.setScreenSize(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT);
+ // View
+ mCamera.setPos(PxVec3(0.0f, 10.0f, 0.0f));
+ mCameraController.init(PxVec3(0.0f, 10.0f, 0.0f), PxVec3(0.0f, 0.0f, 0.0f));
+ setDefaultCameraController();
+
+ // PT: search path for samples' media files
+ strcpy(gSampleMediaFolder, getAssetPathPrefix());
+ strcat(gSampleMediaFolder, SAMPLE_MEDIA_DIR);
+ addSearchPath(gSampleMediaFolder);
+
+ for (PxU32 i = 0; i < MATERIAL_COUNT; ++i)
+ mManagedMaterials[i] = NULL;
+
+ mMenuVisualizations.push_back(MenuTogglableItem(PxVisualizationParameter::eSCALE, "Debug Rendering"));
+
+ #define MENU_PUSHV(var, title) mMenuVisualizations.push_back( \
+ MenuTogglableItem(PxVisualizationParameter::var, title))
+
+ MENU_PUSHV(eCOLLISION_AABBS, "Collision AABBs" );
+ MENU_PUSHV(eCOLLISION_SHAPES, "Collision Shapes" );
+ MENU_PUSHV(eCOLLISION_AXES, "Collision Axes" );
+ MENU_PUSHV(eCOLLISION_FNORMALS, "Collision Face Normals" );
+ MENU_PUSHV(eCOLLISION_EDGES, "Collision Edges" );
+ MENU_PUSHV(eCONTACT_POINT, "Contact Points" );
+ MENU_PUSHV(eCONTACT_NORMAL, "Contact Normals" );
+ MENU_PUSHV(eCONTACT_ERROR, "Contact Error" );
+ MENU_PUSHV(eCONTACT_FORCE, "Contact Force" );
+ MENU_PUSHV(eACTOR_AXES, "Actor Axes" );
+ MENU_PUSHV(eBODY_AXES, "Body Axes" );
+ MENU_PUSHV(eBODY_LIN_VELOCITY, "Linear Velocity" );
+ MENU_PUSHV(eBODY_ANG_VELOCITY, "Angular Velocity" );
+ MENU_PUSHV(eBODY_MASS_AXES, "Mass Axes" );
+ MENU_PUSHV(eJOINT_LIMITS, "Joint Limits" );
+ MENU_PUSHV(eJOINT_LOCAL_FRAMES, "Joint Local Frames" );
+ MENU_PUSHV(ePARTICLE_SYSTEM_BROADPHASE_BOUNDS, "Particle System Broadphase Bounds");
+ MENU_PUSHV(ePARTICLE_SYSTEM_GRID, "Particle System Grid" );
+ MENU_PUSHV(ePARTICLE_SYSTEM_BOUNDS, "Particle System Bounds" );
+ MENU_PUSHV(ePARTICLE_SYSTEM_COLLISION_NORMAL, "Particle System Collision Normals");
+ MENU_PUSHV(eCULL_BOX, "Culling Box" );
+ //
+ MENU_PUSHV(eCOLLISION_STATIC, "Static pruning structure" );
+ MENU_PUSHV(eCOLLISION_DYNAMIC, "Dynamic pruning structure" );
+ MENU_PUSHV(eCOLLISION_COMPOUNDS, "Compounds" );
+ //
+ MENU_PUSHV(eCLOTH_VERTICAL, "Cloth Vertical Phases" );
+ MENU_PUSHV(eCLOTH_HORIZONTAL, "Cloth Horizontal Phases" );
+ MENU_PUSHV(eCLOTH_BENDING, "Cloth Bending Phases" );
+ MENU_PUSHV(eCLOTH_SHEARING, "Cloth Shearing Phases" );
+ MENU_PUSHV(eCLOTH_VIRTUAL_PARTICLES, "Cloth Virtual Particles" );
+
+ mSelected = getSampleTreeRoot().getFirstTest();
+
+ setPvdParams(cmdline);
+}
+
+PhysXSampleApplication::~PhysXSampleApplication()
+{
+ DELETESINGLE(mConsole);
+ DELETESINGLE(mInputEventBuffer);
+
+ PX_ASSERT(!mLights.size());
+}
+
+void PhysXSampleApplication::execute()
+{
+ if(isOpen())
+ onOpen();
+ while(!quitIsSignalled())
+ {
+ if(isOpen() && !isCloseRequested())
+ {
+ updateEngine();
+ }
+ else
+ break;
+#if defined(RENDERER_ANDROID)
+ if(!SamplePlatform::platform()->isOpen())
+ break;
+#endif
+ }
+
+ mInputMutex.lock();
+ if (isOpen() || isCloseRequested())
+ {
+ close();
+ }
+ mInputMutex.unlock();
+
+ quit();
+}
+
+void PhysXSampleApplication::updateEngine()
+{
+ if(mInputEventBuffer)
+ mInputEventBuffer->flush();
+ if(mSwitchSample)
+ switchSample();
+ onDraw();
+}
+
+const char* PhysXSampleApplication::inputInfoMsg(const char* firstPart,const char* secondPart, PxI32 inputEventId1, PxI32 inputEventId2)
+{
+ const char* keyNames1[5];
+
+ PxU32 inputMask = 0;
+ if(m_platform->getSampleUserInput()->gamepadSupported() && m_platform->getSampleUserInput()->keyboardSupported())
+ {
+ inputMask = KEYBOARD_INPUT | GAMEPAD_INPUT | TOUCH_PAD_INPUT | MOUSE_INPUT;
+ }
+ else
+ {
+ if(m_platform->getSampleUserInput()->gamepadSupported())
+ {
+ inputMask = GAMEPAD_INPUT | TOUCH_PAD_INPUT | MOUSE_INPUT;
+ }
+
+ if(m_platform->getSampleUserInput()->keyboardSupported())
+ {
+ inputMask = KEYBOARD_INPUT | TOUCH_PAD_INPUT | MOUSE_INPUT;
+ }
+ }
+
+ PxU16 numNames1 = getPlatform()->getSampleUserInput()->getUserInputKeys(inputEventId1,keyNames1,5,inputMask);
+
+ const char* keyNames2[5];
+ PxU16 numNames2 = getPlatform()->getSampleUserInput()->getUserInputKeys(inputEventId2,keyNames2,5,inputMask);
+
+ if(!numNames1 && !numNames2)
+ return NULL;
+
+ strcpy(m_Msg, firstPart);
+ if(numNames1 && numNames2)
+ {
+ for (PxU16 i = 0; i < numNames1; i++)
+ {
+ strcat(m_Msg, keyNames1[i]);
+ strcat(m_Msg, " or ");
+ }
+
+ for (PxU16 i = 0; i < numNames2; i++)
+ {
+ strcat(m_Msg, keyNames2[i]);
+ if(i != numNames2 - 1)
+ strcat(m_Msg, " or ");
+ }
+ }
+ else
+ {
+ if(numNames1)
+ {
+ for (PxU16 i = 0; i < numNames1; i++)
+ {
+ strcat(m_Msg, keyNames1[i]);
+ if(i != numNames1 - 1)
+ strcat(m_Msg, " or ");
+ }
+ }
+ else
+ {
+ for (PxU16 i = 0; i < numNames2; i++)
+ {
+ strcat(m_Msg, keyNames2[i]);
+ if(i != numNames2 - 1)
+ strcat(m_Msg, " or ");
+ }
+ }
+ }
+
+ strcat(m_Msg, secondPart);
+ return m_Msg;
+}
+
+const char* PhysXSampleApplication::inputInfoMsg_Aor_BandC(const char* firstPart,const char* secondPart, PxI32 inputEventIdA, PxI32 inputEventIdB, PxI32 inputEventIdC)
+{
+ PxU32 inputMask = TOUCH_PAD_INPUT | MOUSE_INPUT;
+ if(m_platform->getSampleUserInput()->gamepadSupported())
+ inputMask |= GAMEPAD_INPUT;
+ if(m_platform->getSampleUserInput()->keyboardSupported())
+ inputMask |= KEYBOARD_INPUT;
+
+ const char* keyNamesA[5];
+ PxU16 numNamesA = getPlatform()->getSampleUserInput()->getUserInputKeys(inputEventIdA,keyNamesA,5,inputMask);
+
+ const char* keyNamesB[5];
+ PxU16 numNamesB = getPlatform()->getSampleUserInput()->getUserInputKeys(inputEventIdB,keyNamesB,5,inputMask);
+
+ const char* keyNamesC[5];
+ PxU16 numNamesC = getPlatform()->getSampleUserInput()->getUserInputKeys(inputEventIdC,keyNamesC,5,inputMask);
+
+ PX_ASSERT((numNamesB!=0) == (numNamesC!=0));
+
+ strcpy(m_Msg, firstPart);
+ {
+
+ for (PxU16 i = 0; i < numNamesA; i++)
+ {
+ strcat(m_Msg, keyNamesA[i]);
+ if(i != numNamesA - 1)
+ strcat(m_Msg, " or ");
+ }
+
+ if(numNamesB && numNamesC)
+ {
+ if(numNamesA)
+ strcat(m_Msg, " or (");
+
+ for (PxU16 i = 0; i < numNamesB; i++)
+ {
+ strcat(m_Msg, keyNamesB[i]);
+ if(i != numNamesB - 1)
+ strcat(m_Msg, " or ");
+ }
+
+ strcat(m_Msg, " and ");
+
+ for (PxU16 i = 0; i < numNamesC; i++)
+ {
+ strcat(m_Msg, keyNamesC[i]);
+ if(i != numNamesC - 1)
+ strcat(m_Msg, " or ");
+ }
+ if(numNamesA)
+ strcat(m_Msg, ")");
+ }
+ }
+
+ strcat(m_Msg, secondPart);
+ return m_Msg;
+}
+
+
+const char* PhysXSampleApplication::inputMoveInfoMsg(const char* firstPart,const char* secondPart, PxI32 inputEventId1, PxI32 inputEventId2,PxI32 inputEventId3,PxI32 inputEventId4)
+{
+ const char* keyNames1[5];
+ const char* keyNames2[5];
+ const char* keyNames3[5];
+ const char* keyNames4[5];
+
+ PxU32 inputMask = 0;
+ if(m_platform->getSampleUserInput()->gamepadSupported() && m_platform->getSampleUserInput()->keyboardSupported())
+ {
+ inputMask = KEYBOARD_INPUT | GAMEPAD_INPUT | TOUCH_PAD_INPUT | MOUSE_INPUT;
+ }
+ else
+ {
+ if(m_platform->getSampleUserInput()->gamepadSupported())
+ {
+ inputMask = GAMEPAD_INPUT | TOUCH_PAD_INPUT | MOUSE_INPUT;
+ }
+
+ if(m_platform->getSampleUserInput()->keyboardSupported())
+ {
+ inputMask = KEYBOARD_INPUT | TOUCH_PAD_INPUT | MOUSE_INPUT;
+ }
+ }
+
+ PxU16 numNames1 = getPlatform()->getSampleUserInput()->getUserInputKeys(inputEventId1,keyNames1,5,inputMask);
+ PxU16 numNames2 = getPlatform()->getSampleUserInput()->getUserInputKeys(inputEventId2,keyNames2,5,inputMask);
+ PxU16 numNames3 = getPlatform()->getSampleUserInput()->getUserInputKeys(inputEventId3,keyNames3,5,inputMask);
+ PxU16 numNames4 = getPlatform()->getSampleUserInput()->getUserInputKeys(inputEventId4,keyNames4,5,inputMask);
+
+
+ if(!numNames1 && !numNames2 && !numNames3 && !numNames4)
+ return NULL;
+
+ bool firstVal = true;
+
+ strcpy(m_Msg, firstPart);
+ if(numNames1)
+ {
+ for (PxU16 i = 0 ; i < numNames1; i++)
+ {
+ if(!firstVal)
+ {
+ strcat(m_Msg, ",");
+ }
+
+ firstVal = false;
+ strcat(m_Msg, keyNames1[i]);
+ }
+ }
+ if(numNames2)
+ {
+ for (PxU16 i = 0 ; i < numNames2; i++)
+ {
+ if(!firstVal)
+ {
+ strcat(m_Msg, ",");
+ }
+
+ firstVal = false;
+ strcat(m_Msg, keyNames2[i]);
+ }
+ }
+ if(numNames3)
+ {
+ for (PxU16 i = 0 ; i < numNames3; i++)
+ {
+ if(!firstVal)
+ {
+ strcat(m_Msg, ",");
+ }
+
+ firstVal = false;
+ strcat(m_Msg, keyNames3[i]);
+ }
+ }
+ if(numNames4)
+ {
+ for (PxU16 i = 0 ; i < numNames4; i++)
+ {
+ if(!firstVal)
+ {
+ strcat(m_Msg, ",");
+ }
+
+ firstVal = false;
+ strcat(m_Msg, keyNames4[i]);
+ }
+ }
+
+ strcat(m_Msg, secondPart);
+ return m_Msg;
+}
+
+void PhysXSampleApplication::collectInputEvents(std::vector<const InputEvent*>& inputEvents)
+{
+ //digital keyboard events
+ DIGITAL_INPUT_EVENT_DEF(MENU_SAMPLES, WKEY_RETURN, XKEY_RETURN, X1KEY_RETURN, PS3KEY_RETURN, PS4KEY_RETURN, AKEY_UNKNOWN, OSXKEY_RETURN, IKEY_UNKNOWN, LINUXKEY_RETURN, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(MENU_QUICK_UP, WKEY_UP, XKEY_UP, X1KEY_UP, PS3KEY_UP, PS4KEY_UP, AKEY_UNKNOWN, OSXKEY_UP, IKEY_UNKNOWN, LINUXKEY_UP, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(MENU_QUICK_DOWN, WKEY_DOWN, XKEY_DOWN, X1KEY_DOWN, PS3KEY_DOWN, PS4KEY_DOWN, AKEY_UNKNOWN, OSXKEY_DOWN, IKEY_UNKNOWN, LINUXKEY_DOWN, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(MENU_QUICK_LEFT, WKEY_LEFT, XKEY_LEFT, X1KEY_LEFT, PS3KEY_LEFT, PS4KEY_LEFT, AKEY_UNKNOWN, OSXKEY_LEFT, IKEY_UNKNOWN, LINUXKEY_LEFT, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(MENU_QUICK_RIGHT, WKEY_RIGHT, XKEY_RIGHT, X1KEY_RIGHT, PS3KEY_RIGHT, PS4KEY_RIGHT, AKEY_UNKNOWN, OSXKEY_RIGHT, IKEY_UNKNOWN, LINUXKEY_RIGHT, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(MENU_SELECT, WKEY_RETURN, XKEY_RETURN, X1KEY_RETURN, PS3KEY_RETURN, PS4KEY_RETURN, AKEY_UNKNOWN, OSXKEY_RETURN, IKEY_UNKNOWN, LINUXKEY_RETURN, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(MENU_ESCAPE, WKEY_ESCAPE, XKEY_ESCAPE, X1KEY_ESCAPE, PS3KEY_ESCAPE, PS4KEY_ESCAPE, AKEY_UNKNOWN, OSXKEY_ESCAPE, IKEY_UNKNOWN, LINUXKEY_ESCAPE, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(QUIT, WKEY_ESCAPE, XKEY_ESCAPE, X1KEY_ESCAPE, PS3KEY_ESCAPE, PS4KEY_ESCAPE, AKEY_UNKNOWN, OSXKEY_ESCAPE, IKEY_UNKNOWN, LINUXKEY_ESCAPE, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(SHOW_EXTENDED_HELP, WKEY_F1, XKEY_F1, X1KEY_F1, PS3KEY_F1, PS4KEY_F1, AKEY_UNKNOWN, OSXKEY_F1, IKEY_UNKNOWN, LINUXKEY_F1, WIIUKEY_UNKNOWN);
+#if PX_SUPPORT_GPU_PHYSX || PX_XBOXONE
+ DIGITAL_INPUT_EVENT_DEF(TOGGLE_CPU_GPU, WKEY_F2, XKEY_UNKNOWN, X1KEY_F2, PS3KEY_UNKNOWN, PS4KEY_UNKNOWN, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, WIIUKEY_UNKNOWN);
+#endif
+ DIGITAL_INPUT_EVENT_DEF(MENU_VISUALIZATIONS, WKEY_F3, XKEY_F3, X1KEY_F3, PS3KEY_F3, PS4KEY_F3, AKEY_UNKNOWN, OSXKEY_F3, IKEY_UNKNOWN, LINUXKEY_F3, WIIUKEY_UNKNOWN);
+
+ //digital mouse events
+ DIGITAL_INPUT_EVENT_DEF(CAMERA_MOVE_BUTTON, MOUSE_BUTTON_LEFT, XKEY_UNKNOWN, X1KEY_UNKNOWN, PS3KEY_UNKNOWN, PS4KEY_UNKNOWN, AKEY_UNKNOWN, MOUSE_BUTTON_LEFT, IKEY_UNKNOWN, MOUSE_BUTTON_LEFT, WIIUKEY_UNKNOWN);
+
+ //digital gamepad events
+ DIGITAL_INPUT_EVENT_DEF(MENU_SAMPLES, GAMEPAD_START, GAMEPAD_START, GAMEPAD_START, GAMEPAD_START, GAMEPAD_START, AKEY_UNKNOWN, GAMEPAD_START, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_START);
+ DIGITAL_INPUT_EVENT_DEF(MENU_UP, GAMEPAD_DIGI_UP, GAMEPAD_DIGI_UP, GAMEPAD_DIGI_UP, GAMEPAD_DIGI_UP, GAMEPAD_DIGI_UP, AKEY_UNKNOWN, GAMEPAD_DIGI_UP, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_DIGI_UP);
+ DIGITAL_INPUT_EVENT_DEF(MENU_DOWN, GAMEPAD_DIGI_DOWN, GAMEPAD_DIGI_DOWN, GAMEPAD_DIGI_DOWN, GAMEPAD_DIGI_DOWN, GAMEPAD_DIGI_DOWN, AKEY_UNKNOWN, GAMEPAD_DIGI_DOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_DIGI_DOWN);
+ DIGITAL_INPUT_EVENT_DEF(MENU_LEFT, GAMEPAD_DIGI_LEFT, GAMEPAD_DIGI_LEFT, GAMEPAD_DIGI_LEFT, GAMEPAD_DIGI_LEFT, GAMEPAD_DIGI_LEFT, AKEY_UNKNOWN, GAMEPAD_DIGI_LEFT, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_DIGI_LEFT);
+ DIGITAL_INPUT_EVENT_DEF(MENU_RIGHT, GAMEPAD_DIGI_RIGHT, GAMEPAD_DIGI_RIGHT, GAMEPAD_DIGI_RIGHT, GAMEPAD_DIGI_RIGHT, GAMEPAD_DIGI_RIGHT, AKEY_UNKNOWN, GAMEPAD_DIGI_RIGHT, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_DIGI_RIGHT);
+ DIGITAL_INPUT_EVENT_DEF(MENU_SELECT, GAMEPAD_SOUTH, GAMEPAD_SOUTH, GAMEPAD_SOUTH, GAMEPAD_SOUTH, GAMEPAD_SOUTH, AKEY_UNKNOWN, GAMEPAD_SOUTH, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_SOUTH);
+ DIGITAL_INPUT_EVENT_DEF(MENU_ESCAPE, GAMEPAD_EAST, GAMEPAD_EAST, GAMEPAD_EAST, GAMEPAD_EAST, GAMEPAD_EAST, AKEY_UNKNOWN, GAMEPAD_EAST, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_EAST);
+
+ //analog mouse events
+ ANALOG_INPUT_EVENT_DEF(CAMERA_MOUSE_LOOK,GAMEPAD_DEFAULT_SENSITIVITY, MOUSE_MOVE, XKEY_UNKNOWN, X1KEY_UNKNOWN, PS3KEY_UNKNOWN, PS4KEY_UNKNOWN, AKEY_UNKNOWN, MOUSE_MOVE, IKEY_UNKNOWN, MOUSE_MOVE, WIIUKEY_UNKNOWN);
+
+ // touchscreen events for sampleall
+ if(mRunning->getParent()->numChildren() > 1)
+ {
+ TOUCH_INPUT_EVENT_DEF(RUN_NEXT_SAMPLE, ">>", ASELECTOR_BUTTON2, ISELECTOR_BUTTON2);
+ TOUCH_INPUT_EVENT_DEF(RUN_PREVIOUS_SAMPLE, "<<", ASELECTOR_BUTTON1, ISELECTOR_BUTTON1);
+ }
+
+ if(mCurrentCameraController)
+ {
+ mCurrentCameraController->collectInputEvents(inputEvents);
+ }
+
+ if(mConsole)
+ {
+ mConsole->collectInputEvents(inputEvents);
+ }
+
+ if(mSample)
+ {
+ mSample->collectInputEvents(inputEvents);
+ }
+}
+
+void PhysXSampleApplication::refreshVisualizationMenuState(PxVisualizationParameter::Enum p)
+{
+ PxScene& scene = mSample->getActiveScene();
+
+ for(PxU32 i=0; i < mMenuVisualizations.size(); i++)
+ {
+ if(mMenuVisualizations[i].toggleCommand == (PxU32)p)
+ {
+ mMenuVisualizations[i].toggleState = !!scene.getVisualizationParameter(p);
+ break;
+ }
+ }
+}
+
+void PhysXSampleApplication::applyDefaultVisualizationSettings()
+{
+ PxScene& scene = mSample->getActiveScene();
+ PxReal debugRenderScale = mSample->getDebugRenderScale();
+
+ for(PxU32 i=0; i < mMenuVisualizations.size(); i++)
+ {
+ bool enabled = mMenuVisualizations[i].toggleState;
+
+ PxVisualizationParameter::Enum p = static_cast<PxVisualizationParameter::Enum>(mMenuVisualizations[i].toggleCommand);
+
+ if (p != PxVisualizationParameter::eSCALE)
+ scene.setVisualizationParameter(p, enabled ? 1.0f : 0.0f);
+ else
+ scene.setVisualizationParameter(p, enabled ? debugRenderScale: 0.0f);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void PhysXSampleApplication::customizeSample(SampleSetup& setup)
+{
+ setup.mName = "PhysXSampleApplication";
+ setup.mWidth = SCREEN_WIDTH;
+ setup.mHeight = SCREEN_HEIGHT;
+ setup.mFullscreen = false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool PhysXSampleApplication::initLogo()
+{
+/* RAWTexture data;
+ data.mName = "physx_logo.bmp";
+ RenderTexture* logoTexture = createRenderTextureFromRawTexture(data);
+
+ mRockMaterial = SAMPLE_NEW(RenderMaterial)(*getRenderer(), PxVec3(1.0f, 1.0f, 1.0f), 1.0f, false, 0xffffffff, rockTexture);
+ mRenderMaterials.push_back(mRockMaterial);
+*/
+ return true;
+}
+
+float PhysXSampleApplication::tweakElapsedTime(float dtime)
+{
+ if(dtime>1.0f)
+ dtime = 1.0f/60.0f;
+
+ if(mOneFrameUpdate)
+ {
+ mPause = false;
+ dtime = 1.0f/60.0f;
+ }
+
+/* if(mOneFrameUpdate)
+ mPause = false;
+
+ if(mPause)
+ return 0.0f;*/
+
+ return dtime;
+}
+
+void PhysXSampleApplication::baseResize(PxU32 width, PxU32 height)
+{
+// shdfnd::printFormatted("Resize: %d | %d\n", width, height);
+
+ SampleApplication::onResize(width, height);
+
+ updateCameraViewport(width, height);
+}
+
+void PhysXSampleApplication::updateCameraViewport(PxU32 clientWidth, PxU32 clientHeight)
+{
+// PxU32 clientWidth, clientHeight;
+// renderer->getWindowSize(clientWidth, clientHeight);
+
+#if defined(RENDERER_WINDOWS)
+ PxU32 width, height;
+ m_platform->getWindowSize(width, height);
+// const PxReal ratio = PxReal(width) / PxReal(height);
+// const PxReal ratio2 = PxReal(Rect.right - Rect.left) / PxReal(Rect.bottom - Rect.top);
+ mCamera.setScreenSize(clientWidth, clientHeight, width, height);
+#else
+ mCamera.setScreenSize(clientWidth, clientHeight, clientWidth, clientHeight);
+#endif
+}
+
+void PhysXSampleApplication::setPvdParams(const SampleCommandLine& cmdLine)
+{
+ if (cmdLine.hasSwitch("nonVizPvd"))
+ {
+ mPvdParams.useFullPvdConnection = false;
+ }
+
+ if (cmdLine.hasSwitch("pvdhost"))
+ {
+ const char* ipStr = cmdLine.getValue("pvdhost");
+ if (ipStr)
+ Ps::strlcpy(mPvdParams.ip, 256, ipStr);
+ }
+
+ if (cmdLine.hasSwitch("pvdport"))
+ {
+ const char* portStr = cmdLine.getValue("pvdport");
+ if (portStr)
+ mPvdParams.port = atoi(portStr);
+ }
+
+ if (cmdLine.hasSwitch("pvdtimeout"))
+ {
+ const char* timeoutStr = cmdLine.getValue("pvdtimeout");
+ if (timeoutStr)
+ mPvdParams.timeout = atoi(timeoutStr);
+ }
+}
+
+void PhysXSampleApplication::onRender()
+{
+ Renderer* renderer = getRenderer();
+ if(renderer)
+ {
+ mCamera.BuildFrustum();
+#if 0
+ PxScene* mScene = &mSample->getActiveScene();
+ if(mScene)
+ {
+ const PxVec3* frustumVerts = mCamera.getFrustumVerts();
+ PxBounds3 cameraBounds(frustumVerts[0], frustumVerts[0]);
+ for(PxU32 i=0;i<8;i++)
+ cameraBounds.include(frustumVerts[i]);
+ mScene->setVisualizationCullingBox(cameraBounds);
+ mScene->setVisualizationParameter(PxVisualizationParameter::eCULL_BOX, 1.0f);
+ }
+#endif
+ renderer->clearBuffers();
+
+ if(mDrawScreenQuad)
+ {
+ ScreenQuad sq;
+ sq.mLeftUpColor = mScreenQuadTopColor;
+ sq.mRightUpColor = mScreenQuadTopColor;
+ sq.mLeftDownColor = mScreenQuadBottomColor;
+ sq.mRightDownColor = mScreenQuadBottomColor;
+
+ renderer->drawScreenQuad(sq);
+ }
+
+ for(PxU32 i=0; i<mLights.size(); i++)
+ {
+ renderer->queueLightForRender(*mLights[i]);
+ }
+
+ {
+ PxVec3 camPos( mCamera.getPos() );
+ PxVec3 camDir = mCamera.getViewDir();
+ PxVec3 camUp = PxVec3( 0, 1, 0 );
+ PxVec3 camTarget = camPos + camDir * 50.0f;
+ PxPvdSceneClient* pvdClient = mSample->getActiveScene().getScenePvdClient();
+ if(pvdClient)
+ pvdClient->updateCamera( "SampleCamera", camPos, camUp, camTarget );
+ }
+ // main scene render
+ {
+ mSample->render();
+ renderer->render(mCamera.getViewMatrix(), mCamera.getProjMatrix());
+ }
+
+ // render debug lines and points with a small depth bias to avoid z-fighting
+ {
+ mSample->getDebugRenderer()->queueForRenderLine();
+ mSample->getDebugRenderer()->queueForRenderPoint();
+
+ // modify entry(3,3) of the projection matrix according to
+ // http://www.terathon.com/gdc07_lengyel.pdf
+ // this applies a small constant depth bias in NDC
+ SampleRenderer::RendererProjection proj = mCamera.getProjMatrix();
+ proj.getPxMat44()(3,3) += 4.8e-3f;
+
+ renderer->render(mCamera.getViewMatrix(), proj);
+ }
+ {
+ const PxReal scale = 0.5f;
+ const PxReal shadowOffset = 6.0f;
+
+ Renderer* renderer = getRenderer();
+ PxU32 x = 10;
+ PxU32 y = (PxU32)(-8);
+ const PxU32 yInc = 18;
+
+ char strbuf[512] = "";
+ if (mMenuExpand)
+ {
+
+ const RendererColor textColor(255, 255, 255, 255);
+ const RendererColor highlightTextColor(255, 255, 0, 255);
+
+ switch(mMenuType)
+ {
+ case MenuType::TESTS:
+ {
+ Test::TestGroup* parent = mSelected->getParent();
+ parent->getPathName(strbuf, sizeof strbuf - 1, true);
+ renderer->print(x, y += yInc, strbuf, scale, shadowOffset, textColor);
+
+ for (Test::TestGroup* child = parent->getFirstChild(); child != NULL; child = parent->getNextChild(*child))
+ {
+ sprintf(strbuf, "%s%s", child->getName(), child->isTest() ? "" : "/...");
+ renderer->print(30, y += yInc, strbuf, scale, shadowOffset, (mSelected == child ? highlightTextColor : textColor));
+ }
+ }
+ break;
+ case MenuType::VISUALIZATIONS:
+ {
+ const RendererColor color(0, 90, 90);
+ ScreenQuad sq;
+ sq.mLeftUpColor = color;
+ sq.mRightUpColor = color;
+ sq.mLeftDownColor = color;
+ sq.mRightDownColor = color;
+ sq.mAlpha = 0.75;
+
+ getRenderer()->drawScreenQuad(sq);
+
+ for (PxU32 i = 0; i < mMenuVisualizations.size(); i++)
+ {
+ bool selected = mMenuVisualizationsIndexSelected == i;
+ sprintf(strbuf, "%d (%s) %s", i+1, mMenuVisualizations[i].toggleState ? "ON " : "OFF", mMenuVisualizations[i].name);
+ renderer->print(30, y += yInc, strbuf, scale, shadowOffset, (selected ? highlightTextColor : textColor));
+ }
+ }
+ break;
+ default: {}
+ }
+
+ //print minimal information
+ {
+ y += yInc;
+
+ const RendererColor textColor(255, 255, 255, 255);
+ const char* msg;
+
+ msg = inputInfoMsg("Press "," for help", SHOW_HELP, -1);
+ if(msg)
+ renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor);
+
+ y+=yInc;
+ }
+
+ if (mTextAlphaHelp != 0.0f)
+ {
+ const RendererColor textColor(255, 255, 255, PxU32(mTextAlphaHelp*255.0f));
+ const char* msg;
+
+ if(m_platform->getSampleUserInput()->keyboardSupported() && m_platform->getSampleUserInput()->gamepadSupported())
+ renderer->print(x, y += yInc, "Use arrow keys or D-Pad to navigate between the items", scale, shadowOffset, textColor);
+ else
+ {
+ if(m_platform->getSampleUserInput()->keyboardSupported())
+ {
+ renderer->print(x, y += yInc, "Use arrow keys to navigate between the items", scale, shadowOffset, textColor);
+ }
+ else
+ {
+ if(m_platform->getSampleUserInput()->gamepadSupported())
+ {
+ renderer->print(x, y += yInc, "Use D-Pad to navigate between the items", scale, shadowOffset, textColor);
+ }
+ }
+ }
+ msg = inputInfoMsg("Press "," to run the selected sample", MENU_SELECT, -1);
+ if(msg)
+ renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor);
+ msg = inputInfoMsg("Press "," to exit sample selector", MENU_ESCAPE, -1);
+ if(msg)
+ renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor);
+ }
+ }
+ else
+ {
+ if (mShowExtendedHelp)
+ {
+ mSample->showExtendedInputEventHelp(x,y);
+ }
+ else
+ {
+ //print minimal information
+ {
+ const RendererColor highlightTextColor(255, 255, 0, 255);
+ mRunning->getPathName(strbuf, sizeof strbuf - 1, true);
+
+ if (mSample->isConnectedPvd())
+ strncat(strbuf, " <PVD>", 7);
+ if (mPause)
+ strncat(strbuf, " <PAUSED>", 10);
+
+ renderer->print(x, y += yInc, strbuf, scale, shadowOffset, highlightTextColor);
+ y += yInc;
+
+ const RendererColor textColor(255, 255, 255, 255);
+ const char* msg;
+
+ msg = inputInfoMsg("Press "," for description", SHOW_DESCRIPTION, -1);
+ if(msg)
+ renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor);
+
+ msg = inputInfoMsg("Press "," for help", SHOW_HELP, -1);
+ if(msg)
+ renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor);
+
+ y+=yInc;
+ }
+
+ mSample->descriptionRender(x, y+=yInc, PxU8(mTextAlphaDesc*255.0f));
+
+ //print help
+ if (mTextAlphaHelp != 0.0f)
+ {
+
+ //print common help
+ const RendererColor textColor(255, 255, 255, PxU8(mTextAlphaHelp*255.0f));
+ const char* msg;
+
+ msg = inputInfoMsg("Press "," to enter sample selector", MENU_SAMPLES, -1);
+ if(msg)
+ renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor);
+
+ msg = inputInfoMsg("Press "," to quit", QUIT,-1);
+ if(msg)
+ renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor);
+
+ //print sample specific help
+ mSample->helpRender(x, y += yInc, PxU8(mTextAlphaHelp*255.0f));
+ }
+ }
+ }
+
+ // PT: "customizeRender" is NOT just for text render, it's a generic render callback that should be called all the time,
+ // not just when "mTextAlpha" isn't 0.0
+ mSample->customizeRender();
+ }
+
+ renderer->drawTouchControls();
+
+ mSample->displayFPS();
+
+ if(isConsoleActive())
+ mConsole->render(getRenderer());
+ }
+}
+/*
+void PhysXSampleApplication::advanceSimulation(float dtime)
+{
+ const PxReal timestep = 1.0f/60.0f;
+ while(dtime>0.0f)
+ {
+ const PxReal dt = dtime>=timestep ? timestep : dtime;
+ mScene->simulate(dt);
+ mScene->fetchResults(true);
+ dtime -= dt;
+ }
+}
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+
+void PhysXSampleApplication::onAnalogInputEvent(const SampleFramework::InputEvent& ie, float val)
+{
+ if(mCurrentCameraController)
+ {
+ mCurrentCameraController->onAnalogInputEvent(ie,val);
+ }
+
+ SampleApplication::onAnalogInputEvent(ie,val);
+
+ if(NULL != mSample)
+ mSample->onAnalogInputEvent(ie,val);
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool PhysXSampleApplication::isConsoleActive() const
+{
+ return mConsole && mConsole->isActive();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+const char* getSampleMediaFilename(const char* filename)
+{
+ return findPath(filename);
+}
+///////////////////////////////////////////////////////////////////////////////
+
+void PhysXSampleApplication::baseTickPreRender(float dtime)
+{
+ if(mCurrentCameraController && !isConsoleActive())
+ mCurrentCameraController->update(getCamera(), dtime);
+}
+
+void PhysXSampleApplication::baseTickPostRender(float dtime)
+{
+}
+
+//float tweakElapsedTime(float dtime);
+void PhysXSampleApplication::onTickPreRender(float dtime)
+{
+ if(!mShowHelp)
+ {
+ mTextAlphaHelp -= dtime;
+ if(mTextAlphaHelp<0.0f)
+ mTextAlphaHelp = 0.0f;
+ }
+ else if(0.0f==mTextAlphaDesc)
+ {
+ mTextAlphaHelp += dtime;
+ if(mTextAlphaHelp>1.0f)
+ mTextAlphaHelp = 1.0f;
+ }
+
+ if(!mShowDescription)
+ {
+ mTextAlphaDesc -= dtime;
+ if(mTextAlphaDesc<0.0f)
+ mTextAlphaDesc = 0.0f;
+ }
+ else if(0.0f==mTextAlphaHelp)
+ {
+ mTextAlphaDesc += dtime;
+ if(mTextAlphaDesc>1.0f)
+ mTextAlphaDesc = 1.0f;
+ }
+
+ if (mSample) mSample->onTickPreRender(dtime);
+}
+
+void PhysXSampleApplication::handleMouseVisualization()
+{
+ // hide cursor if mHideMouseCursor is set and the window has focus.
+ showCursor(!mHideMouseCursor || !hasFocus());
+}
+
+void PhysXSampleApplication::onShutdown()
+{
+ Renderer* renderer = getRenderer();
+
+ if (renderer)
+ {
+ renderer->finishRendering();
+ }
+
+ if (mSample)
+ {
+ mSample->onShutdown();
+ delete mSample;
+ mSample = NULL;
+ }
+
+ if (renderer)
+ {
+ renderer->closeScreenquad();
+ renderer->closeTexter();
+ }
+
+ for(PxU32 i=0; i<mLights.size(); i++)
+ mLights[i]->release();
+ mLights.clear();
+ for(PxU32 i=0;i<MATERIAL_COUNT;i++)
+ {
+ if(mManagedMaterials[i])
+ mManagedMaterials[i]->release();
+ mManagedMaterials[i] = NULL;
+ }
+
+ DELETESINGLE(mDebugRenderer);
+}
+
+void PhysXSampleApplication::onInit()
+{
+ Ps::MutexT<Ps::RawAllocator>::ScopedLock lock(mInputMutex);
+
+ Renderer* renderer = getRenderer();
+
+ getPlatform()->getSampleUserInput()->setRenderer(renderer);
+ getPlatform()->getSampleUserInput()->registerInputEventListerner(mInputEventBuffer);
+
+ PxU32 clientWidth, clientHeight;
+ renderer->getWindowSize(clientWidth, clientHeight);
+ updateCameraViewport(clientWidth, clientHeight);
+
+ RendererDirectionalLightDesc lightdesc;
+ lightdesc.intensity = 1;
+
+ lightdesc.color = RendererColor(250, 250, 250, 255);
+ lightdesc.direction = PxVec3(-4.0f, -5.0f, -3.0f);
+ lightdesc.direction.normalizeFast();
+
+ mLights.push_back(renderer->createLight(lightdesc));
+
+ renderer->initTexter();
+ renderer->initScreenquad();
+
+ mDebugRenderer = SAMPLE_NEW(RenderPhysX3Debug)(*renderer, *getAssetManager());
+
+ // Create managed materials
+ {
+ const PxReal c = 0.75f;
+ const PxReal opacity = 1.0f;
+ const bool doubleSided = false;
+ const PxU32 id = 0xffffffff;
+
+ mManagedMaterials[MATERIAL_GREY] = SAMPLE_NEW(RenderMaterial)(*renderer, PxVec3(0.5f, 0.5f, 0.5f), opacity, doubleSided, id, NULL);
+ mManagedMaterials[MATERIAL_RED] = SAMPLE_NEW(RenderMaterial)(*renderer, PxVec3(c, 0.0f, 0.0f), opacity, doubleSided, id, NULL);
+ mManagedMaterials[MATERIAL_GREEN] = SAMPLE_NEW(RenderMaterial)(*renderer, PxVec3(0.0f, c, 0.0f), opacity, doubleSided, id, NULL);
+ mManagedMaterials[MATERIAL_BLUE] = SAMPLE_NEW(RenderMaterial)(*renderer, PxVec3(0.0f, 0.0f, c), opacity, doubleSided, id, NULL);
+ mManagedMaterials[MATERIAL_YELLOW] = SAMPLE_NEW(RenderMaterial)(*renderer, PxVec3(c, c, 0.0f), opacity, doubleSided, id, NULL);
+ mManagedMaterials[MATERIAL_FLAT] = SAMPLE_NEW(RenderMaterial)(*renderer, PxVec3(0.5f, 0.5f, 0.5f), opacity, doubleSided, id, NULL, true, true);
+ }
+
+ getNextSample();
+ if (mSample)
+ {
+ mSample->onInit(false);
+ mSample->registerInputEvents();
+ }
+}
+
+void PhysXSampleApplication::onTickPostRender(float dtime)
+{
+ if (mSample)
+ mSample->onTickPostRender(dtime);
+}
+
+void PhysXSampleApplication::showCursor(bool show)
+{
+ if(m_platform)
+ m_platform->showCursor(show);
+}
+
+void PhysXSampleApplication::setMouseCursorHiding(bool hide)
+{
+ if(hide != mHideMouseCursor)
+ {
+ mHideMouseCursor = hide;
+ }
+}
+
+void PhysXSampleApplication::setMouseCursorRecentering(bool recenter)
+{
+ PX_ASSERT(SamplePlatform::platform());
+ SamplePlatform::platform()->setMouseCursorRecentering(recenter);
+}
+
+void PhysXSampleApplication::onPointerInputEvent(const InputEvent& ie, PxU32 x, PxU32 y, PxReal dx, PxReal dy, bool val)
+{
+ SampleApplication::onPointerInputEvent(ie,x,y,dx,dy,val);
+
+ if(mSample)
+ {
+ mSample->onPointerInputEvent(ie,x,y,dx,dy,val);
+ }
+
+ if(mCurrentCameraController)
+ {
+ mCurrentCameraController->onPointerInputEvent(ie,x,y,dx,dy,val);
+ }
+}
+
+void PhysXSampleApplication::onKeyDownEx(SampleFramework::SampleUserInput::KeyCode keyCode, PxU32 wParam)
+{
+ if(mSample)
+ mSample->onKeyDownEx(keyCode, wParam);
+
+ if(mConsole)
+ mConsole->onKeyDown(keyCode, wParam);
+
+}
+
+void PhysXSampleApplication::onResize(PxU32 width, PxU32 height)
+{
+ if(mSample)
+ mSample->onResize(width, height);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+void PhysXSampleApplication::onDigitalInputEvent(const SampleFramework::InputEvent& ie, bool val)
+{
+ if(mCurrentCameraController)
+ {
+ mCurrentCameraController->onDigitalInputEvent(ie,val);
+ }
+
+ SampleApplication::onDigitalInputEvent(ie,val);
+
+ if (mConsole)
+ {
+ mConsole->onDigitalInputEvent(ie,val);
+ if(mConsole->isActive())
+ return;
+ }
+
+ MenuKey::Enum menuKey = MenuKey::NONE;
+
+ switch (ie.m_Id)
+ {
+ case RUN_NEXT_SAMPLE:
+ {
+ if(val)
+ {
+ handleMenuKey(MenuKey::NAVI_DOWN);
+ handleMenuKey(MenuKey::SELECT);
+ }
+ }
+ break;
+ case RUN_PREVIOUS_SAMPLE:
+ {
+ if(val)
+ {
+ handleMenuKey(MenuKey::NAVI_UP);
+ if(!handleMenuKey(MenuKey::SELECT))
+ return;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if(val)
+ {
+ switch (ie.m_Id)
+ {
+ case MENU_UP: if(mMenuExpand) menuKey = MenuKey::NAVI_UP; break;
+ case MENU_DOWN: if(mMenuExpand) menuKey = MenuKey::NAVI_DOWN; break;
+ case MENU_LEFT: if(mMenuExpand) menuKey = MenuKey::NAVI_LEFT; break;
+ case MENU_RIGHT: if(mMenuExpand) menuKey = MenuKey::NAVI_RIGHT; break;
+ case MENU_SELECT: if(mMenuExpand) menuKey = MenuKey::SELECT; break;
+ case MENU_ESCAPE: if(mMenuExpand) menuKey = MenuKey::ESCAPE; break;
+ case MENU_QUICK_UP: mMenuExpand = true; menuKey = MenuKey::NAVI_UP; break;
+ case MENU_QUICK_DOWN: mMenuExpand = true; menuKey = MenuKey::NAVI_DOWN; break;
+ case MENU_QUICK_LEFT: mMenuExpand = true; menuKey = MenuKey::NAVI_LEFT; break;
+ case MENU_QUICK_RIGHT: mMenuExpand = true; menuKey = MenuKey::NAVI_RIGHT; break;
+ }
+
+ if (mMenuExpand)
+ {
+ if (ie.m_Id == SHOW_HELP)
+ {
+ mShowHelp = !mShowHelp;
+ return;
+ }
+ if(mMenuType == MenuType::TESTS)
+ {
+ if(!handleMenuKey(menuKey))
+ return;
+ }
+ else
+ {
+ handleSettingMenuKey(menuKey);
+ }
+ return;
+ }
+
+ switch (ie.m_Id)
+ {
+ case SHOW_EXTENDED_HELP:
+ {
+ mShowExtendedHelp = !mShowExtendedHelp;
+ if(mSample)
+ mSample->resetExtendedHelpText();
+ break;
+ }
+ case MENU_VISUALIZATIONS:
+ {
+ mMenuExpand = true;
+ mMenuType = MenuType::VISUALIZATIONS;
+ break;
+ }
+ case MENU_SAMPLES:
+ {
+ mMenuExpand = true;
+ mMenuType = MenuType::TESTS;
+ break;
+ }
+ case QUIT:
+ {
+ requestToClose();
+ break;
+ }
+ default:
+ if(NULL != mSample)
+ {
+ mSample->onDigitalInputEvent(ie,val);
+ }
+ break;
+ }
+ }
+ else
+ {
+ if (mMenuExpand)
+ {
+ if (MENU_ESCAPE == ie.m_Id)
+ {
+ mMenuExpand = false;
+ mMenuType = MenuType::TESTS;
+ }
+ }
+ if(mSample)
+ {
+ mSample->onDigitalInputEvent(ie,val);
+ }
+ }
+}
+
+void PhysXSampleApplication::toggleDebugRenderer()
+{
+ PxScene& scene = mSample->getActiveScene();
+ scene.setVisualizationParameter(PxVisualizationParameter::eSCALE, mSample->getDebugRenderScale());
+ mMenuVisualizations[0].toggleState = true;
+}
+
+void PhysXSampleApplication::handleSettingMenuKey(MenuKey::Enum menuKey)
+{
+ size_t numEntries = mMenuVisualizations.size();
+ switch(menuKey)
+ {
+ case MenuKey::NAVI_LEFT:
+ case MenuKey::NAVI_UP:
+ mMenuVisualizationsIndexSelected = (mMenuVisualizationsIndexSelected > 0) ? (mMenuVisualizationsIndexSelected - 1) : numEntries - 1;
+ break;
+ case MenuKey::NAVI_RIGHT:
+ case MenuKey::NAVI_DOWN:
+ mMenuVisualizationsIndexSelected = (mMenuVisualizationsIndexSelected + 1) % numEntries;
+ break;
+ case MenuKey::SELECT:
+ {
+ MenuTogglableItem& togglableItem = mMenuVisualizations[mMenuVisualizationsIndexSelected];
+ PxU32 menuVisIndex = togglableItem.toggleCommand;
+ PX_ASSERT(menuVisIndex < PxVisualizationParameter::eNUM_VALUES);
+ PxScene& scene = mSample->getActiveScene();
+ PxVisualizationParameter::Enum p = static_cast<PxVisualizationParameter::Enum>(menuVisIndex);
+ scene.setVisualizationParameter(p, (scene.getVisualizationParameter(p) != 0.0f) ? 0.0f : 1.0f);
+
+ bool enabled = scene.getVisualizationParameter(p) != 0.0f;
+ if(enabled && scene.getVisualizationParameter(PxVisualizationParameter::eSCALE) == 0.0f)
+ {
+ toggleDebugRenderer();
+ }
+ togglableItem.toggleState = scene.getVisualizationParameter(p) != 0.0f;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+bool PhysXSampleApplication::handleMenuKey(MenuKey::Enum menuKey)
+{
+ if (!mSelected)
+ return false;
+
+ Test::TestGroup* parent = mSelected->getParent(), *child = NULL;
+ PX_ASSERT(parent);
+
+ switch (menuKey)
+ {
+ case MenuKey::NAVI_LEFT:
+ if (NULL != parent->getParent())
+ mSelected = parent;
+ break;
+ case MenuKey::NAVI_RIGHT:
+ if (NULL != (child = mSelected->getFirstChild()))
+ mSelected = child;
+ break;
+ case MenuKey::NAVI_UP:
+ if (NULL != (child = parent->getPreviousChild(*mSelected)))
+ mSelected = child;
+ else if (NULL != (child = parent->getLastChild()))
+ mSelected = child;
+ break;
+ case MenuKey::NAVI_DOWN:
+ if (NULL != (child = parent->getNextChild(*mSelected)))
+ mSelected = child;
+ else if (NULL != (child = parent->getFirstChild()))
+ mSelected = child;
+ break;
+ case MenuKey::SELECT:
+ if (mSelected->isTest())
+ {
+ mMenuExpand = false;
+ mSwitchSample = true;
+ mInputEventBuffer->clear();
+ return false;
+ }
+ else
+ {
+ if (NULL != (child = mSelected->getFirstChild()))
+ mSelected = child;
+ }
+ break;
+ default:
+ //mSelected = mRunning;
+ break;
+ }
+
+ return true;
+}
+
+void PhysXSampleApplication::switchSample()
+{
+ Ps::MutexT<Ps::RawAllocator>::ScopedLock lock(mInputMutex);
+ if(mInputEventBuffer)
+ mInputEventBuffer->clear();
+
+ bool isRestart = mRunning == mSelected;
+
+ Renderer* renderer = getRenderer();
+ if (renderer)
+ {
+ renderer->finishRendering();
+ }
+
+ if (mSample)
+ {
+ mSample->onShutdown();
+ delete mSample;
+ mSample = NULL;
+ }
+
+ if(!isRestart)
+ {
+ setDefaultCameraController();
+ resetDefaultCameraController();
+ }
+ if (getNextSample())
+ {
+ mSample->onInit(isRestart);
+ mSample->registerInputEvents();
+ if (mCurrentCameraController)
+ mCurrentCameraController->update(getCamera(), 0.0f);
+ mSample->onTickPreRender(0.0f);
+ mSample->onSubstep(0.0f);
+ mSample->initRenderObjects();
+ }
+
+ mSwitchSample = false;
+}
+
+//=============================================================================
+// PhysXSampleManager
+//-----------------------------------------------------------------------------
+Test::TestGroup* PhysXSampleApplication::mSampleTreeRoot = NULL;
+
+Test::TestGroup& PhysXSampleApplication::getSampleTreeRoot()
+{
+ if (NULL == mSampleTreeRoot)
+ {
+ mSampleTreeRoot = new Test::TestGroup("");
+ }
+ return *mSampleTreeRoot;
+}
+
+bool PhysXSampleApplication::addSample(Test::TestGroup &root, SampleCreator creator, const char *fullPath)
+{
+ PX_ASSERT(fullPath);
+
+ do
+ {
+ if ('\0' == fullPath[0] || '/' == fullPath[0])
+ {
+ shdfnd::printFormatted("invalid name: %s\n", fullPath);
+ break;
+ }
+
+ const char* p = fullPath;
+ while ('\0' != *p && '/' != *p)
+ ++p;
+
+ if ('\0' == *p) // test name
+ {
+ if (root.getChildByName(fullPath)) // duplicated name
+ {
+ shdfnd::printFormatted("test \"%s\" exists.\n", fullPath);
+ break;
+ }
+ root.addTest(creator, fullPath);
+ }
+ else // group name
+ {
+ Test::TestGroup* group = root.getChildByName(fullPath, p - fullPath);
+ if (group)
+ return addSample(*group, creator, p + 1);
+
+ group = new Test::TestGroup(fullPath, p - fullPath);
+ if (!addSample(*group, creator, p + 1))
+ {
+ delete group;
+ break;
+ }
+ root.addGroup(group);
+ }
+
+ return true;
+ } while (false);
+ return false;
+}
+
+bool PhysXSampleApplication::getNextSample()
+{
+ Test::TestGroup& root = PhysXSampleApplication::getSampleTreeRoot();
+
+ if (NULL == mSelected)
+ mSelected = root.getFirstTest();
+
+ if (NULL == mSelected)
+ return false;
+
+ mRunning = mSelected;
+ mSample = (*mRunning->getCreator())(*this);
+ return true;
+}
+
+void PhysXSampleApplication::saveCameraState()
+{
+ mSavedView = getCamera().getViewMatrix();
+}
+
+void PhysXSampleApplication::restoreCameraState()
+{
+ getCamera().setView(mSavedView);
+}
diff --git a/PhysX_3.4/Samples/SampleBase/PhysXSampleApplication.h b/PhysX_3.4/Samples/SampleBase/PhysXSampleApplication.h
new file mode 100644
index 00000000..fa0cda57
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/PhysXSampleApplication.h
@@ -0,0 +1,364 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef PHYSX_SAMPLE_APPLICATION_H
+#define PHYSX_SAMPLE_APPLICATION_H
+
+#include "SamplePreprocessor.h"
+#include "SampleApplication.h"
+#include "SampleCamera.h"
+#include "SampleCameraController.h"
+#include "SampleAllocator.h"
+#include "PxFiltering.h"
+#include "RawLoader.h"
+#include "RendererMeshContext.h"
+#include "PxTkFPS.h"
+#include "PxVisualizationParameter.h"
+#include "PxTkRandom.h"
+
+#include <PsThread.h>
+#include <PsSync.h>
+#include "PsHashMap.h"
+#include "PsUtilities.h"
+#include "SampleArray.h"
+
+#if PX_WINDOWS
+#include "task/PxTask.h"
+#endif
+
+#define PHYSX_VERSION_STRING PX_STRINGIZE(PX_PHYSICS_VERSION_MAJOR) "." PX_STRINGIZE(PX_PHYSICS_VERSION_MINOR)
+
+#define SAMPLE_MEDIA_DIR "/PhysX/" PHYSX_VERSION_STRING "/Samples"
+#define SAMPLE_OUTPUT_DIR "media" SAMPLE_MEDIA_DIR "/user"
+
+namespace physx
+{
+ class PxDefaultCpuDispatcher;
+ class PxPhysics;
+ class PxCooking;
+ class PxScene;
+ class PxGeometry;
+ class PxMaterial;
+ class PxRigidActor;
+};
+
+ class RenderPhysX3Debug;
+ class RenderBaseActor;
+ class RenderMaterial;
+ class RenderMeshActor;
+ class RenderTexture;
+ class Stepper;
+ class Console;
+
+ class PhysXSampleApplication;
+ class PhysXSample;
+ class InputEventBuffer;
+
+ namespace Test
+ {
+ class TestGroup;
+ }
+
+ class PhysXSampleCreator
+ {
+ public:
+ virtual ~PhysXSampleCreator() {}
+ virtual PhysXSample* operator()(PhysXSampleApplication& app) const = 0;
+ };
+
+ typedef PhysXSampleCreator *SampleCreator;
+ typedef PhysXSample* (*FunctionCreator)(PhysXSampleApplication& app);
+// typedef PhysXSample* (*SampleCreator)(PhysXSampleApplication& app);
+
+ struct SampleSetup
+ {
+ SampleSetup() :
+ mName (NULL),
+ mWidth (0),
+ mHeight (0),
+ mFullscreen (false)
+ {
+ }
+ const char* mName;
+ PxU32 mWidth;
+ PxU32 mHeight;
+ bool mFullscreen;
+ };
+ // Default materials created by PhysXSampleApplication
+ enum MaterialIndex
+ {
+ MATERIAL_GREY,
+ MATERIAL_RED,
+ MATERIAL_GREEN,
+ MATERIAL_BLUE,
+ MATERIAL_YELLOW,
+ MATERIAL_FLAT,
+ MATERIAL_COUNT,
+ };
+
+template <typename Container>
+void releaseAll(Container& container)
+{
+ for (PxU32 i = 0; i < container.size(); ++i)
+ container[i]->release();
+ container.clear();
+}
+
+
+class PhysXSampleApplication : public SampleFramework::SampleApplication, public SampleAllocateable, public Ps::ThreadT<Ps::RawAllocator>
+ {
+ public:
+ using SampleAllocateable::operator new;
+ using SampleAllocateable::operator delete;
+ private:
+ friend class PhysXSample;
+ struct PvdParameters
+ {
+ char ip[256];
+ PxU32 port;
+ PxU32 timeout;
+ bool useFullPvdConnection;
+
+ PvdParameters()
+ : port(5425)
+ , timeout(10)
+ , useFullPvdConnection(true)
+ {
+ Ps::strlcpy(ip, 256, "127.0.0.1");
+ }
+ };
+ struct MenuKey
+ {
+ enum Enum
+ {
+ NONE,
+ ESCAPE,
+ SELECT,
+ NAVI_UP,
+ NAVI_DOWN,
+ NAVI_LEFT,
+ NAVI_RIGHT
+ };
+ };
+
+ // menu events
+ struct MenuType
+ {
+ enum Enum
+ {
+ NONE,
+ HELP,
+ SETTINGS,
+ VISUALIZATIONS,
+ TESTS
+ };
+ };
+
+ struct MenuTogglableItem
+ {
+ MenuTogglableItem(PxU32 c, const char* n) : toggleCommand(c), toggleState(false), name(n) {}
+ PxU32 toggleCommand;
+ bool toggleState;
+ const char* name;
+ };
+
+ public:
+ PhysXSampleApplication(const SampleFramework::SampleCommandLine& cmdline);
+ virtual ~PhysXSampleApplication();
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // PsThread interface
+ virtual void execute();
+
+ ///////////////////////////////////////////////////////////////////////////////
+
+ // Implements SampleApplication/RendererWindow
+ virtual void onInit();
+ virtual void onShutdown();
+
+ virtual float tweakElapsedTime(float dtime);
+ virtual void onTickPreRender(float dtime);
+ virtual void onRender();
+ virtual void onTickPostRender(float dtime);
+
+ void onKeyDownEx(SampleFramework::SampleUserInput::KeyCode keyCode, PxU32 wParam);
+ void onAnalogInputEvent(const SampleFramework::InputEvent& , float val);
+ void onDigitalInputEvent(const SampleFramework::InputEvent& , bool val);
+ void onPointerInputEvent(const SampleFramework::InputEvent&, PxU32 x, PxU32 y, PxReal dx, PxReal dy, bool val);
+
+ virtual void onResize(PxU32 width, PxU32 height);
+
+ void baseTickPreRender(float dtime);
+ void baseTickPostRender(float dtime);
+
+ void baseResize(PxU32 width, PxU32 height);
+
+ ///////////////////////////////////////////////////////////////////////////////
+
+ void customizeSample(SampleSetup&);
+// void onSubstep(float dtime);
+
+ ///////////////////////////////////////////////////////////////////////////////
+ void applyDefaultVisualizationSettings();
+ void saveCameraState();
+ void restoreCameraState();
+
+ // Camera functions
+ PX_FORCE_INLINE void setDefaultCameraController() { mCurrentCameraController = &mCameraController; mCameraController = DefaultCameraController();}
+ PX_FORCE_INLINE void resetDefaultCameraController() { mCameraController = DefaultCameraController(); }
+ PX_FORCE_INLINE void setCameraController(CameraController* c) { mCurrentCameraController = c; }
+
+ PX_FORCE_INLINE PxReal getTextAlpha1() const { return mTextAlphaHelp; }
+ PX_FORCE_INLINE PxReal getTextAlpha2() const { return mTextAlphaDesc; }
+ PX_FORCE_INLINE bool isPaused() const { return mPause; }
+ PX_FORCE_INLINE Camera& getCamera() { return mCamera; }
+ PX_FORCE_INLINE RenderPhysX3Debug* getDebugRenderer() const { return mDebugRenderer; }
+ PX_FORCE_INLINE Ps::MutexT<Ps::RawAllocator>& getInputMutex() { return mInputMutex; }
+ bool isConsoleActive() const;
+ void showCursor(bool show);
+ void setMouseCursorHiding(bool hide);
+ void setMouseCursorRecentering(bool recenter);
+ void handleMouseVisualization();
+ void updateEngine();
+ void setPvdParams(const SampleFramework::SampleCommandLine& cmdLine);
+ PX_FORCE_INLINE void registerLight(SampleRenderer::RendererLight* light) { mLights.push_back(light); }
+ void collectInputEvents(std::vector<const SampleFramework::InputEvent*>& inputEvents);
+ const char* inputInfoMsg(const char* firstPart,const char* secondPart, PxI32 inputEventId1, PxI32 inputEventId2);
+ const char* inputInfoMsg_Aor_BandC(const char* firstPart,const char* secondPart, PxI32 inputEventIdA, PxI32 inputEventIdB, PxI32 inputEventIdC);
+ const char* inputMoveInfoMsg(const char* firstPart,const char* secondPart, PxI32 inputEventId1, PxI32 inputEventId2,PxI32 inputEventId3,PxI32 inputEventId4);
+ void requestToClose() { mIsCloseRequested = true; }
+ bool isCloseRequested() { return mIsCloseRequested; }
+
+ private:
+ PxReal mTextAlphaHelp;
+ PxReal mTextAlphaDesc;
+ MenuType::Enum mMenuType;
+ std::vector<MenuTogglableItem> mMenuVisualizations;
+ size_t mMenuVisualizationsIndexSelected;
+ void setMenuVisualizations(MenuTogglableItem& togglableItem);
+ char m_Msg[512];
+
+ PxTransform mSavedView;
+ bool mIsCloseRequested;
+
+ protected:
+ Console* mConsole;
+
+ Camera mCamera;
+ DefaultCameraController mCameraController;
+ CameraController* mCurrentCameraController;
+
+ std::vector<SampleRenderer::RendererLight*> mLights;
+ RenderMaterial* mManagedMaterials[MATERIAL_COUNT];
+
+ RenderPhysX3Debug* mDebugRenderer;
+
+
+ bool mPause;
+ bool mOneFrameUpdate;
+ bool mSwitchSample;
+
+ bool mShowHelp;
+ bool mShowDescription;
+ bool mShowExtendedHelp;
+ volatile bool mHideMouseCursor;
+ InputEventBuffer* mInputEventBuffer;
+ Ps::MutexT<RawAllocator> mInputMutex;
+
+ bool mDrawScreenQuad;
+ SampleRenderer::RendererColor mScreenQuadTopColor;
+ SampleRenderer::RendererColor mScreenQuadBottomColor;
+
+ PvdParameters mPvdParams;
+ void updateCameraViewport(PxU32 w, PxU32 h);
+ bool initLogo();
+
+ private:
+ bool handleMenuKey(MenuKey::Enum menuKey);
+ void handleSettingMenuKey(MenuKey::Enum menuKey);
+ void refreshVisualizationMenuState(PxVisualizationParameter::Enum p);
+ void toggleDebugRenderer();
+
+//-----------------------------------------------------------------------------
+// PhysXSampleManager
+//-----------------------------------------------------------------------------
+ public:
+ static bool registerSample(SampleCreator creator, const char* fullPath)
+ {
+ return addSample(getSampleTreeRoot(), creator, fullPath);
+ }
+ bool getNextSample();
+ void switchSample();
+ protected:
+ static Test::TestGroup* mSampleTreeRoot;
+ static Test::TestGroup& getSampleTreeRoot();
+ static bool addSample(Test::TestGroup& root, SampleCreator creator, const char* fullPath);
+ public:
+ bool mMenuExpand;
+ Test::TestGroup* mRunning;
+ Test::TestGroup* mSelected;
+ PhysXSample* mSample;
+ const char* mDefaultSamplePath;
+ };
+
+ const char* getSampleMediaFilename(const char* filename);
+ PxToolkit::BasicRandom& getSampleRandom();
+ PxErrorCallback& getSampleErrorCallback();
+
+//=============================================================================
+// macro REGISTER_SAMPLE
+//-----------------------------------------------------------------------------
+ class SampleFunctionCreator : public PhysXSampleCreator
+ {
+ public:
+ SampleFunctionCreator(FunctionCreator func) : mFunc(func) {}
+ virtual PhysXSample* operator()(PhysXSampleApplication& app) const { return (*mFunc)(app); }
+ private:
+ FunctionCreator mFunc;
+ };
+
+#define SAMPLE_CREATOR(className) create##className
+#define SAMPLE_STARTER(className) className##Starter
+
+#define SAMPLE_CREATOR_VAR(className) g##className##creator
+
+#define REGISTER_SAMPLE(className, fullPath) \
+ static PhysXSample* SAMPLE_CREATOR(className)(PhysXSampleApplication& app) { \
+ return SAMPLE_NEW(className)(app); \
+ } \
+ static SampleFunctionCreator SAMPLE_CREATOR_VAR(className)(SAMPLE_CREATOR(className)); \
+ struct SAMPLE_STARTER(className) { \
+ SAMPLE_STARTER(className)() { \
+ PhysXSampleApplication::registerSample(&SAMPLE_CREATOR_VAR(className), fullPath); \
+ } \
+ } g##className##Starter;
+
+
+///////////////////////////////////////////////////////////////////////////////
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/Picking.cpp b/PhysX_3.4/Samples/SampleBase/Picking.cpp
new file mode 100644
index 00000000..5721e9da
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/Picking.cpp
@@ -0,0 +1,289 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "PxScene.h"
+#include "PxQueryReport.h"
+#include "PxBatchQueryDesc.h"
+#include "extensions/PxJoint.h"
+#include "PxRigidDynamic.h"
+#include "extensions/PxDistanceJoint.h"
+#include "extensions/PxSphericalJoint.h"
+#include "PxArticulationLink.h"
+#include "PxShape.h"
+#include "Picking.h"
+#include "RendererMemoryMacros.h"
+
+#if PX_UNIX_FAMILY
+#include <stdio.h>
+#endif
+
+using namespace physx; // PT: please DO NOT indent the whole file
+
+Picking::Picking(PhysXSample& frame) :
+ mSelectedActor (NULL),
+ mMouseJoint (NULL),
+ mMouseActor (NULL),
+ mMouseActorToDelete (NULL),
+ mDistanceToPicked (0.0f),
+ mMouseScreenX (0),
+ mMouseScreenY (0),
+ mFrame (frame)
+{
+}
+Picking::~Picking() {}
+
+bool Picking::isPicked() const
+{
+ return mMouseJoint!=0;
+}
+
+void Picking::moveCursor(PxI32 x, PxI32 y)
+{
+ mMouseScreenX = x;
+ mMouseScreenY = y;
+}
+
+/*void Picking::moveCursor(PxReal deltaDepth)
+{
+ const PxReal range[2] = { 0.0f, 1.0f };
+
+ const PxReal r = (range[1] - range[0]);
+ const PxReal d = (mMouseDepth - range[0])/r;
+ const PxReal delta = deltaDepth*0.02f*(1.0f - d);
+
+ mMouseDepth = PxClamp(mMouseDepth + delta, range[0], range[1]);
+}*/
+
+void Picking::tick()
+{
+ if(mMouseJoint)
+ moveActor(mMouseScreenX,mMouseScreenY);
+
+ // PT: delete mouse actor one frame later to avoid crashes
+ SAFE_RELEASE(mMouseActorToDelete);
+}
+
+void Picking::computeCameraRay(PxVec3& orig, PxVec3& dir, PxI32 x, PxI32 y) const
+{
+ const PxVec3& camPos = mFrame.getCamera().getPos();
+
+ // compute picking ray
+// const PxVec3 rayOrig = unProject(x, y, 0.0f); // PT: what the frell is that?
+ const PxVec3 rayOrig = camPos;
+ const PxVec3 rayDir = (unProject(x, y, 1.0f) - rayOrig).getNormalized();
+
+ orig = rayOrig;
+ dir = rayDir;
+}
+
+bool Picking::pick(int x, int y)
+{
+ PxScene& scene = mFrame.getActiveScene();
+
+ PxVec3 rayOrig, rayDir;
+ computeCameraRay(rayOrig, rayDir, x, y);
+
+ // raycast rigid bodies in scene
+ PxRaycastHit hit; hit.shape = NULL;
+ PxRaycastBuffer hit1;
+ scene.raycast(rayOrig, rayDir, PX_MAX_F32, hit1, PxHitFlag::ePOSITION);
+ hit = hit1.block;
+
+ if(hit.shape)
+ {
+ const char* shapeName = hit.shape->getName();
+ if(shapeName)
+ shdfnd::printFormatted("Picked shape name: %s\n", shapeName);
+
+ PxRigidActor* actor = hit.actor;
+ PX_ASSERT(actor);
+ mSelectedActor = static_cast<PxRigidActor*>(actor->is<PxRigidDynamic>());
+ if(!mSelectedActor)
+ mSelectedActor = static_cast<PxRigidActor*>(actor->is<PxArticulationLink>());
+
+ //ML::this is very useful to debug some collision problem
+ PxTransform t = actor->getGlobalPose();
+ PX_UNUSED(t);
+ shdfnd::printFormatted("id = %i\n PxTransform transform(PxVec3(%f, %f, %f), PxQuat(%f, %f, %f, %f))\n", reinterpret_cast<size_t>(actor->userData), t.p.x, t.p.y, t.p.z, t.q.x, t.q.y, t.q.z, t.q.w);
+ }
+ else
+ mSelectedActor = 0;
+
+ if(mSelectedActor)
+ {
+ shdfnd::printFormatted("Actor '%s' picked! (userData: %p)\n", mSelectedActor->getName(), mSelectedActor->userData);
+
+ //if its a dynamic rigid body, joint it for dragging purposes:
+ grabActor(hit.position, rayOrig);
+ }
+
+#ifdef VISUALIZE_PICKING_RAYS
+ Ray ray;
+ ray.origin = rayOrig;
+ ray.dir = rayDir;
+ mRays.push_back(ray);
+#endif
+ return true;
+}
+
+
+//----------------------------------------------------------------------------//
+
+PxActor* Picking::letGo()
+{
+ // let go any picked actor
+ if(mMouseJoint)
+ {
+ mMouseJoint->release();
+ mMouseJoint = NULL;
+
+ // SAFE_RELEASE(mMouseActor); // PT: releasing immediately crashes
+ PX_ASSERT(!mMouseActorToDelete);
+ mMouseActorToDelete = mMouseActor; // PT: instead, we mark for deletion next frame
+ }
+
+ PxActor* returnedActor = mSelectedActor;
+
+ mSelectedActor = NULL;
+
+ return returnedActor;
+}
+
+//----------------------------------------------------------------------------//
+
+void Picking::grabActor(const PxVec3& worldImpact, const PxVec3& rayOrigin)
+{
+ if(!mSelectedActor
+ || (mSelectedActor->getType() != PxActorType::eRIGID_DYNAMIC
+ && mSelectedActor->getType() != PxActorType::eARTICULATION_LINK))
+ return;
+
+ PxScene& scene = mFrame.getActiveScene();
+ PxPhysics& physics = scene.getPhysics();
+
+ //create a shape less actor for the mouse
+ {
+ mMouseActor = physics.createRigidDynamic(PxTransform(worldImpact, PxQuat(PxIdentity)));
+ mMouseActor->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, true);
+ mMouseActor->setMass(1.0f);
+ mMouseActor->setMassSpaceInertiaTensor(PxVec3(1.0f, 1.0f, 1.0f));
+
+ scene.addActor(*mMouseActor);
+ }
+ PxRigidActor* pickedActor = static_cast<PxRigidActor*>(mSelectedActor);
+
+#if USE_D6_JOINT_FOR_MOUSE
+ mMouseJoint = PxD6JointCreate( physics,
+ mMouseActor,
+ PxTransform(PxIdentity),
+ pickedActor,
+ PxTransform(pickedActor->getGlobalPose().transformInv(worldImpact)));
+ mMouseJoint->setMotion(PxD6Axis::eSWING1, PxD6Motion::eFREE);
+ mMouseJoint->setMotion(PxD6Axis::eSWING2, PxD6Motion::eFREE);
+ mMouseJoint->setMotion(PxD6Axis::eTWIST, PxD6Motion::eFREE);
+#elif USE_SPHERICAL_JOINT_FOR_MOUSE
+ mMouseJoint = PxSphericalJointCreate(physics,
+ mMouseActor,
+ PxTransform(PxIdentity),
+ pickedActor,
+ PxTransform(pickedActor->getGlobalPose().transformInv(worldImpact)));
+#else
+ mMouseJoint = PxDistanceJointCreate(physics,
+ mMouseActor,
+ PxTransform(PxIdentity),
+ pickedActor,
+ PxTransform(pickedActor->getGlobalPose().transformInv(worldImpact)));
+ mMouseJoint->setMaxDistance(0.0f);
+ mMouseJoint->setMinDistance(0.0f);
+ mMouseJoint->setDistanceJointFlags(PxDistanceJointFlag::eMAX_DISTANCE_ENABLED);
+#endif
+
+ mDistanceToPicked = (worldImpact - rayOrigin).magnitude();
+}
+
+//----------------------------------------------------------------------------//
+
+void Picking::moveActor(int x, int y)
+{
+ if(!mMouseActor)
+ return;
+
+ PxVec3 rayOrig, rayDir;
+ computeCameraRay(rayOrig, rayDir, x, y);
+
+ const PxVec3 pos = rayOrig + mDistanceToPicked * rayDir;
+
+ mMouseActor->setKinematicTarget(PxTransform(pos, PxQuat(PxIdentity)));
+}
+
+//----------------------------------------------------------------------------//
+
+PxVec3 Picking::unProject(int x, int y, float depth) const
+{
+ SampleRenderer::Renderer* renderer = mFrame.getRenderer();
+ const SampleRenderer::RendererProjection& projection = mFrame.getCamera().getProjMatrix();
+ const PxTransform view = mFrame.getCamera().getViewMatrix().getInverse();
+
+ PxU32 windowWidth = 0;
+ PxU32 windowHeight = 0;
+ renderer->getWindowSize(windowWidth, windowHeight);
+
+ const PxF32 outX = (float)x / (float)windowWidth;
+ const PxF32 outY = (float)y / (float)windowHeight;
+
+ return SampleRenderer::unproject(projection, view, outX * 2 -1, outY * 2 -1, depth * 2 - 1);
+}
+
+//----------------------------------------------------------------------------//
+
+void Picking::project(const physx::PxVec3& v, int& xi, int& yi, float& depth) const
+{
+ SampleRenderer::Renderer* renderer = mFrame.getRenderer();
+ SampleRenderer::RendererProjection projection = mFrame.getCamera().getProjMatrix();
+ const PxTransform view = mFrame.getCamera().getViewMatrix().getInverse();
+
+ PxVec3 pos = SampleRenderer::project(projection, view, v);
+ ///* Map x, y and z to range 0-1 */
+ pos.x = (pos.x + 1 ) * 0.5f;
+ pos.y = (pos.y + 1 ) * 0.5f;
+ pos.z = (pos.z + 1 ) * 0.5f;
+
+ PxU32 windowWidth = 0;
+ PxU32 windowHeight = 0;
+ renderer->getWindowSize(windowWidth, windowHeight);
+
+ /* Map x,y to viewport */
+ pos.x *= windowWidth;
+ pos.y *= windowHeight;
+
+ depth = (float)pos.z;
+
+ xi = (int)(pos.x + 0.5);
+ yi = (int)(pos.y + 0.5);
+}
diff --git a/PhysX_3.4/Samples/SampleBase/Picking.h b/PhysX_3.4/Samples/SampleBase/Picking.h
new file mode 100644
index 00000000..48cb5c29
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/Picking.h
@@ -0,0 +1,121 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PICKING_H
+#define PICKING_H
+
+#include "foundation/PxSimpleTypes.h"
+#include "foundation/PxVec3.h"
+#include "extensions/PxD6Joint.h"
+#include "extensions/PxSphericalJoint.h"
+
+#include "PhysXSample.h"
+#include "RendererProjection.h"
+
+#define USE_D6_JOINT_FOR_MOUSE 1 // PT: please keep it 0 for interactive tests where one needs to rotate objects
+#define USE_SPHERICAL_JOINT_FOR_MOUSE 0
+//#define VISUALIZE_PICKING_RAYS
+
+namespace physx
+{
+ class PxActor;
+ class PxDistanceJoint;
+ class PxRigidDynamic;
+ class PxScene;
+ class PxPhysics;
+}
+
+namespace physx {
+
+ struct PickingCommands
+ {
+ enum Enum
+ {
+ PICK_START, //Bound to mouse 1 down
+ PICK_STOP, //bound to mouse 1 up
+ SCREEN_MOTION_CURSOR, //See DefaultMovementStrategy
+ SCREEN_MOTION_CURSOR_DEPTH, //See DefaultMovementStrategy
+ };
+ };
+
+ class Picking
+ {
+ public:
+ Picking(PhysXSample& frame);
+ ~Picking();
+
+ PX_FORCE_INLINE void lazyPick() { pick(mMouseScreenX, mMouseScreenY); }
+ bool isPicked() const;
+ bool pick(int x, int y);
+ void moveCursor(PxI32 x, PxI32 y);
+// void moveCursor(PxReal deltaDepth);
+
+ void computeCameraRay(PxVec3& orig, PxVec3& dir, PxI32 x, PxI32 y) const;
+
+ // returns picked actor
+ PxActor* letGo();
+ void tick();
+ void project(const physx::PxVec3& v, int& xi, int& yi, float& depth) const;
+
+#ifdef VISUALIZE_PICKING_RAYS
+ struct Ray
+ {
+ PxVec3 origin;
+ PxVec3 dir;
+ };
+ PX_FORCE_INLINE const std::vector<Ray>& getRays() const { return mRays; }
+#endif
+
+ private:
+ void grabActor(const PxVec3& worldImpact, const PxVec3& rayOrigin);
+ void moveActor(int x, int y);
+ PxVec3 unProject( int x, int y, float depth) const;
+
+ PxActor* mSelectedActor;
+
+#if USE_D6_JOINT_FOR_MOUSE
+ PxD6Joint* mMouseJoint; // was PxDistanceJoint, PxSphericalJoint, PxD6Joint
+#elif USE_SPHERICAL_JOINT_FOR_MOUSE
+ PxSphericalJoint* mMouseJoint;
+#else
+ PxDistanceJoint* mMouseJoint;
+#endif
+ PxRigidDynamic* mMouseActor;
+ PxRigidDynamic* mMouseActorToDelete;
+ PxReal mDistanceToPicked;
+ int mMouseScreenX, mMouseScreenY;
+ PhysXSample& mFrame;
+#ifdef VISUALIZE_PICKING_RAYS
+ std::vector<Ray> mRays;
+#endif
+ };
+}
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/RawLoader.cpp b/PhysX_3.4/Samples/SampleBase/RawLoader.cpp
new file mode 100644
index 00000000..05151a8d
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RawLoader.cpp
@@ -0,0 +1,415 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+// PT: this file is a loader for "raw" binary files. It should NOT create SDK objects directly.
+
+#include <stdio.h>
+#include "foundation/PxPreprocessor.h"
+#include "RawLoader.h"
+#include "RendererColor.h"
+#include "RendererMemoryMacros.h"
+#include "SampleAllocatorSDKClasses.h"
+#include "PxTkFile.h"
+
+using namespace SampleRenderer;
+
+RAWObject::RAWObject() : mName(NULL)
+{
+ mTransform = PxTransform(PxIdentity);
+}
+
+RAWTexture::RAWTexture() :
+ mID (0xffffffff),
+ mWidth (0),
+ mHeight (0),
+ mHasAlpha (false),
+ mPixels (NULL)
+{
+}
+
+RAWMesh::RAWMesh() :
+ mNbVerts (0),
+ mNbFaces (0),
+ mMaterialID (0xffffffff),
+ mVerts (NULL),
+ mVertexNormals (NULL),
+ mVertexColors (NULL),
+ mUVs (NULL),
+ mIndices (NULL)
+{
+}
+
+RAWShape::RAWShape() :
+ mNbVerts (0),
+ mVerts (NULL)
+{
+}
+
+RAWHelper::RAWHelper()
+{
+}
+
+RAWMaterial::RAWMaterial() :
+ mID (0xffffffff),
+ mDiffuseID (0xffffffff),
+ mOpacity (1.0f),
+ mDoubleSided (false)
+{
+ mAmbientColor = PxVec3(0);
+ mDiffuseColor = PxVec3(0);
+ mSpecularColor = PxVec3(0);
+}
+
+#if PX_INTEL_FAMILY
+ static const bool gFlip = false;
+#elif PX_PPC
+ static const bool gFlip = true;
+#elif PX_ARM_FAMILY
+ static const bool gFlip = false;
+#else
+ #error Unknown platform!
+#endif
+
+ PX_INLINE void Flip(PxU32& v)
+ {
+ PxU8* b = (PxU8*)&v;
+
+ PxU8 temp = b[0];
+ b[0] = b[3];
+ b[3] = temp;
+ temp = b[1];
+ b[1] = b[2];
+ b[2] = temp;
+ }
+
+ PX_INLINE void Flip(PxI32& v)
+ {
+ Flip((PxU32&)v);
+ }
+
+ PX_INLINE void Flip(PxF32& v)
+ {
+ Flip((PxU32&)v);
+ }
+
+static PxU8 read8(File* fp)
+{
+ PxU8 data;
+ size_t numRead = fread(&data, 1, 1, fp);
+ if(numRead != 1) { return 0; }
+ return data;
+}
+
+static PxU32 read32(File* fp)
+{
+ PxU32 data;
+ size_t numRead = fread(&data, 1, 4, fp);
+ if(numRead != 4) { return 0; }
+ if(gFlip)
+ Flip(data);
+ return data;
+}
+
+static PxF32 readFloat(File* fp)
+{
+ PxF32 data;
+ size_t numRead = fread(&data, 1, 4, fp);
+ if(numRead != 4) { return 0; }
+ if(gFlip)
+ Flip(data);
+ return data;
+}
+
+static PxTransform readTransform(File* fp, PxReal scale)
+{
+ PxTransform tr;
+ tr.p.x = scale * readFloat(fp);
+ tr.p.y = scale * readFloat(fp);
+ tr.p.z = scale * readFloat(fp);
+
+ tr.q.x = readFloat(fp);
+ tr.q.y = readFloat(fp);
+ tr.q.z = readFloat(fp);
+ tr.q.w = readFloat(fp);
+
+ PX_ASSERT(tr.isValid());
+
+ return tr;
+}
+
+static void readVertexArray(File* fp, PxVec3* verts, PxU32 nbVerts)
+{
+ const size_t size = 4*3*nbVerts;
+ size_t numRead = fread(verts, 1, size, fp);
+ if(numRead != size) { return; }
+
+ if(gFlip)
+ {
+ for(PxU32 j=0;j<nbVerts;j++)
+ {
+ Flip(verts[j].x);
+ Flip(verts[j].y);
+ Flip(verts[j].z);
+ }
+ }
+}
+
+static void readUVs(File* fp, PxReal* uvs, PxU32 nbVerts)
+{
+ const size_t size = 4*2*nbVerts;
+ size_t numRead = fread(uvs, 1, size, fp);
+ if(numRead != size) { return; }
+
+ if(gFlip)
+ {
+ for(PxU32 j=0;j<nbVerts*2;j++)
+ Flip(uvs[j]);
+ }
+}
+
+static void readVertices(File* fp, PxVec3* verts, PxU32 nbVerts, PxReal scale)
+{
+ readVertexArray(fp, verts, nbVerts);
+
+ for(PxU32 j=0;j<nbVerts;j++)
+ verts[j] *= scale;
+}
+
+static void readNormals(File* fp, PxVec3* verts, PxU32 nbVerts)
+{
+ readVertexArray(fp, verts, nbVerts);
+}
+
+static void readVertexColors(File* fp, PxVec3* colors, PxU32 nbVerts)
+{
+ readVertexArray(fp, colors, nbVerts);
+}
+
+static void readName(File* fp, char* objectName)
+{
+ PxU32 offset=0;
+ char c;
+ do
+ {
+ size_t numRead = fread(&c, 1, 1, fp);
+ if(numRead != 1) { c = '\0';}
+ objectName[offset++] = c;
+ }while(c);
+ objectName[offset]=0;
+}
+
+bool loadRAWfile(const char* filename, RAWImportCallback& cb, PxReal scale)
+{
+ File* fp = NULL;
+ PxToolkit::fopen_s(&fp, filename, "rb");
+ if(!fp)
+ return false;
+
+ // General info
+ const PxU32 tag = read32(fp);
+ const PxU32 generalVersion = read32(fp);
+ const PxU32 nbMaterials = read32(fp);
+ const PxU32 nbTextures = read32(fp);
+ const PxU32 nbMeshes = read32(fp);
+ const PxU32 nbShapes = read32(fp);
+ const PxU32 nbHelpers = read32(fp);
+
+ (void)tag;
+ (void)generalVersion;
+ char objectName[512];
+
+ // Textures
+ for(PxU32 i=0;i<nbTextures;i++)
+ {
+ RAWTexture data;
+
+ readName(fp, objectName);
+ data.mName = objectName;
+ data.mTransform = PxTransform(PxIdentity); // PT: texture transform not supported yet
+ data.mID = read32(fp);
+
+ RendererColorAlloc* pixels = NULL;
+ if(read8(fp))
+ {
+ data.mWidth = read32(fp);
+ data.mHeight = read32(fp);
+ data.mHasAlpha = read8(fp)!=0;
+ const PxU32 nbPixels = data.mWidth*data.mHeight;
+ pixels = SAMPLE_NEW(RendererColorAlloc)[nbPixels];
+ data.mPixels = pixels;
+ for(PxU32 i=0;i<nbPixels;i++)
+ {
+ pixels[i].r = read8(fp);
+ pixels[i].g = read8(fp);
+ pixels[i].b = read8(fp);
+ if(data.mHasAlpha)
+ pixels[i].a = read8(fp);
+ else
+ pixels[i].a = 0xff;
+ }
+ }
+ else
+ {
+ data.mWidth = 0;
+ data.mHeight = 0;
+ data.mHasAlpha = false;
+ data.mPixels = NULL;
+ }
+
+ cb.newTexture(data);
+ DELETEARRAY(pixels);
+ }
+
+ // Materials
+ for(PxU32 i=0;i<nbMaterials;i++)
+ {
+ RAWMaterial data;
+ data.mID = read32(fp);
+ data.mDiffuseID = read32(fp);
+ data.mOpacity = readFloat(fp);
+ data.mDoubleSided = read32(fp)!=0;
+
+ data.mAmbientColor.x = readFloat(fp);
+ data.mAmbientColor.y = readFloat(fp);
+ data.mAmbientColor.z = readFloat(fp);
+
+ data.mDiffuseColor.x = readFloat(fp);
+ data.mDiffuseColor.y = readFloat(fp);
+ data.mDiffuseColor.z = readFloat(fp);
+
+ data.mSpecularColor.x = readFloat(fp);
+ data.mSpecularColor.y = readFloat(fp);
+ data.mSpecularColor.z = readFloat(fp);
+
+ cb.newMaterial(data);
+ }
+
+ // Meshes
+ for(PxU32 i=0;i<nbMeshes;i++)
+ {
+ RAWMesh data;
+
+ readName(fp, objectName);
+ data.mName = objectName;
+ data.mTransform = readTransform(fp, scale);
+ //
+ data.mNbVerts = read32(fp);
+ data.mNbFaces = read32(fp);
+ const PxU32 hasVertexColors = read32(fp);
+ const PxU32 hasUVs = read32(fp);
+ data.mMaterialID = read32(fp);
+
+ PxVec3Alloc* tmpVerts = SAMPLE_NEW(PxVec3Alloc)[data.mNbVerts];
+ PxVec3Alloc* tmpNormals = SAMPLE_NEW(PxVec3Alloc)[data.mNbVerts];
+ PxVec3Alloc* tmpColors = NULL;
+ PxReal* tmpUVs = NULL;
+
+ data.mVerts = tmpVerts;
+ data.mVertexNormals = tmpNormals;
+ data.mVertexColors = NULL;
+ data.mUVs = NULL;
+
+ readVertices(fp, tmpVerts, data.mNbVerts, scale);
+ readNormals(fp, tmpNormals, data.mNbVerts);
+
+ if(hasVertexColors)
+ {
+ tmpColors = SAMPLE_NEW(PxVec3Alloc)[data.mNbVerts];
+ data.mVertexColors = tmpColors;
+ readVertexColors(fp, tmpColors, data.mNbVerts);
+ }
+
+ if(hasUVs)
+ {
+ tmpUVs = (PxReal*)SAMPLE_ALLOC(sizeof(PxReal)*data.mNbVerts*2);
+ data.mUVs = tmpUVs;
+ readUVs(fp, tmpUVs, data.mNbVerts);
+ }
+
+ PxU32* tmpIndices = (PxU32*)SAMPLE_ALLOC(sizeof(PxU32)*data.mNbFaces*3);
+ data.mIndices = tmpIndices;
+ const size_t size = 4*3*data.mNbFaces;
+ size_t numRead = fread(tmpIndices, 1, size, fp);
+ if(numRead != size)
+ {
+ SAMPLE_FREE(tmpIndices);
+ SAMPLE_FREE(tmpUVs);
+ DELETEARRAY(tmpColors);
+ DELETEARRAY(tmpNormals);
+ DELETEARRAY(tmpVerts);
+ return false;
+ }
+ if(gFlip)
+ {
+ for(PxU32 j=0;j<data.mNbFaces*3;j++)
+ {
+ Flip(tmpIndices[j]);
+ }
+ }
+
+ cb.newMesh(data);
+
+ SAMPLE_FREE(tmpIndices);
+ SAMPLE_FREE(tmpUVs);
+ DELETEARRAY(tmpColors);
+ DELETEARRAY(tmpNormals);
+ DELETEARRAY(tmpVerts);
+ }
+
+ // Shapes
+ for(PxU32 i=0;i<nbShapes;i++)
+ {
+ RAWShape data;
+
+ readName(fp, objectName);
+ data.mName = objectName;
+ data.mTransform = readTransform(fp, scale);
+ //
+ data.mNbVerts = read32(fp);
+ PxVec3Alloc* tmp = SAMPLE_NEW(PxVec3Alloc)[data.mNbVerts];
+ data.mVerts = tmp;
+ readVertices(fp, tmp, data.mNbVerts, scale);
+
+ cb.newShape(data);
+
+ DELETEARRAY(tmp);
+ }
+
+ // Helpers
+ for(PxU32 i=0;i<nbHelpers;i++)
+ {
+ RAWHelper data;
+
+ readName(fp, objectName);
+ data.mName = objectName;
+ data.mTransform = readTransform(fp, scale);
+ }
+ return true;
+}
diff --git a/PhysX_3.4/Samples/SampleBase/RawLoader.h b/PhysX_3.4/Samples/SampleBase/RawLoader.h
new file mode 100644
index 00000000..f33e99d8
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RawLoader.h
@@ -0,0 +1,120 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef RAW_LOADER_H
+#define RAW_LOADER_H
+
+#include "SampleAllocator.h"
+#include "foundation/PxTransform.h"
+
+namespace SampleRenderer
+{
+ class RendererColor;
+}
+
+ class RAWObject : public SampleAllocateable
+ {
+ public:
+ RAWObject();
+
+ const char* mName;
+ PxTransform mTransform;
+ };
+
+ class RAWTexture : public RAWObject
+ {
+ public:
+ RAWTexture();
+
+ PxU32 mID;
+ PxU32 mWidth;
+ PxU32 mHeight;
+ bool mHasAlpha;
+ const SampleRenderer::RendererColor* mPixels;
+ };
+
+ class RAWMesh : public RAWObject
+ {
+ public:
+ RAWMesh();
+
+ PxU32 mNbVerts;
+ PxU32 mNbFaces;
+ PxU32 mMaterialID;
+ const PxVec3* mVerts;
+ const PxVec3* mVertexNormals;
+ const PxVec3* mVertexColors;
+ const PxReal* mUVs;
+ const PxU32* mIndices;
+ };
+
+ class RAWShape : public RAWObject
+ {
+ public:
+ RAWShape();
+
+ PxU32 mNbVerts;
+ const PxVec3* mVerts;
+ };
+
+ class RAWHelper : public RAWObject
+ {
+ public:
+ RAWHelper();
+ };
+
+ class RAWMaterial : public SampleAllocateable
+ {
+ public:
+ RAWMaterial();
+
+ PxU32 mID;
+ PxU32 mDiffuseID;
+ PxReal mOpacity;
+ PxVec3 mAmbientColor;
+ PxVec3 mDiffuseColor;
+ PxVec3 mSpecularColor;
+ bool mDoubleSided;
+ };
+
+ class RAWImportCallback
+ {
+ public:
+ virtual ~RAWImportCallback() {}
+ virtual void newMaterial(const RAWMaterial&) = 0;
+ virtual void newMesh(const RAWMesh&) = 0;
+ virtual void newShape(const RAWShape&) = 0;
+ virtual void newHelper(const RAWHelper&) = 0;
+ virtual void newTexture(const RAWTexture&) = 0;
+ };
+
+ bool loadRAWfile(const char* filename, RAWImportCallback& cb, PxReal scale);
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/RaycastCCD.cpp b/PhysX_3.4/Samples/SampleBase/RaycastCCD.cpp
new file mode 100644
index 00000000..075d97e8
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RaycastCCD.cpp
@@ -0,0 +1,252 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "RaycastCCD.h"
+
+#include "geometry/PxBoxGeometry.h"
+#include "geometry/PxSphereGeometry.h"
+#include "geometry/PxCapsuleGeometry.h"
+#include "geometry/PxConvexMeshGeometry.h"
+#include "geometry/PxConvexMesh.h"
+#include "PxQueryReport.h"
+#include "PxScene.h"
+#include "PxRigidDynamic.h"
+#include "extensions/PxShapeExt.h"
+#include <stdio.h>
+
+//#define RAYCAST_CCD_PRINT_DEBUG
+
+PxVec3 getShapeCenter(PxRigidActor* actor, PxShape* shape, const PxVec3& localOffset)
+{
+ PxVec3 offset = localOffset;
+
+ switch(shape->getGeometryType())
+ {
+ case PxGeometryType::eCONVEXMESH:
+ {
+ PxConvexMeshGeometry geometry;
+ bool status = shape->getConvexMeshGeometry(geometry);
+ PX_UNUSED(status);
+ PX_ASSERT(status);
+
+ PxReal mass;
+ PxMat33 localInertia;
+ PxVec3 localCenterOfMass;
+ geometry.convexMesh->getMassInformation(mass, localInertia, localCenterOfMass);
+
+ offset += localCenterOfMass;
+ }
+ break;
+ default:
+ break;
+ }
+ const PxTransform pose = PxShapeExt::getGlobalPose(*shape, *actor);
+ return pose.transform(offset);
+}
+
+static PxReal computeInternalRadius(PxRigidActor* actor, PxShape* shape, const PxVec3& dir, /*PxVec3& offset,*/ const PxVec3& centerOffset)
+{
+ const PxBounds3 bounds = PxShapeExt::getWorldBounds(*shape, *actor);
+ const PxReal diagonal = (bounds.maximum - bounds.minimum).magnitude();
+ const PxReal offsetFromOrigin = diagonal * 2.0f;
+
+ PxTransform pose = PxShapeExt::getGlobalPose(*shape, *actor);
+
+ PxReal internalRadius = 0.0f;
+ const PxReal length = offsetFromOrigin*2.0f;
+
+ // PT: we do a switch here anyway since the code is not *exactly* the same all the time
+ {
+ switch(shape->getGeometryType())
+ {
+ case PxGeometryType::eBOX:
+ case PxGeometryType::eCAPSULE:
+ {
+ pose.p = PxVec3(0);
+ const PxVec3 virtualOrigin = pose.p + dir * offsetFromOrigin;
+
+ PxRaycastHit hit;
+
+ const PxHitFlags sceneQueryFlags = PxHitFlag::ePOSITION|PxHitFlag::eNORMAL|PxHitFlag::eDISTANCE;
+ PxU32 nbHits = PxGeometryQuery::raycast(virtualOrigin, -dir, shape->getGeometry().any(), pose, length, sceneQueryFlags, 1, &hit);
+ PX_UNUSED(nbHits);
+ PX_ASSERT(nbHits);
+
+ internalRadius = offsetFromOrigin - hit.distance;
+ // offset = PxVec3(0.0f);
+ }
+ break;
+
+ case PxGeometryType::eSPHERE:
+ {
+ PxSphereGeometry geometry;
+ bool status = shape->getSphereGeometry(geometry);
+ PX_UNUSED(status);
+ PX_ASSERT(status);
+
+ internalRadius = geometry.radius;
+ // offset = PxVec3(0.0f);
+ }
+ break;
+
+ case PxGeometryType::eCONVEXMESH:
+ {
+ /*PxVec3 saved = pose.p;
+ pose.p = PxVec3(0);
+
+ // pose.p = geometry.convexMesh->getCenterOfMass();
+ // const PxVec3 virtualOrigin = pose.p + dir * offsetFromOrigin;
+
+ // const PxVec3 localCenter = computeCenter(geometry.convexMesh);
+ // const PxVec3 localCenter = geometry.convexMesh->getCenterOfMass();
+ // const PxVec3 virtualOrigin = pose.rotate(localCenter) + dir * offsetFromOrigin;
+ const PxVec3 localCenter = pose.rotate(geometry.convexMesh->getCenterOfMass());
+ const PxVec3 virtualOrigin = localCenter + dir * offsetFromOrigin;
+
+ PxRaycastHit hit;
+ PxU32 nbHits = Gu::raycast_convexMesh(geometry, pose, virtualOrigin, -dir, length, 0xffffffff, 1, &hit);
+ PX_ASSERT(nbHits);
+ internalRadius = offsetFromOrigin - hit.distance;
+
+ pose.p = localCenter;
+
+ PxVec3 shapeCenter = getShapeCenter(shape);
+ offset = shapeCenter - saved;*/
+
+
+ PxVec3 shapeCenter = getShapeCenter(actor, shape, centerOffset);
+ shapeCenter -= pose.p;
+ pose.p = PxVec3(0);
+
+ const PxVec3 virtualOrigin = shapeCenter + dir * offsetFromOrigin;
+ PxRaycastHit hit;
+ const PxHitFlags sceneQueryFlags = PxHitFlag::ePOSITION|PxHitFlag::eNORMAL|PxHitFlag::eDISTANCE;
+ PxU32 nbHits = PxGeometryQuery::raycast(virtualOrigin, -dir, shape->getGeometry().any(), pose, length, sceneQueryFlags, 1, &hit);
+ PX_UNUSED(nbHits);
+ PX_ASSERT(nbHits);
+
+ internalRadius = offsetFromOrigin - hit.distance;
+ // offset = shapeCenter;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return internalRadius;
+}
+
+static bool CCDRaycast(PxScene* scene, const PxVec3& origin, const PxVec3& unitDir, const PxReal distance, PxRaycastHit& hit)
+{
+ const PxHitFlags outputFlags = PxHitFlag::ePOSITION|PxHitFlag::eNORMAL|PxHitFlag::eDISTANCE;
+
+ PxQueryFilterData filterData;
+ filterData.flags = PxQueryFlag::eSTATIC;
+
+ PxQueryFilterCallback* filterCall = NULL;
+
+ PxRaycastBuffer buf1;
+ scene->raycast(origin, unitDir, distance, buf1, outputFlags, filterData, filterCall, NULL);
+ hit = buf1.block;
+ return buf1.hasBlock;
+}
+
+static PxRigidDynamic* canDoCCD(PxRigidActor& actor, PxShape* shape)
+{
+ PxRigidDynamic* dyna = actor.is<PxRigidDynamic>();
+ if(!dyna)
+ return NULL; // PT: no need to do it for statics
+
+ const PxU32 nbShapes = dyna->getNbShapes();
+ if(nbShapes!=1)
+ return NULL; // PT: only works with simple actors for now
+
+ if(dyna->getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC)
+ return NULL; // PT: no need to do it for kinematics
+
+ return dyna;
+}
+
+bool doRaycastCCD(PxRigidActor* actor, PxShape* shape, PxTransform& newPose, PxVec3& newShapeCenter, const PxVec3& ccdWitness, const PxVec3& ccdWitnessOffset)
+{
+ PxRigidDynamic* dyna = canDoCCD(*actor, shape);
+ if(!dyna)
+ return true;
+
+ bool updateCCDWitness = true;
+
+ const PxVec3 offset = newPose.p - newShapeCenter;
+ const PxVec3& origin = ccdWitness;
+ const PxVec3& dest = newShapeCenter;
+
+ PxVec3 dir = dest - origin;
+ const PxReal length = dir.magnitude();
+ if(length!=0.0f)
+ {
+ dir /= length;
+
+ // Compute internal radius
+ const PxReal internalRadius = computeInternalRadius(actor, shape, dir, ccdWitnessOffset);
+
+ // Compute distance to impact
+ PxRaycastHit hit;
+ if(internalRadius!=0.0f && CCDRaycast(actor->getScene(), origin, dir, length, hit))
+ {
+#ifdef RAYCAST_CCD_PRINT_DEBUG
+ static int count=0;
+ shdfnd::printFormatted("CCD hit %d\n", count++);
+#endif
+ updateCCDWitness = false;
+ const PxReal radiusLimit = internalRadius * 0.75f;
+ if(hit.distance>radiusLimit)
+ {
+ newShapeCenter = origin + dir * (hit.distance - radiusLimit);
+#ifdef RAYCAST_CCD_PRINT_DEBUG
+ shdfnd::printFormatted(" Path0: %f | %f\n", hit.distance, radiusLimit);
+#endif
+ }
+ else
+ {
+ newShapeCenter = origin;
+#ifdef RAYCAST_CCD_PRINT_DEBUG
+ shdfnd::printFormatted(" Path1: %f\n", hit.distance);
+#endif
+ }
+
+ {
+ newPose.p = offset + newShapeCenter;
+ const PxTransform shapeLocalPose = shape->getLocalPose();
+ const PxTransform inverseShapeLocalPose = shapeLocalPose.getInverse();
+ PxTransform newGlobalPose = newPose * inverseShapeLocalPose;
+ dyna->setGlobalPose(newGlobalPose);
+ }
+ }
+ }
+ return updateCCDWitness;
+}
diff --git a/PhysX_3.4/Samples/SampleBase/RaycastCCD.h b/PhysX_3.4/Samples/SampleBase/RaycastCCD.h
new file mode 100644
index 00000000..081eddf7
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RaycastCCD.h
@@ -0,0 +1,46 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef RAYCAST_CCD_H
+#define RAYCAST_CCD_H
+
+#include "common/PxPhysXCommonConfig.h"
+
+using namespace physx;
+
+namespace physx
+{
+ class PxShape;
+ class PxRigidActor;
+}
+
+ PxVec3 getShapeCenter(PxRigidActor* actor, PxShape* shape, const PxVec3& localOffset);
+ bool doRaycastCCD(PxRigidActor* actor, PxShape* shape, PxTransform& pose, PxVec3& newShapeCenter, const PxVec3& ccdWitness, const PxVec3& ccdWitnessOffset);
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/RenderBaseActor.cpp b/PhysX_3.4/Samples/SampleBase/RenderBaseActor.cpp
new file mode 100644
index 00000000..1813e0a3
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RenderBaseActor.cpp
@@ -0,0 +1,279 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SamplePreprocessor.h"
+#include "RenderBaseActor.h"
+#include "RenderMaterial.h"
+#include "RendererShape.h"
+#include "Renderer.h"
+#include "RendererMemoryMacros.h"
+#include "extensions/PxShapeExt.h"
+#include "RaycastCCD.h"
+#include "RenderPhysX3Debug.h"
+#include "PxRigidDynamic.h"
+#include "PxArticulationLink.h"
+
+#include "geometry/PxSphereGeometry.h"
+#include "geometry/PxBoxGeometry.h"
+#include "RenderSphereActor.h"
+#include "RenderCapsuleActor.h"
+
+using namespace physx;
+using namespace SampleRenderer;
+
+static const bool gRaycastCCD = true;
+
+RenderBaseActor::RenderBaseActor() :
+ mRendererShape (NULL),
+ mPhysicsShape (NULL),
+ mDynamicActor (NULL),
+ mArticulationLink (NULL),
+ mMaterial (NULL),
+ mEnableCCD (false),
+ mEnableRender (true),
+ mEnableDebugRender (true),
+ mEnableCameraCull (false)
+{
+ mTransform = PxTransform(PxIdentity);
+ mWorldBounds = PxBounds3(PxVec3(0),PxVec3(0));
+
+ mCCDWitness = PxVec3(0);
+ mCCDWitnessOffset = PxVec3(0);
+
+ mPhysicsToGraphicsRot = PxQuat(PxIdentity);
+
+ updateScale();
+}
+
+RenderBaseActor::RenderBaseActor(const RenderBaseActor& src) : RenderBaseObject(src)
+{
+ mEnableCCD = src.mEnableCCD;
+ mEnableRender = src.mEnableRender;
+ mEnableDebugRender = src.mEnableDebugRender;
+ mEnableCameraCull = src.mEnableCameraCull;
+
+ mTransform = src.getTransform();
+ mWorldBounds = PxBounds3(PxVec3(0.0f), PxVec3(0.0f));
+ mPhysicsShape = NULL; // PT: the physics shape is not cloned for now
+ mDynamicActor = NULL; // PT: the physics actor is not cloned for now
+ mArticulationLink = NULL; // PT: the articulation link is not cloned for now
+ mMaterial = src.getRenderMaterial();
+ mRendererShape = NULL;
+ setRenderShape(src.getRenderShape());
+
+ mPhysicsToGraphicsRot = src.mPhysicsToGraphicsRot;
+ mCCDWitness = src.mCCDWitness;
+ mCCDWitnessOffset = src.mCCDWitnessOffset;
+
+ mScaling = src.mScaling;
+
+ updateScale();
+}
+
+RenderBaseActor::~RenderBaseActor()
+{
+ deleteRenderShape();
+ mMaterial = NULL; // PT: we don't own this
+ mPhysicsShape = NULL; // PT: we don't own this
+ mDynamicActor = NULL; // PT: we don't own this
+}
+
+void RenderBaseActor::update(float deltaTime)
+{
+ // Setup render transform from physics transform, if physics object exists
+ if(mPhysicsShape)
+ {
+ if(!mArticulationLink && ( !mDynamicActor || mDynamicActor->isSleeping()))
+ return;
+
+ PxTransform newPose = PxShapeExt::getGlobalPose(*mPhysicsShape, *mPhysicsActor);
+ PxVec3 newShapeCenter = getShapeCenter(mPhysicsActor, mPhysicsShape, mCCDWitnessOffset);
+
+ bool updateCCDWitness = true;
+ if(gRaycastCCD && mEnableCCD)
+ updateCCDWitness = doRaycastCCD(mPhysicsActor, mPhysicsShape, newPose, newShapeCenter, mCCDWitness, mCCDWitnessOffset);
+
+ // Copy physics pose to graphics pose
+ setTransform(PxTransform(newPose.p, newPose.q * mPhysicsToGraphicsRot));
+
+ if(updateCCDWitness)
+ mCCDWitness = newShapeCenter;
+
+ setWorldBounds(PxShapeExt::getWorldBounds(*mPhysicsShape, *mPhysicsActor));
+ }
+}
+
+void RenderBaseActor::render(Renderer& renderer, RenderMaterial* material, bool wireFrame)
+{
+ if(!mEnableRender)
+ return;
+
+ RenderMaterial* m = mMaterial ? mMaterial : material;
+ PX_ASSERT(m);
+
+ mRendererMeshContext.cullMode = m->mDoubleSided ? RendererMeshContext::NONE : RendererMeshContext::CLOCKWISE;
+ mRendererMeshContext.fillMode = wireFrame ? RendererMeshContext::LINE : RendererMeshContext::SOLID;
+ mRendererMeshContext.material = m->mRenderMaterial;
+ mRendererMeshContext.materialInstance = m->mRenderMaterialInstance;
+ mRendererMeshContext.mesh = mRendererShape->getMesh();
+ mRendererMeshContext.transform = &mScaledTransform;
+
+ renderer.queueMeshForRender(mRendererMeshContext);
+}
+
+PxBounds3 RenderBaseActor::getWorldBounds() const
+{
+ return mWorldBounds;
+}
+
+void RenderBaseActor::setWorldBounds(const PxBounds3& bounds)
+{
+ mWorldBounds = bounds;
+}
+
+void RenderBaseActor::updateScale()
+{
+ if (!mScaling.isIdentity())
+ {
+ PxMat33 q = PxMat33(mTransform.q) * mScaling.toMat33();
+ mScaledTransform = PxMat44(q, mTransform.p);
+ mRendererMeshContext.negativeScale = mScaling.hasNegativeDeterminant();
+ }
+ else
+ {
+ mScaledTransform = PxMat44(mTransform);
+ }
+}
+
+void RenderBaseActor::setPhysicsShape(PxShape* shape, PxRigidActor* actor)
+{
+ mPhysicsShape = shape;
+ mPhysicsActor = actor;
+
+ if(shape)
+ {
+ mCCDWitness = getShapeCenter(actor, shape, mCCDWitnessOffset);
+
+ const PxTransform newPose = PxShapeExt::getGlobalPose(*shape, *actor);
+ setTransform(PxTransform(newPose.p, newPose.q * mPhysicsToGraphicsRot));
+
+ PxRigidActor& ra = *actor;
+ mDynamicActor = ra.is<PxRigidDynamic>();
+ mArticulationLink = ra.is<PxArticulationLink>();
+ mWorldBounds = PxShapeExt::getWorldBounds(*mPhysicsShape, *mPhysicsActor);
+ }
+ else
+ {
+ mDynamicActor = NULL;
+ }
+}
+
+void RenderBaseActor::setRenderMaterial(RenderMaterial* material)
+{
+ mMaterial = material;
+}
+
+void RenderBaseActor::setRenderShape(RendererShape* shape)
+{
+ PX_ASSERT(!mRendererShape);
+ mRendererShape = shape;
+
+ if(shape)
+ {
+ // PT: we use the user-data as a ref-counter
+ size_t refCount = size_t(mRendererShape->m_userData);
+ refCount++;
+ mRendererShape->m_userData = (void*)refCount;
+ }
+}
+
+void RenderBaseActor::deleteRenderShape()
+{
+ if(mRendererShape)
+ {
+ // PT: we use the user-data as a ref-counter
+ size_t refCount = size_t(mRendererShape->m_userData);
+ refCount--;
+ if(!refCount)
+ {
+ DELETESINGLE(mRendererShape);
+ }
+ else
+ {
+ mRendererShape->m_userData = (void*)refCount;
+ mRendererShape = NULL;
+ }
+ }
+}
+
+void RenderBaseActor::drawDebug(RenderPhysX3Debug* debug)
+{
+// return;
+
+ if(!mPhysicsShape)
+ return;
+
+ if(0 && mEnableCCD)
+ {
+ const PxBounds3 bounds = PxShapeExt::getWorldBounds(*mPhysicsShape, *mPhysicsActor);
+ const PxReal scale = (bounds.maximum - bounds.minimum).magnitude();
+
+ const PxTransform pose = PxShapeExt::getGlobalPose(*mPhysicsShape, *mPhysicsActor);
+ debug->addLine(pose.p, pose.p+PxVec3(scale, 0.0f, 0.0f), RendererColor(0, 255, 0));
+ debug->addLine(pose.p, pose.p+PxVec3(0.0f, scale, 0.0f), RendererColor(0, 255, 0));
+ debug->addLine(pose.p, pose.p+PxVec3(0.0f, 0.0f, scale), RendererColor(0, 255, 0));
+
+ const PxVec3 shapeCenter = getShapeCenter(mPhysicsActor, mPhysicsShape, mCCDWitnessOffset);
+//shdfnd::printFormatted("Render: %f | %f | %f\n", shapeCenter.x, shapeCenter.y, shapeCenter.z);
+
+ debug->addLine(shapeCenter, shapeCenter+PxVec3(scale, 0.0f, 0.0f), RendererColor(255, 0, 0));
+ debug->addLine(shapeCenter, shapeCenter+PxVec3(0.0f, scale, 0.0f), RendererColor(255, 0, 0));
+ debug->addLine(shapeCenter, shapeCenter+PxVec3(0.0f, 0.0f, scale), RendererColor(255, 0, 0));
+ return;
+ }
+
+/*
+ BasicRandom rnd(42);
+
+ const PxTransform globalShapePose = PxShapeExt::getGlobalPose(*mPhysicsShape);
+
+ const RendererColor colorPurple(255, 0, 255);
+ for(PxU32 i=0;i<50;i++)
+ {
+ PxVec3 dir;
+ rnd.unitRandomPt(dir);
+
+ PxVec3 localCenter;
+ const PxReal internalRadius = computeInternalRadius(mPhysicsShape, dir, localCenter, mCCDWitnessOffset);
+
+ const PxVec3 center = globalShapePose.transform(localCenter);
+
+ debug->addLine(center, center+dir*internalRadius, colorPurple);
+ }*/
+}
diff --git a/PhysX_3.4/Samples/SampleBase/RenderBaseActor.h b/PhysX_3.4/Samples/SampleBase/RenderBaseActor.h
new file mode 100644
index 00000000..bac9a015
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RenderBaseActor.h
@@ -0,0 +1,126 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef RENDER_BASE_ACTOR_H
+#define RENDER_BASE_ACTOR_H
+
+#include "RendererMeshContext.h"
+#include "common/PxPhysXCommonConfig.h"
+#include "RenderBaseObject.h"
+#include "geometry/PxMeshScale.h"
+#include "foundation/PxBounds3.h"
+
+namespace SampleRenderer
+{
+ class RendererShape;
+}
+
+ class RenderMaterial;
+
+namespace physx
+{
+ class PxShape;
+ class PxRigidActor;
+ class PxRigidDynamic;
+ class PxArticulationLink;
+ class PxMeshScale;
+}
+
+ class RenderPhysX3Debug;
+
+ class RenderBaseActor : public RenderBaseObject
+ {
+ public:
+ RenderBaseActor();
+ RenderBaseActor(const RenderBaseActor&);
+ virtual ~RenderBaseActor();
+
+ virtual void update(float deltaTime);
+ virtual void render(SampleRenderer::Renderer& renderer, RenderMaterial* material=NULL, bool wireFrame = false);
+ virtual void drawDebug(RenderPhysX3Debug*);
+
+ PX_FORCE_INLINE void setTransform(const PxTransform& tr) { mTransform = tr; updateScale(); }
+ PX_FORCE_INLINE void setMeshScale(const PxMeshScale& scaling){ mScaling = scaling; updateScale(); }
+ void setPhysicsShape(PxShape* shape, PxRigidActor* actor);
+ void setRenderMaterial(RenderMaterial*);
+
+ PX_FORCE_INLINE const PxTransform& getTransform() const { return mTransform; }
+ PX_FORCE_INLINE PxShape* getPhysicsShape() const { return mPhysicsShape; }
+ PX_FORCE_INLINE PxRigidActor* getPhysicsActor() const { return mPhysicsActor; }
+ PX_FORCE_INLINE SampleRenderer::RendererShape* getRenderShape() { return mRendererShape; }
+ PX_FORCE_INLINE SampleRenderer::RendererShape* getRenderShape() const { return mRendererShape; }
+ PX_FORCE_INLINE RenderMaterial* getRenderMaterial() { return mMaterial; }
+ PX_FORCE_INLINE RenderMaterial* getRenderMaterial() const { return mMaterial; }
+
+ PxBounds3 getWorldBounds() const;
+ void setWorldBounds(const PxBounds3& bounds);
+
+ PX_FORCE_INLINE void setRaycastCCD(bool flag) { mEnableCCD = flag; }
+ PX_FORCE_INLINE void setCCDWitnessOffset(const PxVec3& offset) { mCCDWitnessOffset = offset; }
+
+ PX_FORCE_INLINE void setRendering(bool flag) { mEnableRender = flag; }
+
+ PX_FORCE_INLINE void setEnableDebugRender(bool flag) { mEnableDebugRender = flag; }
+ PX_FORCE_INLINE bool getEnableDebugRender() const { return mEnableDebugRender; }
+
+ PX_FORCE_INLINE void setEnableCameraCull(bool flag) { mEnableCameraCull = flag; }
+ PX_FORCE_INLINE bool getEnableCameraCull() const { return mEnableCameraCull; }
+
+ private:
+ SampleRenderer::RendererShape* mRendererShape;
+ PxMeshScale mScaling;
+ PxTransform mTransform;
+ PxBounds3 mWorldBounds;
+
+ protected:
+
+ SampleRenderer::RendererMeshContext mRendererMeshContext;
+ PxMat44 mScaledTransform;
+ PxQuat mPhysicsToGraphicsRot;
+
+ PxShape* mPhysicsShape;
+ PxRigidActor* mPhysicsActor;
+ PxRigidDynamic* mDynamicActor;
+ PxArticulationLink* mArticulationLink;
+ RenderMaterial* mMaterial;
+
+ PxVec3 mCCDWitness;
+ PxVec3 mCCDWitnessOffset;
+ bool mEnableCCD;
+ bool mEnableRender;
+ bool mEnableDebugRender;
+ bool mEnableCameraCull;
+ protected:
+ void setRenderShape(SampleRenderer::RendererShape*);
+ void deleteRenderShape();
+ private:
+ void updateScale();
+ };
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/RenderBaseObject.cpp b/PhysX_3.4/Samples/SampleBase/RenderBaseObject.cpp
new file mode 100644
index 00000000..d47aba37
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RenderBaseObject.cpp
@@ -0,0 +1,52 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "RenderBaseObject.h"
+#include <string.h>
+
+RenderBaseObject::RenderBaseObject()
+ : mActive(true)
+ , mUserData (NULL)
+{
+ mName[0] = 0;
+}
+
+RenderBaseObject::RenderBaseObject(const RenderBaseObject& src)
+{
+ strcpy(mName, src.mName);
+}
+
+RenderBaseObject::~RenderBaseObject()
+{
+}
+
+void RenderBaseObject::release()
+{
+ delete this;
+}
diff --git a/PhysX_3.4/Samples/SampleBase/RenderBaseObject.h b/PhysX_3.4/Samples/SampleBase/RenderBaseObject.h
new file mode 100644
index 00000000..cd154bf1
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RenderBaseObject.h
@@ -0,0 +1,49 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef RENDER_BASE_OBJECT_H
+#define RENDER_BASE_OBJECT_H
+
+#include "SampleAllocator.h"
+
+ class RenderBaseObject : public SampleAllocateable
+ {
+ public:
+ RenderBaseObject();
+ RenderBaseObject(const RenderBaseObject&);
+ virtual ~RenderBaseObject();
+
+ virtual void release();
+
+ bool mActive;
+ void* mUserData;
+ char mName[512];
+ };
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/RenderBoxActor.cpp b/PhysX_3.4/Samples/SampleBase/RenderBoxActor.cpp
new file mode 100644
index 00000000..b5d8ed20
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RenderBoxActor.cpp
@@ -0,0 +1,48 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "RenderBoxActor.h"
+#include "RendererBoxShape.h"
+
+using namespace physx;
+using namespace SampleRenderer;
+
+RenderBoxActor::RenderBoxActor(Renderer& renderer, const PxVec3& extents, const PxReal* uvs)
+{
+ RendererShape* rs = new RendererBoxShape(renderer, extents, uvs);
+ setRenderShape(rs);
+}
+
+RenderBoxActor::RenderBoxActor(const RenderBoxActor& src) : RenderBaseActor(src)
+{
+}
+
+RenderBoxActor::~RenderBoxActor()
+{
+}
diff --git a/PhysX_3.4/Samples/SampleBase/RenderBoxActor.h b/PhysX_3.4/Samples/SampleBase/RenderBoxActor.h
new file mode 100644
index 00000000..af804bfa
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RenderBoxActor.h
@@ -0,0 +1,49 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef RENDER_BOX_ACTOR_H
+#define RENDER_BOX_ACTOR_H
+
+#include "RenderBaseActor.h"
+#include "foundation/PxVec3.h"
+
+namespace SampleRenderer
+{
+ class Renderer;
+}
+
+ class RenderBoxActor : public RenderBaseActor
+ {
+ public:
+ RenderBoxActor(SampleRenderer::Renderer& renderer, const PxVec3& extents, const PxReal* uvs=NULL);
+ RenderBoxActor(const RenderBoxActor&);
+ virtual ~RenderBoxActor();
+ };
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/RenderCapsuleActor.cpp b/PhysX_3.4/Samples/SampleBase/RenderCapsuleActor.cpp
new file mode 100644
index 00000000..afaa4e7d
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RenderCapsuleActor.cpp
@@ -0,0 +1,58 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "RenderCapsuleActor.h"
+#include "RendererCapsuleShape.h"
+#include "extensions/PxShapeExt.h"
+
+using namespace physx;
+using namespace SampleRenderer;
+
+RenderCapsuleActor::RenderCapsuleActor(Renderer& renderer, PxReal radius, PxReal halfHeight)
+{
+ RendererShape* rs = new RendererCapsuleShape(renderer, halfHeight, radius);
+ setRenderShape(rs);
+
+ // PT: seems there's a mismatch between the renderer's and the SDK's idea of what a default capsule pose should be
+ mPhysicsToGraphicsRot = PxQuat(PxHalfPi, PxVec3(0.0f, 0.0f, 1.0f));
+}
+
+void RenderCapsuleActor::setDimensions(PxReal halfHeight, PxReal radius0, PxReal radius1)
+{
+ RendererCapsuleShape* capsuleShape = static_cast<RendererCapsuleShape*>(getRenderShape());
+ capsuleShape->setDimensions(halfHeight, radius0, radius1);
+}
+
+RenderCapsuleActor::RenderCapsuleActor(const RenderCapsuleActor& src) : RenderBaseActor(src)
+{
+}
+
+RenderCapsuleActor::~RenderCapsuleActor()
+{
+}
diff --git a/PhysX_3.4/Samples/SampleBase/RenderCapsuleActor.h b/PhysX_3.4/Samples/SampleBase/RenderCapsuleActor.h
new file mode 100644
index 00000000..5196a89f
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RenderCapsuleActor.h
@@ -0,0 +1,53 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef RENDER_CAPSULE_ACTOR_H
+#define RENDER_CAPSULE_ACTOR_H
+
+#include "RenderBaseActor.h"
+#include "foundation/PxSimpleTypes.h"
+
+namespace SampleRenderer
+{
+ class Renderer;
+}
+
+ class RenderCapsuleActor : public RenderBaseActor
+ {
+ public:
+ RenderCapsuleActor(SampleRenderer::Renderer& renderer, PxReal radius, PxReal halfHeight);
+
+ // resize this capsule
+ void setDimensions(PxReal halfHeight, PxReal radius0, PxReal radius1);
+
+ RenderCapsuleActor(const RenderCapsuleActor&);
+ virtual ~RenderCapsuleActor();
+ };
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/RenderClothActor.cpp b/PhysX_3.4/Samples/SampleBase/RenderClothActor.cpp
new file mode 100644
index 00000000..8741be40
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RenderClothActor.cpp
@@ -0,0 +1,946 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "PxPhysXConfig.h"
+#if PX_USE_CLOTH_API
+
+#include "RenderClothActor.h"
+#include "RenderCapsuleActor.h"
+#include "RenderSphereActor.h"
+#include "RenderMeshActor.h"
+#include "RenderMaterial.h"
+#include "RendererMeshShape.h"
+#include "RendererClothShape.h"
+#include "RendererCapsuleShape.h"
+#include "PhysXSample.h"
+#include "foundation/PxBounds3.h"
+
+#include "cloth/PxClothParticleData.h"
+#include "cloth/PxCloth.h"
+
+#include "task/PxTask.h"
+
+#include "extensions/PxSmoothNormals.h"
+
+using namespace SampleRenderer;
+
+/// These functions can probably move to PxToolkit or PxExtension
+namespace
+{
+
+// create uv from planar projection onto xz plane (where most cloth grids are created)
+void createUVWithPlanarProjection(PxReal* uvs, PxU32 numVerts, const PxVec3* verts)
+{
+ PxBounds3 bounds = PxBounds3::empty();
+
+ for(PxU32 i = 0; i < numVerts; i++)
+ bounds.include(verts[i]);
+
+ PxVec3 dim = bounds.getDimensions();
+ PxReal minVal = PX_MAX_REAL;
+ PxU32 minAxis = 0;
+
+ // find smallest axis
+ if (dim.x < minVal) { minVal = dim.x; minAxis = 0; }
+ if (dim.y < minVal) { minVal = dim.y; minAxis = 1; }
+ if (dim.z < minVal) { minVal = dim.z; minAxis = 2; }
+
+ PxU32 uAxis = 0, vAxis = 1;
+ switch (minAxis)
+ {
+ case 0: uAxis = 1; vAxis = 2; break;
+ case 1: uAxis = 0; vAxis = 2; break;
+ case 2: uAxis = 0; vAxis = 1; break;
+ }
+
+ const float sizeU = dim[uAxis];
+ const float sizeV = dim[vAxis];
+ const float minU = bounds.minimum[uAxis];
+ const float minV = bounds.minimum[vAxis];
+
+ for (PxU32 i = 0; i < numVerts; ++i)
+ {
+ uvs[i*2+0] = (verts[i][uAxis] - minU) / sizeU;
+ uvs[i*2+1] = 1.f - (verts[i][vAxis]-minV) / sizeV;
+ }
+
+}
+
+// extract current cloth particle position from PxCloth
+// verts is supposed to have been pre-allocated to be at least size of particle array
+bool getVertsFromCloth(PxVec3* verts, const PxCloth& cloth)
+{
+ PxClothParticleData* readData = const_cast<PxCloth&>(cloth).lockParticleData();
+ if (!readData)
+ return false;
+
+ // copy vertex positions
+ PxU32 numVerts = cloth.getNbParticles();
+ for (PxU32 i = 0; i < numVerts; ++i)
+ verts[i] = readData->particles[i].pos;
+
+ readData->unlock();
+
+ return true;
+}
+
+// copy face structure from PxClothMeshDesc
+PxU16* createFacesFromMeshDesc(const PxClothMeshDesc& desc)
+{
+ PxU32 numTriangles = desc.triangles.count;
+ PxU32 numQuads = desc.quads.count;
+
+ PxU16* faces = (PxU16*)SAMPLE_ALLOC(sizeof(PxU16)* (numTriangles*3 + numQuads*6));
+ PxU16* fIt = faces;
+
+ PxU8* triangles = (PxU8*)desc.triangles.data;
+ for (PxU32 i = 0; i < numTriangles; i++)
+ {
+ if (desc.flags & PxMeshFlag::e16_BIT_INDICES)
+ {
+ PxU16* triangle = (PxU16*)triangles;
+ *fIt++ = triangle[ 0 ];
+ *fIt++ = triangle[ 1 ];
+ *fIt++ = triangle[ 2 ];
+ }
+ else
+ {
+ PxU32* triangle = (PxU32*)triangles;
+ *fIt++ = triangle[ 0 ];
+ *fIt++ = triangle[ 1 ];
+ *fIt++ = triangle[ 2 ];
+ }
+ triangles += desc.triangles.stride;
+ }
+
+ PxU8* quads = (PxU8*)desc.quads.data;
+ for (PxU32 i = 0; i < numQuads; i++)
+ {
+ if (desc.flags & PxMeshFlag::e16_BIT_INDICES)
+ {
+ PxU16* quad = (PxU16*)quads;
+ *fIt++ = quad[ 0 ];
+ *fIt++ = quad[ 1 ];
+ *fIt++ = quad[ 2 ];
+ *fIt++ = quad[ 2 ];
+ *fIt++ = quad[ 3 ];
+ *fIt++ = quad[ 0 ];
+ }
+ else
+ {
+ PxU32* quad = (PxU32*)quads;
+ *fIt++ = quad[ 0 ];
+ *fIt++ = quad[ 1 ];
+ *fIt++ = quad[ 2 ];
+ *fIt++ = quad[ 2 ];
+ *fIt++ = quad[ 3 ];
+ *fIt++ = quad[ 0 ];
+ }
+ quads += desc.quads.stride;
+ }
+
+ return faces;
+}
+
+} // anonymous namespace
+
+RenderClothActor::RenderClothActor(SampleRenderer::Renderer& renderer, const PxCloth& cloth, const PxClothMeshDesc &desc, const PxVec2* uv, const PxReal capsuleScale)
+ : mRenderer(renderer)
+ , mCloth(cloth)
+ , mNumFaces(0), mFaces(NULL)
+ , mSpheres(0), mCapsules(0), mPlanes(0), mConvexes(0), mTriangles(0)
+ , mNumSpheres(0), mNumCapsules(0), mNumPlanes(0), mNumConvexes(0), mNumTriangles(0)
+ , mUV(NULL)
+ , mCapsuleScale(capsuleScale)
+ , mClothRenderShape(NULL)
+ , mConvexMaterial(NULL)
+ , mMeshActor(NULL)
+ , mConvexActor(NULL)
+{
+ int numVerts = desc.points.count;
+
+ mNumFaces = desc.triangles.count + 2*desc.quads.count;
+ mFaces = createFacesFromMeshDesc(desc);
+
+ const PxVec3* verts = reinterpret_cast<const PxVec3*>(desc.points.data);
+
+ mUV = (PxReal*)SAMPLE_ALLOC(sizeof(PxReal)*numVerts*2);
+ if (uv)
+ memcpy( mUV, uv, sizeof(PxReal) * 2 * numVerts);
+ else
+ createUVWithPlanarProjection(mUV, numVerts, verts);
+
+ mClothVertices.resize(numVerts);
+ mClothNormals.resize(numVerts);
+
+ updateRenderShape();
+}
+
+RenderClothActor::~RenderClothActor()
+{
+ SAMPLE_FREE( mUV );
+ SAMPLE_FREE( mFaces );
+ SAMPLE_FREE( mSpheres );
+ SAMPLE_FREE( mCapsules );
+ SAMPLE_FREE( mPlanes );
+ SAMPLE_FREE( mConvexes );
+ SAMPLE_FREE( mTriangles );
+
+ freeCollisionRenderSpheres();
+ freeCollisionRenderCapsules();
+
+ delete mMeshActor;
+ delete mConvexActor;
+}
+
+void RenderClothActor::setConvexMaterial(RenderMaterial* material)
+{
+ mConvexMaterial = material;
+}
+
+void RenderClothActor::freeCollisionRenderSpheres()
+{
+ for (PxU32 i=0; i < mSphereActors.size(); ++i)
+ delete mSphereActors[i];
+
+ mSphereActors.clear();
+}
+
+void RenderClothActor::freeCollisionRenderCapsules()
+{
+ for (PxU32 i=0; i < mCapsuleActors.size(); ++i)
+ delete mCapsuleActors[i];
+
+ mCapsuleActors.clear();
+}
+
+namespace
+{
+ void BuildNormals(const PxVec3* PX_RESTRICT vertices, PxU32 numVerts, const PxU16* PX_RESTRICT faces, PxU32 numFaces, PxVec3* PX_RESTRICT normals)
+ {
+ memset(normals, 0, sizeof(PxVec3)*numVerts);
+
+ const PxU32 numIndices = numFaces*3;
+
+ // accumulate area weighted face normals in each vertex
+ for (PxU32 t=0; t < numIndices; t+=3)
+ {
+ PxU16 i = faces[t];
+ PxU16 j = faces[t+1];
+ PxU16 k = faces[t+2];
+
+ PxVec3 e1 = vertices[j]-vertices[i];
+ PxVec3 e2 = vertices[k]-vertices[i];
+
+ PxVec3 n = e2.cross(e1);
+
+ normals[i] += n;
+ normals[j] += n;
+ normals[k] += n;
+ }
+
+ // average
+ for (PxU32 i=0; i < numVerts; ++i)
+ normals[i].normalize();
+ }
+}
+
+
+void RenderClothActor::updateRenderShape()
+{
+ PX_PROFILE_ZONE("RenderClothActor::updateRenderShape",0);
+
+ int numVerts = mCloth.getNbParticles();
+
+ PX_ASSERT(numVerts > 0);
+
+ if(!mClothRenderShape)
+ {
+ PxCudaContextManager* ctxMgr = NULL;
+
+#if defined(RENDERER_ENABLE_CUDA_INTEROP)
+ PxGpuDispatcher* dispatcher = mCloth.getScene()->getTaskManager()->getGpuDispatcher();
+
+ // contxt must be created in at least one valid interop mode
+ if (dispatcher && (ctxMgr = dispatcher->getCudaContextManager()) &&
+ ctxMgr->getInteropMode() != PxCudaInteropMode::D3D10_INTEROP &&
+ ctxMgr->getInteropMode() != PxCudaInteropMode::D3D11_INTEROP)
+ {
+ ctxMgr = NULL;
+ }
+#endif
+
+ mClothRenderShape = new RendererClothShape(
+ mRenderer,
+ &mClothVertices[0],
+ numVerts,
+ &mClothNormals[0],
+ mUV,
+ &mFaces[0],
+ mNumFaces, false, ctxMgr);
+
+ setRenderShape(mClothRenderShape);
+ }
+
+ {
+ PX_PROFILE_ZONE("RenderClothShape::update",0);
+
+ bool needUpdate = true;
+
+#if defined(RENDERER_ENABLE_CUDA_INTEROP)
+
+ if (mCloth.getClothFlags()&PxClothFlag::eGPU && mClothRenderShape->isInteropEnabled())
+ {
+ PxClothParticleData* data = const_cast<PxCloth&>(mCloth).lockParticleData(PxDataAccessFlag::eDEVICE);
+ {
+ PX_PROFILE_ZONE("updateInterop",0);
+ bool success = mClothRenderShape->update(reinterpret_cast<CUdeviceptr>(data->particles), numVerts);
+
+ // if CUDA update succeeded then skip CPU update
+ if (success)
+ needUpdate = false;
+ }
+ data->unlock();
+ }
+#endif // RENDERER_ENABLE_CUDA_INTEROP
+
+ if (needUpdate)
+ {
+ bool result;
+ result = getVertsFromCloth(&mClothVertices[0], mCloth);
+ PX_UNUSED(result);
+ PX_ASSERT(result == true);
+
+ {
+ // update render normals
+ PX_PROFILE_ZONE("BuildSmoothNormals",0);
+ BuildNormals(&mClothVertices[0], mClothVertices.size(), mFaces, mNumFaces, &mClothNormals[0]);
+ }
+
+ mClothRenderShape->update(&mClothVertices[0], numVerts, &mClothNormals[0]);
+ }
+ }
+
+ setTransform(mCloth.getGlobalPose());
+}
+
+namespace
+{
+ struct ConvexMeshBuilder
+ {
+ ConvexMeshBuilder(const PxVec4* planes)
+ : mPlanes(planes)
+ {}
+
+ void operator()(PxU32 mask, float scale=1.0f);
+
+ const PxVec4* mPlanes;
+ shdfnd::Array<PxVec3> mVertices;
+ shdfnd::Array<PxU16> mIndices;
+ };
+
+ /*
+ void test()
+ {
+ int data[4*32];
+ float planes[4*32];
+
+ for(PxU32 numPlanes = 1; numPlanes<=32; ++numPlanes)
+ {
+ int seed = 0;
+
+ const PxU32 planeMask = (PxU64(1) << numPlanes) - 1;
+ for(PxU32 i=0; i<100000; ++i)
+ {
+ srand(seed);
+
+ for(PxU32 j=0; j<4*numPlanes; ++j)
+ planes[j] = float(data[j] = rand()) / RAND_MAX * 2.0f - 1.0f;
+
+ ConvexMeshBuilder builder(reinterpret_cast<PxVec4*>(planes));
+ builder(planeMask, 0.0f);
+
+ seed = data[numPlanes*4-1];
+ }
+ }
+ }
+ */
+}
+
+void RenderClothActor::update(float deltaTime)
+{
+ PX_PROFILE_ZONE("RenderClothActor::update",0);
+
+ updateRenderShape();
+
+ // update collision shapes
+ PxU32 numSpheres = mCloth.getNbCollisionSpheres();
+ PxU32 numCapsules = mCloth.getNbCollisionCapsules();
+ PxU32 numPlanes = mCloth.getNbCollisionPlanes();
+ PxU32 numConvexes = mCloth.getNbCollisionConvexes();
+ PxU32 numTriangles = mCloth.getNbCollisionTriangles();
+
+ if (numSpheres == 0 && mNumSpheres == 0 &&
+ numTriangles == 0 && mNumTriangles == 0 &&
+ numConvexes == 0 && mNumConvexes == 0)
+ return;
+
+ if(numSpheres != mNumSpheres)
+ {
+ SAMPLE_FREE(mSpheres);
+ mSpheres = (PxClothCollisionSphere*)SAMPLE_ALLOC(sizeof(PxClothCollisionSphere) * (mNumSpheres = numSpheres));
+ }
+
+ if(numCapsules != mNumCapsules)
+ {
+ SAMPLE_FREE(mCapsules);
+ mCapsules = (PxU32*)SAMPLE_ALLOC(sizeof(PxU32) * 2 * (mNumCapsules = numCapsules));
+ }
+
+ if(numPlanes != mNumPlanes)
+ {
+ SAMPLE_FREE(mPlanes);
+ mPlanes = (PxClothCollisionPlane*)SAMPLE_ALLOC(sizeof(PxClothCollisionPlane) * (mNumPlanes = numPlanes));
+ }
+
+ if(numConvexes != mNumConvexes)
+ {
+ SAMPLE_FREE(mConvexes);
+ mConvexes = (PxU32*)SAMPLE_ALLOC(sizeof(PxU32) * (mNumConvexes = numConvexes));
+ }
+
+ if(numTriangles != mNumTriangles)
+ {
+ SAMPLE_FREE(mTriangles);
+ mTriangles = (PxClothCollisionTriangle*)SAMPLE_ALLOC(sizeof(PxClothCollisionTriangle) * (mNumTriangles = numTriangles));
+ mMeshIndices.resize(0); mMeshIndices.reserve(mNumTriangles*3);
+ for(PxU32 i=0; i<mNumTriangles*3; ++i)
+ mMeshIndices.pushBack(PxU16(i));
+ }
+
+ {
+ PX_PROFILE_ZONE("mCloth.getCollisionData",0);
+ mCloth.getCollisionData(mSpheres, mCapsules, mPlanes, mConvexes, mTriangles);
+ }
+
+ PxTransform clothPose = mCloth.getGlobalPose();
+
+ // see if we need to recreate the collision shapes (count has changed)
+ if (numSpheres != mSphereActors.size())
+ {
+ freeCollisionRenderSpheres();
+
+ // create sphere actors (we reuse the RenderCapsuleActor type)
+ for (PxU32 i=0; i < numSpheres; i++)
+ {
+ RenderSphereActor* sphere = SAMPLE_NEW(RenderSphereActor)(mClothRenderShape->getRenderer(), 1.0f);
+ mSphereActors.pushBack(sphere);
+ }
+ }
+
+ if (numCapsules != mCapsuleActors.size())
+ {
+ freeCollisionRenderCapsules();
+
+ // create capsule actors
+ for (PxU32 i=0; i < numCapsules; i++)
+ {
+ RenderCapsuleActor* capsule = SAMPLE_NEW(RenderCapsuleActor)(mClothRenderShape->getRenderer(), 1.0f, 1.0f);
+ mCapsuleActors.pushBack(capsule);
+ }
+ }
+
+
+ {
+ PX_PROFILE_ZONE("updateRenderSpheres",0);
+
+ // update all spheres
+ for (PxU32 i=0; i < numSpheres; ++i)
+ {
+ float r = mSpheres[i].radius*mCapsuleScale;
+
+ mSphereActors[i]->setRendering(true);
+ mSphereActors[i]->setTransform(PxTransform(clothPose.transform(mSpheres[i].pos)));
+ mSphereActors[i]->setMeshScale(PxMeshScale(PxVec3(r, r, r), PxQuat(PxIdentity)));
+ }
+ }
+
+
+ {
+ PX_PROFILE_ZONE("updateRenderCapsules",0);
+
+ // capsule needs to be flipped to match PxTransformFromSegment
+ PxTransform flip(PxVec3(0.0f), PxQuat(-PxHalfPi, PxVec3(0.0f, 0.0f, 1.0f)));
+
+ // update all capsules
+ for (PxU32 i=0; i < numCapsules; ++i)
+ {
+ PxU32 i0 = mCapsules[i*2];
+ PxU32 i1 = mCapsules[i*2+1];
+
+ PxClothCollisionSphere& sphere0 = mSpheres[i0];
+ PxClothCollisionSphere& sphere1 = mSpheres[i1];
+
+ // disable individual rendering for spheres belonging to a capsule
+ mSphereActors[i0]->setRendering(false);
+ mSphereActors[i1]->setRendering(false);
+
+ PxVec3 p0 = clothPose.transform(sphere0.pos);
+ PxVec3 p1 = clothPose.transform(sphere1.pos);
+
+ mCapsuleActors[i]->setDimensions((p1-p0).magnitude()*0.5f, mCapsuleScale*sphere0.radius, mCapsuleScale*sphere1.radius);
+ mCapsuleActors[i]->setTransform(PxTransformFromSegment(p0, p1)*flip);
+ }
+ }
+
+ // update all triangles
+ SAMPLE_FREE(mMeshActor);
+ if(mNumTriangles)
+ {
+ mMeshActor = SAMPLE_NEW(RenderMeshActor)(mRenderer, reinterpret_cast<const PxVec3*>(
+ mTriangles), mNumTriangles*3, 0, 0, mMeshIndices.begin(), NULL, mNumTriangles, true);
+ mMeshActor->setTransform(clothPose);
+ }
+
+ SAMPLE_FREE(mConvexActor);
+ if(mNumConvexes)
+ {
+ ConvexMeshBuilder builder(reinterpret_cast<const PxVec4*>(mPlanes));
+ for(PxU32 i=0; i<mNumConvexes; ++i)
+ builder(mConvexes[i], mCloth.getWorldBounds().getExtents().maxElement());
+ mConvexVertices = builder.mVertices;
+ mConvexIndices = builder.mIndices;
+ if(!mConvexIndices.empty())
+ {
+ mConvexActor = SAMPLE_NEW(RenderMeshActor)(mRenderer, mConvexVertices.begin(),
+ mConvexVertices.size(), 0, 0, mConvexIndices.begin(), NULL, mConvexIndices.size()/3, true);
+ mConvexActor->setTransform(clothPose);
+ }
+ }
+
+}
+
+void RenderClothActor::render(SampleRenderer::Renderer& renderer, RenderMaterial* material, bool wireFrame)
+{
+ RenderBaseActor::render(renderer, material, wireFrame);
+
+ // render collision shapes
+
+ for (PxU32 i=0; i < mSphereActors.size(); ++i)
+ mSphereActors[i]->render(renderer, material, wireFrame);
+
+ for (PxU32 i=0; i < mCapsuleActors.size(); ++i)
+ mCapsuleActors[i]->render(renderer, material, wireFrame);
+
+ if(mMeshActor)
+ mMeshActor->render(renderer, material, wireFrame);
+
+ if(mConvexActor)
+ mConvexActor->render(renderer, mConvexMaterial ? mConvexMaterial : material, wireFrame);
+}
+
+namespace
+{
+ PxReal 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);
+ }
+
+ 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 PxU16 sInvalid = PxU16(-1);
+
+ // restriction: only supports a single patch per vertex.
+ struct HalfedgeMesh
+ {
+ struct Halfedge
+ {
+ Halfedge(PxU16 vertex = sInvalid, PxU16 face = sInvalid,
+ PxU16 next = sInvalid, PxU16 prev = sInvalid)
+ : mVertex(vertex), mFace(face), mNext(next), mPrev(prev)
+ {}
+
+ PxU16 mVertex; // to
+ PxU16 mFace; // left
+ PxU16 mNext; // ccw
+ PxU16 mPrev; // cw
+ };
+
+ HalfedgeMesh() : mNumTriangles(0) {}
+
+ PxU16 findHalfedge(PxU16 v0, PxU16 v1)
+ {
+ PxU16 h = mVertices[v0], start = h;
+ while(h != sInvalid && mHalfedges[h].mVertex != v1)
+ {
+ h = mHalfedges[h ^ 1].mNext;
+ if(h == start)
+ return sInvalid;
+ }
+ return h;
+ }
+
+ void connect(PxU16 h0, PxU16 h1)
+ {
+ mHalfedges[h0].mNext = h1;
+ mHalfedges[h1].mPrev = h0;
+ }
+
+ void addTriangle(PxU16 v0, PxU16 v1, PxU16 v2)
+ {
+ // add new vertices
+ PxU16 n = PxMax(v0, PxMax(v1, v2))+1;
+ if(mVertices.size() < n)
+ mVertices.resize(n, sInvalid);
+
+ // collect halfedges, prev and next of triangle
+ PxU16 verts[] = { v0, v1, v2 };
+ PxU16 handles[3], prev[3], next[3];
+ for(PxU16 i=0; i<3; ++i)
+ {
+ PxU16 j = (i+1)%3;
+ PxU16 h = findHalfedge(verts[i], verts[j]);
+ if(h == sInvalid)
+ {
+ // add new edge
+ h = 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(PxU16 i=0; i<3; ++i)
+ {
+ PxU16 j = (i+1)%3;
+
+ mHalfedges[handles[i]].mFace = mFaces.size();
+
+ // connect prev and next
+ connect(handles[i], handles[j]);
+
+ if(next[j] == sInvalid) // new next edge, connect opposite
+ connect(handles[j]^1, next[i]!=sInvalid ? next[i] : handles[i]^1);
+
+ if(prev[i] == sInvalid) // new prev edge, connect opposite
+ connect(prev[j]!=sInvalid ? prev[j] : handles[j]^1, handles[i]^1);
+
+ // prev is boundary, update middle vertex
+ if(mHalfedges[handles[i]^1].mFace == sInvalid)
+ mVertices[verts[j]] = handles[i]^1;
+ }
+
+ PX_ASSERT(mNumTriangles < 0xffff);
+ mFaces.pushBack(handles[2]);
+ ++mNumTriangles;
+ }
+
+ PxU16 removeTriangle(PxU16 f)
+ {
+ PxU16 result = sInvalid;
+
+ for(PxU16 i=0, h = mFaces[f]; i<3; ++i)
+ {
+ PxU16 v0 = mHalfedges[h^1].mVertex;
+ PxU16 v1 = mHalfedges[h].mVertex;
+
+ mHalfedges[h].mFace = sInvalid;
+
+ if(mHalfedges[h^1].mFace == sInvalid) // was boundary edge, remove
+ {
+ PxU16 v0Prev = mHalfedges[h ].mPrev;
+ PxU16 v0Next = mHalfedges[h^1].mNext;
+ PxU16 v1Prev = mHalfedges[h^1].mPrev;
+ PxU16 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(PxU16 v, PxU16 f)
+ {
+ PxU16 h = mFaces[f];
+ if(h == sInvalid)
+ return false;
+
+ PxU16 v0 = mHalfedges[h].mVertex;
+ h = mHalfedges[h].mNext;
+ PxU16 v1 = mHalfedges[h].mVertex;
+ h = mHalfedges[h].mNext;
+ PxU16 v2 = mHalfedges[h].mVertex;
+ h = mHalfedges[h].mNext;
+
+ return det(mPoints[v], mPoints[v0], mPoints[v1], mPoints[v2]) < -1e-5f;
+ }
+
+ /*
+ void print() const
+ {
+ for(PxU32 i=0; i<mFaces.size(); ++i)
+ {
+ shdfnd::printFormatted("f%u: ", i);
+ PxU16 h = mFaces[i];
+ if(h == sInvalid)
+ {
+ shdfnd::printFormatted("deleted\n");
+ continue;
+ }
+
+ for(int j=0; j<3; ++j)
+ {
+ shdfnd::printFormatted("h%u -> v%u -> ", PxU32(h), PxU32(mHalfedges[h].mVertex));
+ h = mHalfedges[h].mNext;
+ }
+
+ shdfnd::printFormatted("\n");
+ }
+
+ for(PxU32 i=0; i<mVertices.size(); ++i)
+ {
+ shdfnd::printFormatted("v%u: ", i);
+ PxU16 h = mVertices[i];
+ if(h == sInvalid)
+ {
+ shdfnd::printFormatted("deleted\n");
+ continue;
+ }
+
+ PxU16 start = h;
+ do {
+ shdfnd::printFormatted("h%u -> v%u, ", PxU32(h), PxU32(mHalfedges[h].mVertex));
+ h = mHalfedges[h^1].mNext;
+ } while (h != start);
+
+ shdfnd::printFormatted("\n");
+ }
+
+ for(PxU32 i=0; i<mHalfedges.size(); ++i)
+ {
+ shdfnd::printFormatted("h%u: v%u, ", i, PxU32(mHalfedges[i].mVertex));
+
+ if(mHalfedges[i].mFace == sInvalid)
+ shdfnd::printFormatted("boundary, ");
+ else
+ shdfnd::printFormatted("f%u, ", PxU32(mHalfedges[i].mFace));
+
+ shdfnd::printFormatted("p%u, n%u\n", PxU32(mHalfedges[i].mPrev), PxU32(mHalfedges[i].mNext));
+ }
+ }
+ */
+
+ shdfnd::Array<Halfedge> mHalfedges;
+ shdfnd::Array<PxU16> mVertices; // vertex -> (boundary) halfedge
+ shdfnd::Array<PxU16> mFaces; // face -> halfedge
+ shdfnd::Array<PxVec4> mPoints;
+ PxU16 mNumTriangles;
+ };
+}
+
+void ConvexMeshBuilder::operator()(PxU32 planeMask, float scale)
+{
+ PxU16 numPlanes = shdfnd::bitCount(planeMask);
+
+ if (numPlanes == 1)
+ {
+ PxTransform t = PxTransformFromPlaneEquation(reinterpret_cast<const PxPlane&>(mPlanes[Ps::lowestSetBit(planeMask)]));
+
+ if (!t.isValid())
+ return;
+
+ const PxU16 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) };
+
+ PxU32 baseIndex = mVertices.size();
+
+ for (PxU32 i=0; i < 4; ++i)
+ mVertices.pushBack(t.transform(vertices[i]));
+
+ for (PxU32 i=0; i < 6; ++i)
+ mIndices.pushBack(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(PxU16 i=4; i<mesh.mPoints.size(); ++i)
+ {
+ // remove any visible triangle
+ PxU16 v0 = sInvalid;
+ for(PxU16 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(PxU16 h=0; mesh.mVertices[v0] == sInvalid; h+=2)
+ {
+ if ((mesh.mHalfedges[h ].mFace == sInvalid) ^
+ (mesh.mHalfedges[h+1].mFace == sInvalid))
+ {
+ v0 = mesh.mHalfedges[h].mVertex;
+ }
+ }
+
+ // tesselate hole
+ PxU16 start = v0;
+ do {
+ PxU16 h = mesh.mVertices[v0];
+ PxU16 v1 = mesh.mHalfedges[h].mVertex;
+ mesh.addTriangle(v0, v1, i);
+ v0 = v1;
+ } while(v0 != start);
+ }
+
+ // convert triangles to vertices (intersection of 3 planes)
+ shdfnd::Array<PxU32> face2Vertex(mesh.mFaces.size(), sInvalid);
+ for(PxU32 i=0; i<mesh.mFaces.size(); ++i)
+ {
+ PxU16 h = mesh.mFaces[i];
+ if(h == sInvalid)
+ continue;
+
+ PxU16 v0 = mesh.mHalfedges[h].mVertex;
+ h = mesh.mHalfedges[h].mNext;
+ PxU16 v1 = mesh.mHalfedges[h].mVertex;
+ h = mesh.mHalfedges[h].mNext;
+ PxU16 v2 = mesh.mHalfedges[h].mVertex;
+
+ face2Vertex[i] = mVertices.size();
+ mVertices.pushBack(intersect(mesh.mPoints[v0], mesh.mPoints[v1], mesh.mPoints[v2]));
+ }
+
+ // convert vertices to polygons (face one-ring)
+ for(PxU32 i=0; i<mesh.mVertices.size(); ++i)
+ {
+ PxU16 h = mesh.mVertices[i];
+ if(h == sInvalid)
+ continue;
+
+ PxU16 v0 = face2Vertex[mesh.mHalfedges[h].mFace];
+ h = mesh.mHalfedges[h].mPrev^1;
+ PxU16 v1 = face2Vertex[mesh.mHalfedges[h].mFace];
+
+ while(true)
+ {
+ h = mesh.mHalfedges[h].mPrev^1;
+ PxU16 v2 = face2Vertex[mesh.mHalfedges[h].mFace];
+
+ if(v0 == v2)
+ break;
+
+ PxVec3 e0 = mVertices[v0] - mVertices[v2];
+ PxVec3 e1 = mVertices[v1] - mVertices[v2];
+ if(e0.cross(e1).magnitudeSquared() < 1e-10f)
+ continue;
+
+ mIndices.pushBack(v0);
+ mIndices.pushBack(v2);
+ mIndices.pushBack(v1);
+
+ v1 = v2;
+ }
+
+ }
+}
+
+#endif // PX_USE_CLOTH_API
+
+
diff --git a/PhysX_3.4/Samples/SampleBase/RenderClothActor.h b/PhysX_3.4/Samples/SampleBase/RenderClothActor.h
new file mode 100644
index 00000000..68925420
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RenderClothActor.h
@@ -0,0 +1,117 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef RENDER_CLOTH_ACTOR_H
+#define RENDER_CLOTH_ACTOR_H
+
+#include "RenderBaseActor.h"
+#include "RenderPhysX3Debug.h"
+
+#include "SampleAllocator.h"
+#include "SampleArray.h"
+
+#include "cloth/PxCloth.h"
+#include "extensions/PxClothMeshDesc.h"
+#include "RenderMaterial.h"
+
+namespace SampleRenderer
+{
+ class Renderer;
+ class RendererClothShape;
+}
+
+class RenderCapsuleActor;
+class RenderSphereActor;
+class RenderMeshActor;
+
+class RenderClothActor : public RenderBaseActor
+{
+public:
+ RenderClothActor( SampleRenderer::Renderer& renderer, const PxCloth& cloth, const PxClothMeshDesc &desc, const PxVec2* uvs = NULL, PxReal capsuleScale = 1.0f);
+
+ virtual ~RenderClothActor();
+
+ virtual void update(float deltaTime);
+ virtual void render(SampleRenderer::Renderer& renderer, RenderMaterial* material, bool wireFrame);
+ void setConvexMaterial(RenderMaterial* material);
+
+ virtual SampleRenderer::RendererClothShape* getRenderClothShape() const { return mClothRenderShape; }
+ virtual const PxCloth* getCloth() const { return &mCloth; }
+
+private:
+ void updateRenderShape();
+
+private:
+
+ RenderClothActor& operator=(const RenderClothActor&);
+
+ void freeCollisionRenderSpheres();
+ void freeCollisionRenderCapsules();
+
+ SampleRenderer::Renderer& mRenderer;
+ const PxCloth& mCloth;
+
+ // copied mesh structure
+ PxU32 mNumFaces;
+ PxU16* mFaces;
+
+ // collision data used for debug rendering
+ PxClothCollisionSphere* mSpheres;
+ PxU32* mCapsules;
+ PxClothCollisionPlane* mPlanes;
+ PxU32* mConvexes;
+ PxClothCollisionTriangle* mTriangles;
+ PxU32 mNumSpheres, mNumCapsules, mNumPlanes, mNumConvexes, mNumTriangles;
+
+ // texture uv (used only for render)
+ PxReal* mUV;
+
+ PxVec3 mRendererColor;
+ PxReal mCapsuleScale;
+
+ SampleRenderer::RendererClothShape* mClothRenderShape;
+ RenderMaterial* mConvexMaterial;
+
+ // collision shapes render actors
+ shdfnd::Array<RenderSphereActor*> mSphereActors;
+ shdfnd::Array<RenderCapsuleActor*> mCapsuleActors;
+
+ RenderMeshActor* mMeshActor;
+ shdfnd::Array<PxU16> mMeshIndices;
+
+ RenderMeshActor* mConvexActor;
+ shdfnd::Array<PxVec3> mConvexVertices;
+ shdfnd::Array<PxU16> mConvexIndices;
+
+ shdfnd::Array<PxVec3> mClothVertices;
+ shdfnd::Array<PxVec3> mClothNormals;
+
+};
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/RenderGridActor.cpp b/PhysX_3.4/Samples/SampleBase/RenderGridActor.cpp
new file mode 100644
index 00000000..4cf10265
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RenderGridActor.cpp
@@ -0,0 +1,50 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "RenderGridActor.h"
+#include "RendererGridShape.h"
+
+using namespace physx;
+using namespace SampleRenderer;
+
+RenderGridActor::RenderGridActor(Renderer& renderer, PxU32 size, PxReal cellSize, PxQuat v)
+{
+ RendererShape* rs = new RendererGridShape(renderer, size, cellSize);
+ setRenderShape(rs);
+
+ mPhysicsToGraphicsRot = v;
+}
+
+RenderGridActor::~RenderGridActor()
+{
+}
+
+void RenderGridActor::update(float deltaTime)
+{
+}
diff --git a/PhysX_3.4/Samples/SampleBase/RenderGridActor.h b/PhysX_3.4/Samples/SampleBase/RenderGridActor.h
new file mode 100644
index 00000000..06fb80e3
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RenderGridActor.h
@@ -0,0 +1,49 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef RENDER_GRID_ACTOR_H
+#define RENDER_GRID_ACTOR_H
+
+#include "RenderBaseActor.h"
+
+namespace SampleRenderer
+{
+ class Renderer;
+}
+
+ class RenderGridActor : public RenderBaseActor
+ {
+ public:
+ RenderGridActor(SampleRenderer::Renderer& renderer, PxU32 size, PxReal cellSize, PxQuat v = PxQuat(PxIdentity));
+ virtual ~RenderGridActor();
+
+ virtual void update(float deltaTime);
+ };
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/RenderMaterial.cpp b/PhysX_3.4/Samples/SampleBase/RenderMaterial.cpp
new file mode 100644
index 00000000..25313c80
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RenderMaterial.cpp
@@ -0,0 +1,184 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SamplePreprocessor.h"
+#include "RenderMaterial.h"
+#include "RenderTexture.h"
+#include "RendererMaterialDesc.h"
+#include "Renderer.h"
+#include "RendererMaterial.h"
+#include "RendererMaterialInstance.h"
+#include "RendererMemoryMacros.h"
+
+using namespace physx;
+using namespace SampleRenderer;
+
+const char* defaultMaterialLitVertexShader = "vertex/staticmesh.cg";
+const char* defaultMaterialTexturedUnlitFragmentShader = "fragment/sample_diffuse_and_texture.cg";
+const char* defaultMaterialTexturedLitFragmentShader = "fragment/sample_diffuse_and_texture.cg";
+const char* defaultMaterialFragmentShader = "fragment/sample_diffuse_no_texture.cg";
+
+RenderMaterial::RenderMaterial(Renderer& renderer, const PxVec3& diffuseColor, PxReal opacity, bool doubleSided, PxU32 id, RenderTexture* texture, bool lit, bool flat, bool instanced) :
+ mRenderMaterial (NULL),
+ mRenderMaterialInstance (NULL),
+ mID (id),
+ mDoubleSided (doubleSided),
+ mOwnsRendererMaterial (true)
+{
+ RendererMaterialDesc matDesc;
+ if(lit)
+ matDesc.type = RendererMaterial::TYPE_LIT;
+ else
+ matDesc.type = RendererMaterial::TYPE_UNLIT;
+ matDesc.alphaTestFunc = RendererMaterial::ALPHA_TEST_ALWAYS;
+ matDesc.alphaTestRef = 0.0f;
+ if(opacity==1.0f)
+ {
+ matDesc.blending = false;
+ matDesc.srcBlendFunc = RendererMaterial::BLEND_ONE;
+ matDesc.dstBlendFunc = RendererMaterial::BLEND_ONE;
+ }
+ else
+ {
+ matDesc.type = RendererMaterial::TYPE_UNLIT;
+ matDesc.blending = true;
+// matDesc.srcBlendFunc = RendererMaterial::BLEND_ONE;
+// matDesc.dstBlendFunc = RendererMaterial::BLEND_ONE;
+ matDesc.srcBlendFunc = RendererMaterial::BLEND_SRC_ALPHA;
+ matDesc.dstBlendFunc = RendererMaterial::BLEND_ONE_MINUS_SRC_ALPHA;
+ }
+
+ if(instanced)
+ {
+ matDesc.instanced = true;
+ }
+ else
+ {
+ matDesc.instanced = false;
+ }
+
+ matDesc.geometryShaderPath = NULL;
+
+ matDesc.vertexShaderPath = defaultMaterialLitVertexShader;
+
+ if(texture)
+ {
+ if(lit)
+ {
+ matDesc.fragmentShaderPath = defaultMaterialTexturedLitFragmentShader;
+ }
+ else
+ {
+ matDesc.fragmentShaderPath = defaultMaterialTexturedUnlitFragmentShader;
+ }
+ }
+ else
+ {
+ matDesc.fragmentShaderPath = defaultMaterialFragmentShader;
+ }
+ PX_ASSERT(matDesc.isValid());
+
+ mRenderMaterial = renderer.createMaterial(matDesc);
+ mRenderMaterialInstance = new RendererMaterialInstance(*mRenderMaterial);
+
+ setDiffuseColor(PxVec4(diffuseColor.x, diffuseColor.y, diffuseColor.z, opacity));
+ setShadeMode(flat);
+
+ update(renderer);
+
+ if(texture)
+ {
+ const RendererMaterial::Variable* var = mRenderMaterialInstance->findVariable("diffuseTexture", RendererMaterial::VARIABLE_SAMPLER2D);
+ //PX_ASSERT(var);
+ if(var)
+ mRenderMaterialInstance->writeData(*var, &texture->mTexture);
+ }
+}
+
+RenderMaterial::RenderMaterial(Renderer& renderer, RendererMaterial* mat, RendererMaterialInstance* matInstance, PxU32 id) :
+ mRenderMaterial (mat),
+ mRenderMaterialInstance (matInstance),
+ mID (id),
+ mDoubleSided (false),
+ mOwnsRendererMaterial (false)
+{
+ update(renderer);
+}
+
+void RenderMaterial::update(SampleRenderer::Renderer& renderer)
+{
+ const RendererMaterial::Variable* var = mRenderMaterialInstance->findVariable("windowWidth", RendererMaterial::VARIABLE_FLOAT);
+ if(var)
+ {
+ PxU32 tmpWindowWidth, tmpWindowHeight;
+ renderer.getWindowSize(tmpWindowWidth, tmpWindowHeight);
+
+ const PxReal windowWidth = PxReal(tmpWindowWidth);
+ mRenderMaterialInstance->writeData(*var, &windowWidth);
+ }
+
+}
+
+void RenderMaterial::setParticleSize(const PxReal particleSize)
+{
+ const RendererMaterial::Variable* var = mRenderMaterialInstance->findVariable("particleSize", RendererMaterial::VARIABLE_FLOAT);
+ if(var)
+ {
+ mRenderMaterialInstance->writeData(*var, &particleSize);
+ }
+}
+
+void RenderMaterial::setDiffuseColor(const PxVec4& color)
+{
+ const RendererMaterial::Variable* var = mRenderMaterialInstance->findVariable("diffuseColor", RendererMaterial::VARIABLE_FLOAT4);
+ if(var)
+ {
+ const PxReal data[] = { color.x, color.y, color.z, color.w };
+ mRenderMaterialInstance->writeData(*var, data);
+ }
+}
+
+void RenderMaterial::setShadeMode(bool flat)
+{
+ const RendererMaterial::Variable* var = mRenderMaterialInstance->findVariable("shadeMode", RendererMaterial::VARIABLE_FLOAT);
+ if(var)
+ {
+ float shadeMode = flat?1.0f:0.0f;
+ mRenderMaterialInstance->writeData(*var, &shadeMode);
+ }
+}
+
+RenderMaterial::~RenderMaterial()
+{
+ if(mOwnsRendererMaterial)
+ {
+ DELETESINGLE(mRenderMaterialInstance);
+ SAFE_RELEASE(mRenderMaterial);
+ }
+}
diff --git a/PhysX_3.4/Samples/SampleBase/RenderMaterial.h b/PhysX_3.4/Samples/SampleBase/RenderMaterial.h
new file mode 100644
index 00000000..5d03f398
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RenderMaterial.h
@@ -0,0 +1,78 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef RENDER_MATERIAL_H
+#define RENDER_MATERIAL_H
+
+#include "RenderBaseObject.h"
+#include "common/PxPhysXCommonConfig.h"
+#include "foundation/PxVec3.h"
+
+namespace SampleRenderer
+{
+ class Renderer;
+ class RendererMaterial;
+ class RendererMaterialInstance;
+}
+
+ class RenderTexture;
+
+ class RenderMaterial : public RenderBaseObject
+ {
+ public:
+ RenderMaterial(SampleRenderer::Renderer& renderer,
+ const PxVec3& diffuseColor,
+ PxReal opacity,
+ bool doubleSided,
+ PxU32 id,
+ RenderTexture* texture,
+ bool lit = true,
+ bool flat = false,
+ bool instanced = false);
+
+ RenderMaterial(SampleRenderer::Renderer& renderer,
+ SampleRenderer::RendererMaterial* mat,
+ SampleRenderer::RendererMaterialInstance* matInstance,
+ PxU32 id);
+ virtual ~RenderMaterial();
+
+ // the intent of this function is to update shaders variables, when needed (e.g. on resize)
+ virtual void update(SampleRenderer::Renderer& renderer);
+ void setDiffuseColor(const PxVec4& color);
+ void setParticleSize(const PxReal particleSize);
+ void setShadeMode(bool flat);
+
+ SampleRenderer::RendererMaterial* mRenderMaterial;
+ SampleRenderer::RendererMaterialInstance* mRenderMaterialInstance;
+ PxU32 mID;
+ bool mDoubleSided;
+ bool mOwnsRendererMaterial;
+ };
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/RenderMeshActor.cpp b/PhysX_3.4/Samples/SampleBase/RenderMeshActor.cpp
new file mode 100644
index 00000000..43c3519c
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RenderMeshActor.cpp
@@ -0,0 +1,66 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "RenderMeshActor.h"
+#include "RendererMeshShape.h"
+#include "RendererMemoryMacros.h"
+#include "extensions/PxSmoothNormals.h"
+#include "SampleAllocatorSDKClasses.h"
+
+using namespace physx;
+using namespace SampleRenderer;
+
+RenderMeshActor::RenderMeshActor( Renderer& renderer,
+ const PxVec3* verts, PxU32 numVerts,
+ const PxVec3* vertexNormals,
+ const PxReal* uvs,
+ const PxU16* faces16, const PxU32* faces32, PxU32 numFaces, bool flipWinding
+ )
+{
+ PxVec3Alloc* normals = NULL;
+ if(!vertexNormals)
+ {
+ normals = SAMPLE_NEW(PxVec3Alloc)[numVerts];
+ PxBuildSmoothNormals(numFaces, numVerts, verts, faces32, faces16, normals, flipWinding);
+ vertexNormals = normals;
+ }
+
+ RendererShape* rs = new RendererMeshShape(renderer, verts, numVerts, vertexNormals, uvs, faces16, faces32, numFaces, flipWinding);
+ setRenderShape(rs);
+
+ DELETEARRAY(normals);
+}
+
+RenderMeshActor::RenderMeshActor(const RenderMeshActor& src) : RenderBaseActor(src)
+{
+}
+
+RenderMeshActor::~RenderMeshActor()
+{
+}
diff --git a/PhysX_3.4/Samples/SampleBase/RenderMeshActor.h b/PhysX_3.4/Samples/SampleBase/RenderMeshActor.h
new file mode 100644
index 00000000..94f88f64
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RenderMeshActor.h
@@ -0,0 +1,54 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef RENDER_MESH_ACTOR_H
+#define RENDER_MESH_ACTOR_H
+
+#include "RenderBaseActor.h"
+#include "foundation/PxVec3.h"
+
+namespace SampleRenderer
+{
+ class Renderer;
+}
+
+ class RenderMeshActor : public RenderBaseActor
+ {
+ public:
+ RenderMeshActor(SampleRenderer::Renderer& renderer,
+ const PxVec3* verts, PxU32 numVerts,
+ const PxVec3* vertexNormals,
+ const PxReal* uvs,
+ const PxU16* faces16, const PxU32* faces32, PxU32 numFaces, bool flipWinding=false
+ );
+ RenderMeshActor(const RenderMeshActor&);
+ virtual ~RenderMeshActor();
+ };
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/RenderParticleSystemActor.cpp b/PhysX_3.4/Samples/SampleBase/RenderParticleSystemActor.cpp
new file mode 100644
index 00000000..d6bc10cb
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RenderParticleSystemActor.cpp
@@ -0,0 +1,178 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "PxPhysXConfig.h"
+
+#if PX_USE_PARTICLE_SYSTEM_API
+
+#include "RenderParticleSystemActor.h"
+#include "RendererParticleSystemShape.h"
+#include "RendererSimpleParticleSystemShape.h"
+#include "ParticleSystem.h"
+#include "RendererMemoryMacros.h"
+
+using namespace SampleRenderer;
+
+RenderParticleSystemActor::RenderParticleSystemActor(SampleRenderer::Renderer& renderer,
+ ParticleSystem* ps,
+ bool _mesh_instancing,
+ bool _fading,
+ PxReal fadingPeriod,
+ PxReal debriScaleFactor) : mRenderer(renderer),
+ mPS(ps),
+ mUseMeshInstancing(_mesh_instancing),
+ mFading(_fading)
+{
+ if(mRenderer.isSpriteRenderingSupported())
+ {
+ RendererShape* rs = new SampleRenderer::RendererParticleSystemShape(mRenderer,
+ mPS->getPxParticleBase()->getMaxParticles(),
+ mUseMeshInstancing,
+ mFading,
+ fadingPeriod,
+ debriScaleFactor,
+ mPS->getCudaContextManager());
+ setRenderShape(rs);
+ mUseSpritesMesh = true;
+ }
+ else
+ {
+ RendererShape* rs = new SampleRenderer::RendererSimpleParticleSystemShape(mRenderer,
+ mPS->getPxParticleBase()->getMaxParticles());
+ setRenderShape(rs);
+ mUseSpritesMesh = false;
+ }
+}
+
+RenderParticleSystemActor::~RenderParticleSystemActor()
+{
+ DELETESINGLE(mPS);
+}
+
+void RenderParticleSystemActor::update(float deltaTime)
+{
+ setTransform(PxTransform(PxIdentity));
+
+#if defined(RENDERER_ENABLE_CUDA_INTEROP)
+
+ SampleRenderer::RendererParticleSystemShape* shape =
+ static_cast<SampleRenderer::RendererParticleSystemShape*>(getRenderShape());
+
+ if (shape->isInteropEnabled() && (mPS->getPxParticleSystem().getParticleBaseFlags()&PxParticleBaseFlag::eGPU))
+ {
+ PxParticleReadData* data = mPS->getPxParticleSystem().lockParticleReadData(PxDataAccessFlag::eREADABLE | PxDataAccessFlag::eDEVICE);
+
+ if(data)
+ {
+ if(mUseMeshInstancing)
+ {
+ shape->updateInstanced(mPS->getValidParticleRange(),
+ reinterpret_cast<CUdeviceptr>(&data->positionBuffer[0]),
+ mPS->getValiditiesDevice(),
+ mPS->getOrientationsDevice(),
+ data->nbValidParticles);
+ }
+ else
+ {
+ CUdeviceptr lifetimes = 0;
+ if(mFading && mPS->useLifetime())
+ lifetimes = mPS->getLifetimesDevice();
+
+ shape->updateBillboard(mPS->getValidParticleRange(),
+ reinterpret_cast<CUdeviceptr>(&data->positionBuffer[0]),
+ mPS->getValiditiesDevice(),
+ lifetimes,
+ data->nbValidParticles);
+ }
+
+ data->unlock();
+ }
+ }
+ else
+
+#endif
+
+ {
+ PxParticleReadData* data = mPS->getPxParticleSystem().lockParticleReadData(PxDataAccessFlag::eREADABLE);
+
+ if(data)
+ {
+ if(mUseMeshInstancing)
+ {
+ SampleRenderer::RendererParticleSystemShape* shape =
+ static_cast<SampleRenderer::RendererParticleSystemShape*>(getRenderShape());
+ shape->updateInstanced(mPS->getValidParticleRange(),
+ &(mPS->getPositions()[0]),
+ mPS->getValidity(),
+ &(mPS->getOrientations()[0]));
+
+ }
+ else
+ {
+ if(mUseSpritesMesh)
+ {
+ SampleRenderer::RendererParticleSystemShape* shape =
+ static_cast<SampleRenderer::RendererParticleSystemShape*>(getRenderShape());
+ const PxReal* lifetimes = NULL;
+ if(mFading && mPS->useLifetime())
+ {
+ lifetimes = &(mPS->getLifetimes()[0]);
+ }
+ shape->updateBillboard(mPS->getValidParticleRange(),
+ &(mPS->getPositions()[0]),
+ mPS->getValidity(),
+ lifetimes);
+ }
+ else
+ {
+ SampleRenderer::RendererSimpleParticleSystemShape* shape =
+ static_cast<SampleRenderer::RendererSimpleParticleSystemShape*>(getRenderShape());
+ const PxReal* lifetimes = NULL;
+ if(mFading && mPS->useLifetime())
+ {
+ lifetimes = &(mPS->getLifetimes()[0]);
+ }
+ shape->updateBillboard(mPS->getValidParticleRange(),
+ &(mPS->getPositions()[0]),
+ mPS->getValidity(),
+ lifetimes);
+ }
+ }
+
+ data->unlock();
+ }
+ }
+}
+
+void RenderParticleSystemActor::updateSubstep(float deltaTime)
+{
+ mPS->update(deltaTime);
+}
+
+#endif // PX_USE_PARTICLE_SYSTEM_API
diff --git a/PhysX_3.4/Samples/SampleBase/RenderParticleSystemActor.h b/PhysX_3.4/Samples/SampleBase/RenderParticleSystemActor.h
new file mode 100644
index 00000000..313e2e0c
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RenderParticleSystemActor.h
@@ -0,0 +1,66 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef RENDER_PARTICLE_SYSTEM_ACTOR_H
+#define RENDER_PARTICLE_SYSTEM_ACTOR_H
+
+#include "RenderBaseActor.h"
+#include "foundation/PxVec3.h"
+
+namespace SampleRenderer
+{
+ class Renderer;
+}
+class ParticleSystem;
+
+// NOTE: This class takes ownership of the passed ParticleSystem object.
+class RenderParticleSystemActor : public RenderBaseActor
+{
+public:
+ RenderParticleSystemActor(SampleRenderer::Renderer& renderer,
+ ParticleSystem* ps,
+ bool _mesh_instancing = false,
+ bool _fading = false,
+ PxReal fadingPeriod = 1.0f,
+ PxReal debriScaleFactor = 1.0f);
+ virtual ~RenderParticleSystemActor();
+
+ virtual void update(float deltaTime);
+ void updateSubstep(float deltaTime);
+ ParticleSystem* getParticleSystem() { return mPS; }
+private:
+ RenderParticleSystemActor& operator=(const RenderParticleSystemActor&);
+ SampleRenderer::Renderer& mRenderer;
+ ParticleSystem* mPS;
+ bool mUseMeshInstancing;
+ bool mUseSpritesMesh;
+ bool mFading;
+};
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/RenderPhysX3Debug.cpp b/PhysX_3.4/Samples/SampleBase/RenderPhysX3Debug.cpp
new file mode 100644
index 00000000..7605f72c
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RenderPhysX3Debug.cpp
@@ -0,0 +1,923 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#include "RenderPhysX3Debug.h"
+#include "RendererColor.h"
+#include "common/PxRenderBuffer.h"
+#include "foundation/PxSimpleTypes.h"
+#include "SampleCamera.h"
+
+#include "geometry/PxConvexMesh.h"
+#include "geometry/PxConvexMeshGeometry.h"
+#include "geometry/PxCapsuleGeometry.h"
+#include "geometry/PxSphereGeometry.h"
+#include "geometry/PxBoxGeometry.h"
+#include "PsUtilities.h"
+#include "PsString.h"
+
+using namespace physx;
+using namespace SampleRenderer;
+using namespace SampleFramework;
+
+RenderPhysX3Debug::RenderPhysX3Debug(Renderer& renderer, SampleAssetManager& assetmanager) :
+ SamplePointDebugRender (renderer, assetmanager),
+ SampleLineDebugRender (renderer, assetmanager),
+ SampleTriangleDebugRender (renderer, assetmanager)
+{
+}
+
+RenderPhysX3Debug::~RenderPhysX3Debug()
+{
+}
+
+void RenderPhysX3Debug::update(const PxRenderBuffer& debugRenderable)
+{
+ // Points
+ const PxU32 numPoints = debugRenderable.getNbPoints();
+ if(numPoints)
+ {
+ const PxDebugPoint* PX_RESTRICT points = debugRenderable.getPoints();
+ checkResizePoint(numPoints);
+ for(PxU32 i=0; i<numPoints; i++)
+ {
+ const PxDebugPoint& point = points[i];
+ addPoint(point.pos, RendererColor(point.color));
+ }
+ }
+
+ // Lines
+ const PxU32 numLines = debugRenderable.getNbLines();
+ if(numLines)
+ {
+ const PxDebugLine* PX_RESTRICT lines = debugRenderable.getLines();
+ checkResizeLine(numLines * 2);
+ for(PxU32 i=0; i<numLines; i++)
+ {
+ const PxDebugLine& line = lines[i];
+ addLine(line.pos0, line.pos1, RendererColor(line.color0));
+ }
+ }
+
+ // Triangles
+ const PxU32 numTriangles = debugRenderable.getNbTriangles();
+ if(numTriangles)
+ {
+ const PxDebugTriangle* PX_RESTRICT triangles = debugRenderable.getTriangles();
+ checkResizeTriangle(numTriangles * 3);
+ for(PxU32 i=0; i<numTriangles; i++)
+ {
+ const PxDebugTriangle& triangle = triangles[i];
+ addTriangle(triangle.pos0, triangle.pos1, triangle.pos2, RendererColor(triangle.color0));
+ }
+ }
+}
+
+void RenderPhysX3Debug::update(const PxRenderBuffer& debugRenderable, const Camera& camera)
+{
+ // Points
+ const PxU32 numPoints = debugRenderable.getNbPoints();
+ if(numPoints)
+ {
+ const PxDebugPoint* PX_RESTRICT points = debugRenderable.getPoints();
+ checkResizePoint(numPoints);
+ for(PxU32 i=0; i<numPoints; i++)
+ {
+ const PxDebugPoint& point = points[i];
+ addPoint(point.pos, RendererColor(point.color));
+ }
+ }
+
+ // Lines
+ const PxU32 numLines = debugRenderable.getNbLines();
+ if(numLines)
+ {
+ const PxDebugLine* PX_RESTRICT lines = debugRenderable.getLines();
+ checkResizeLine(numLines * 2);
+ PxU32 nbVisible = 0;
+ for(PxU32 i=0; i<numLines; i++)
+ {
+ const PxDebugLine& line = lines[i];
+
+ PxBounds3 b;
+ b.minimum.x = PxMin(line.pos0.x, line.pos1.x);
+ b.minimum.y = PxMin(line.pos0.y, line.pos1.y);
+ b.minimum.z = PxMin(line.pos0.z, line.pos1.z);
+ b.maximum.x = PxMax(line.pos0.x, line.pos1.x);
+ b.maximum.y = PxMax(line.pos0.y, line.pos1.y);
+ b.maximum.z = PxMax(line.pos0.z, line.pos1.z);
+ if(camera.cull(b)==PLANEAABB_EXCLUSION)
+ continue;
+
+ addLine(line.pos0, line.pos1, RendererColor(line.color0));
+ nbVisible++;
+ }
+ shdfnd::printFormatted("%f\n", float(nbVisible)/float(numLines));
+ }
+
+ // Triangles
+ const PxU32 numTriangles = debugRenderable.getNbTriangles();
+ if(numTriangles)
+ {
+ const PxDebugTriangle* PX_RESTRICT triangles = debugRenderable.getTriangles();
+ checkResizeTriangle(numTriangles * 3);
+ for(PxU32 i=0; i<numTriangles; i++)
+ {
+ const PxDebugTriangle& triangle = triangles[i];
+ addTriangle(triangle.pos0, triangle.pos1, triangle.pos2, RendererColor(triangle.color0));
+ }
+ }
+}
+
+void RenderPhysX3Debug::queueForRender()
+{
+ queueForRenderPoint();
+ queueForRenderLine();
+ queueForRenderTriangle();
+}
+
+void RenderPhysX3Debug::clear()
+{
+ clearPoint();
+ clearLine();
+ clearTriangle();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#define NB_CIRCLE_PTS 20
+
+void RenderPhysX3Debug::addBox(const PxVec3* pts, const RendererColor& color, PxU32 renderFlags)
+{
+ if(renderFlags & RENDER_DEBUG_WIREFRAME)
+ {
+ const PxU8 indices[] = {
+ 0, 1, 1, 2, 2, 3, 3, 0,
+ 7, 6, 6, 5, 5, 4, 4, 7,
+ 1, 5, 6, 2,
+ 3, 7, 4, 0
+ };
+
+ for(PxU32 i=0;i<12;i++)
+ addLine(pts[indices[i*2]], pts[indices[i*2+1]], color);
+ }
+
+ if(renderFlags & RENDER_DEBUG_SOLID)
+ {
+ const PxU8 indices[] = {
+ 0,2,1, 0,3,2,
+ 1,6,5, 1,2,6,
+ 5,7,4, 5,6,7,
+ 4,3,0, 4,7,3,
+ 3,6,2, 3,7,6,
+ 5,0,1, 5,4,0
+ };
+ for(PxU32 i=0;i<12;i++)
+ addTriangle(pts[indices[i*3+0]], pts[indices[i*3+1]], pts[indices[i*3+2]], color);
+ }
+}
+
+void RenderPhysX3Debug::addCircle(PxU32 nbPts, const PxVec3* pts, const RendererColor& color, const PxVec3& offset)
+{
+ for(PxU32 i=0;i<nbPts;i++)
+ {
+ const PxU32 j = (i+1) % nbPts;
+ addLine(pts[i]+offset, pts[j]+offset, color);
+ }
+}
+
+void RenderPhysX3Debug::addAABB(const PxBounds3& box, const RendererColor& color, PxU32 renderFlags)
+{
+ const PxVec3& min = box.minimum;
+ const PxVec3& max = box.maximum;
+
+ // 7+------+6 0 = ---
+ // /| /| 1 = +--
+ // / | / | 2 = ++-
+ // / 4+---/--+5 3 = -+-
+ // 3+------+2 / y z 4 = --+
+ // | / | / | / 5 = +-+
+ // |/ |/ |/ 6 = +++
+ // 0+------+1 *---x 7 = -++
+
+ // Generate 8 corners of the bbox
+ PxVec3 pts[8];
+ pts[0] = PxVec3(min.x, min.y, min.z);
+ pts[1] = PxVec3(max.x, min.y, min.z);
+ pts[2] = PxVec3(max.x, max.y, min.z);
+ pts[3] = PxVec3(min.x, max.y, min.z);
+ pts[4] = PxVec3(min.x, min.y, max.z);
+ pts[5] = PxVec3(max.x, min.y, max.z);
+ pts[6] = PxVec3(max.x, max.y, max.z);
+ pts[7] = PxVec3(min.x, max.y, max.z);
+
+ addBox(pts, color, renderFlags);
+}
+
+void RenderPhysX3Debug::addBox(const PxBoxGeometry& bg, const PxTransform& tr, const RendererColor& color, PxU32 renderFlags)
+{
+ addOBB(tr.p, bg.halfExtents, PxMat33(tr.q), color, renderFlags);
+}
+
+void RenderPhysX3Debug::addOBB(const PxVec3& boxCenter, const PxVec3& boxExtents, const PxMat33& boxRot, const RendererColor& color, PxU32 renderFlags)
+{
+ PxVec3 Axis0 = boxRot.column0;
+ PxVec3 Axis1 = boxRot.column1;
+ PxVec3 Axis2 = boxRot.column2;
+
+ // "Rotated extents"
+ Axis0 *= boxExtents.x;
+ Axis1 *= boxExtents.y;
+ Axis2 *= boxExtents.z;
+
+ // 7+------+6 0 = ---
+ // /| /| 1 = +--
+ // / | / | 2 = ++-
+ // / 4+---/--+5 3 = -+-
+ // 3+------+2 / y z 4 = --+
+ // | / | / | / 5 = +-+
+ // |/ |/ |/ 6 = +++
+ // 0+------+1 *---x 7 = -++
+
+ // Original code: 24 vector ops
+/* pts[0] = mCenter - Axis0 - Axis1 - Axis2;
+ pts[1] = mCenter + Axis0 - Axis1 - Axis2;
+ pts[2] = mCenter + Axis0 + Axis1 - Axis2;
+ pts[3] = mCenter - Axis0 + Axis1 - Axis2;
+ pts[4] = mCenter - Axis0 - Axis1 + Axis2;
+ pts[5] = mCenter + Axis0 - Axis1 + Axis2;
+ pts[6] = mCenter + Axis0 + Axis1 + Axis2;
+ pts[7] = mCenter - Axis0 + Axis1 + Axis2;*/
+
+ // Rewritten: 12 vector ops
+ PxVec3 pts[8];
+ pts[0] = pts[3] = pts[4] = pts[7] = boxCenter - Axis0;
+ pts[1] = pts[2] = pts[5] = pts[6] = boxCenter + Axis0;
+
+ PxVec3 Tmp = Axis1 + Axis2;
+ pts[0] -= Tmp;
+ pts[1] -= Tmp;
+ pts[6] += Tmp;
+ pts[7] += Tmp;
+
+ Tmp = Axis1 - Axis2;
+ pts[2] += Tmp;
+ pts[3] += Tmp;
+ pts[4] -= Tmp;
+ pts[5] -= Tmp;
+
+ addBox(pts, color, renderFlags);
+}
+
+ enum Orientation
+ {
+ ORIENTATION_XY,
+ ORIENTATION_XZ,
+ ORIENTATION_YZ,
+
+ ORIENTATION_FORCE_DWORD = 0x7fffffff
+ };
+
+static bool generatePolygon(PxU32 nbVerts, PxVec3* verts, Orientation orientation, float amplitude, float phase, const PxTransform* transform=NULL)
+{
+ if(!nbVerts || !verts)
+ return false;
+
+ const float step = PxTwoPi/float(nbVerts);
+
+ for(PxU32 i=0;i<nbVerts;i++)
+ {
+ const float angle = phase + float(i) * step;
+ const float y = sinf(angle) * amplitude;
+ const float x = cosf(angle) * amplitude;
+
+ if(orientation==ORIENTATION_XY) { verts[i] = PxVec3(x, y, 0.0f); }
+ else if(orientation==ORIENTATION_XZ) { verts[i] = PxVec3(x, 0.0f, y); }
+ else if(orientation==ORIENTATION_YZ) { verts[i] = PxVec3(0.0f, x, y); }
+
+ if(transform)
+ verts[i] = transform->transform(verts[i]);
+ }
+ return true;
+}
+
+
+// PT: this comes from RendererCapsuleShape.cpp. Maybe we could grab the data from there instead of duplicating. But it protects us from external changes.
+static const PxVec3 gCapsuleVertices[] =
+{
+ PxVec3(0.0000f, -2.0000f, -0.0000f),
+ PxVec3(0.3827f, -1.9239f, -0.0000f),
+ PxVec3(0.2706f, -1.9239f, 0.2706f),
+ PxVec3(-0.0000f, -1.9239f, 0.3827f),
+ PxVec3(-0.2706f, -1.9239f, 0.2706f),
+ PxVec3(-0.3827f, -1.9239f, -0.0000f),
+ PxVec3(-0.2706f, -1.9239f, -0.2706f),
+ PxVec3(0.0000f, -1.9239f, -0.3827f),
+ PxVec3(0.2706f, -1.9239f, -0.2706f),
+ PxVec3(0.7071f, -1.7071f, -0.0000f),
+ PxVec3(0.5000f, -1.7071f, 0.5000f),
+ PxVec3(-0.0000f, -1.7071f, 0.7071f),
+ PxVec3(-0.5000f, -1.7071f, 0.5000f),
+ PxVec3(-0.7071f, -1.7071f, -0.0000f),
+ PxVec3(-0.5000f, -1.7071f, -0.5000f),
+ PxVec3(0.0000f, -1.7071f, -0.7071f),
+ PxVec3(0.5000f, -1.7071f, -0.5000f),
+ PxVec3(0.9239f, -1.3827f, -0.0000f),
+ PxVec3(0.6533f, -1.3827f, 0.6533f),
+ PxVec3(-0.0000f, -1.3827f, 0.9239f),
+ PxVec3(-0.6533f, -1.3827f, 0.6533f),
+ PxVec3(-0.9239f, -1.3827f, -0.0000f),
+ PxVec3(-0.6533f, -1.3827f, -0.6533f),
+ PxVec3(0.0000f, -1.3827f, -0.9239f),
+ PxVec3(0.6533f, -1.3827f, -0.6533f),
+ PxVec3(1.0000f, -1.0000f, -0.0000f),
+ PxVec3(0.7071f, -1.0000f, 0.7071f),
+ PxVec3(-0.0000f, -1.0000f, 1.0000f),
+ PxVec3(-0.7071f, -1.0000f, 0.7071f),
+ PxVec3(-1.0000f, -1.0000f, -0.0000f),
+ PxVec3(-0.7071f, -1.0000f, -0.7071f),
+ PxVec3(0.0000f, -1.0000f, -1.0000f),
+ PxVec3(0.7071f, -1.0000f, -0.7071f),
+ PxVec3(1.0000f, 1.0000f, 0.0000f),
+ PxVec3(0.7071f, 1.0000f, 0.7071f),
+ PxVec3(-0.0000f, 1.0000f, 1.0000f),
+ PxVec3(-0.7071f, 1.0000f, 0.7071f),
+ PxVec3(-1.0000f, 1.0000f, -0.0000f),
+ PxVec3(-0.7071f, 1.0000f, -0.7071f),
+ PxVec3(0.0000f, 1.0000f, -1.0000f),
+ PxVec3(0.7071f, 1.0000f, -0.7071f),
+ PxVec3(0.9239f, 1.3827f, 0.0000f),
+ PxVec3(0.6533f, 1.3827f, 0.6533f),
+ PxVec3(-0.0000f, 1.3827f, 0.9239f),
+ PxVec3(-0.6533f, 1.3827f, 0.6533f),
+ PxVec3(-0.9239f, 1.3827f, -0.0000f),
+ PxVec3(-0.6533f, 1.3827f, -0.6533f),
+ PxVec3(0.0000f, 1.3827f, -0.9239f),
+ PxVec3(0.6533f, 1.3827f, -0.6533f),
+ PxVec3(0.7071f, 1.7071f, 0.0000f),
+ PxVec3(0.5000f, 1.7071f, 0.5000f),
+ PxVec3(-0.0000f, 1.7071f, 0.7071f),
+ PxVec3(-0.5000f, 1.7071f, 0.5000f),
+ PxVec3(-0.7071f, 1.7071f, 0.0000f),
+ PxVec3(-0.5000f, 1.7071f, -0.5000f),
+ PxVec3(0.0000f, 1.7071f, -0.7071f),
+ PxVec3(0.5000f, 1.7071f, -0.5000f),
+ PxVec3(0.3827f, 1.9239f, 0.0000f),
+ PxVec3(0.2706f, 1.9239f, 0.2706f),
+ PxVec3(-0.0000f, 1.9239f, 0.3827f),
+ PxVec3(-0.2706f, 1.9239f, 0.2706f),
+ PxVec3(-0.3827f, 1.9239f, 0.0000f),
+ PxVec3(-0.2706f, 1.9239f, -0.2706f),
+ PxVec3(0.0000f, 1.9239f, -0.3827f),
+ PxVec3(0.2706f, 1.9239f, -0.2706f),
+ PxVec3(0.0000f, 2.0000f, 0.0000f),
+};
+
+static const PxU8 gCapsuleIndices[] =
+{
+ 1, 0, 2, 2, 0, 3, 3, 0, 4, 4, 0, 5, 5, 0, 6, 6, 0, 7, 7, 0, 8,
+ 8, 0, 1, 9, 1, 10, 10, 1, 2, 10, 2, 11, 11, 2, 3, 11, 3, 12,
+ 12, 3, 4, 12, 4, 13, 13, 4, 5, 13, 5, 14, 14, 5, 6, 14, 6, 15,
+ 15, 6, 7, 15, 7, 16, 16, 7, 8, 16, 8, 9, 9, 8, 1, 17, 9, 18,
+ 18, 9, 10, 18, 10, 19, 19, 10, 11, 19, 11, 20, 20, 11, 12, 20, 12, 21,
+ 21, 12, 13, 21, 13, 22, 22, 13, 14, 22, 14, 23, 23, 14, 15, 23, 15, 24,
+ 24, 15, 16, 24, 16, 17, 17, 16, 9, 25, 17, 26, 26, 17, 18, 26, 18, 27,
+ 27, 18, 19, 27, 19, 28, 28, 19, 20, 28, 20, 29, 29, 20, 21, 29, 21, 30,
+ 30, 21, 22, 30, 22, 31, 31, 22, 23, 31, 23, 32, 32, 23, 24, 32, 24, 25,
+ 25, 24, 17, 33, 25, 34, 34, 25, 26, 34, 26, 35, 35, 26, 27, 35, 27, 36,
+ 36, 27, 28, 36, 28, 37, 37, 28, 29, 37, 29, 38, 38, 29, 30, 38, 30, 39,
+ 39, 30, 31, 39, 31, 40, 40, 31, 32, 40, 32, 33, 33, 32, 25, 41, 33, 42,
+ 42, 33, 34, 42, 34, 43, 43, 34, 35, 43, 35, 44, 44, 35, 36, 44, 36, 45,
+ 45, 36, 37, 45, 37, 46, 46, 37, 38, 46, 38, 47, 47, 38, 39, 47, 39, 48,
+ 48, 39, 40, 48, 40, 41, 41, 40, 33, 49, 41, 50, 50, 41, 42, 50, 42, 51,
+ 51, 42, 43, 51, 43, 52, 52, 43, 44, 52, 44, 53, 53, 44, 45, 53, 45, 54,
+ 54, 45, 46, 54, 46, 55, 55, 46, 47, 55, 47, 56, 56, 47, 48, 56, 48, 49,
+ 49, 48, 41, 57, 49, 58, 58, 49, 50, 58, 50, 59, 59, 50, 51, 59, 51, 60,
+ 60, 51, 52, 60, 52, 61, 61, 52, 53, 61, 53, 62, 62, 53, 54, 62, 54, 63,
+ 63, 54, 55, 63, 55, 64, 64, 55, 56, 64, 56, 57, 57, 56, 49, 65, 57, 58,
+ 65, 58, 59, 65, 59, 60, 65, 60, 61, 65, 61, 62, 65, 62, 63, 65, 63, 64,
+ 65, 64, 57,
+};
+static const PxU32 gNumCapsuleIndices = PX_ARRAY_SIZE(gCapsuleIndices);
+
+static PX_FORCE_INLINE void fixCapsuleVertex(PxVec3& p, PxF32 radius, PxF32 halfHeight)
+{
+ const PxF32 sign = p.y > 0 ? 1.0f : -1.0f;
+ p.y -= sign;
+ p *= radius;
+ p.y += halfHeight*sign;
+}
+
+void RenderPhysX3Debug::addSphere(const PxSphereGeometry& sg, const PxTransform& tr, const RendererColor& color, PxU32 renderFlags)
+{
+ addSphere(tr.p, sg.radius, color, renderFlags);
+}
+
+void RenderPhysX3Debug::addSphere(const PxVec3& sphereCenter, float sphereRadius, const RendererColor& color, PxU32 renderFlags)
+{
+ const PxU32 nbVerts = NB_CIRCLE_PTS;
+ PxVec3 pts[NB_CIRCLE_PTS];
+
+ if(renderFlags & RENDER_DEBUG_WIREFRAME)
+ {
+ generatePolygon(nbVerts, pts, ORIENTATION_XY, sphereRadius, 0.0f);
+ addCircle(nbVerts, pts, color, sphereCenter);
+
+ generatePolygon(nbVerts, pts, ORIENTATION_XZ, sphereRadius, 0.0f);
+ addCircle(nbVerts, pts, color, sphereCenter);
+
+ generatePolygon(nbVerts, pts, ORIENTATION_YZ, sphereRadius, 0.0f);
+ addCircle(nbVerts, pts, color, sphereCenter);
+ }
+
+ if(renderFlags & RENDER_DEBUG_SOLID)
+ {
+ const PxF32 halfHeight = 0.0f;
+ for(PxU32 i=0;i<gNumCapsuleIndices/3;i++)
+ {
+ const PxU32 i0 = gCapsuleIndices[i*3+0];
+ const PxU32 i1 = gCapsuleIndices[i*3+1];
+ const PxU32 i2 = gCapsuleIndices[i*3+2];
+ PxVec3 v0 = gCapsuleVertices[i0];
+ PxVec3 v1 = gCapsuleVertices[i1];
+ PxVec3 v2 = gCapsuleVertices[i2];
+
+ fixCapsuleVertex(v0, sphereRadius, halfHeight);
+ fixCapsuleVertex(v1, sphereRadius, halfHeight);
+ fixCapsuleVertex(v2, sphereRadius, halfHeight);
+
+ addTriangle(v0+sphereCenter, v1+sphereCenter, v2+sphereCenter, color);
+ }
+ }
+}
+
+#define MAX_TEMP_VERTEX_BUFFER 400
+
+// creaet triangle strip of spheres
+static bool generateSphere(PxU32 nbSeg, PxU32& nbVerts, PxVec3* verts, PxVec3* normals)
+{
+ PxVec3 tempVertexBuffer[MAX_TEMP_VERTEX_BUFFER];
+ PxVec3 tempNormalBuffer[MAX_TEMP_VERTEX_BUFFER];
+
+ int halfSeg = nbSeg / 2;
+ int nSeg = halfSeg * 2;
+
+ if (((nSeg+1) * (nSeg+1)) > MAX_TEMP_VERTEX_BUFFER)
+ return false;
+
+ const float stepTheta = PxTwoPi / float(nSeg);
+ const float stepPhi = PxPi / float(nSeg);
+
+ // compute sphere vertices on the temporary buffer
+ nbVerts = 0;
+ for (int i = 0; i <= nSeg; i++)
+ {
+ const float theta = float(i) * stepTheta;
+ const float cosi = cos(theta);
+ const float sini = sin(theta);
+
+ for (int j = -halfSeg; j <= halfSeg; j++)
+ {
+ const float phi = float(j) * stepPhi;
+ const float sinj = sin( phi);
+ const float cosj = cos( phi);
+
+ const float y = cosj * cosi;
+ const float x = sinj;
+ const float z = cosj * sini;
+
+ tempVertexBuffer[nbVerts] = PxVec3(x,y,z);
+ tempNormalBuffer[nbVerts] = PxVec3(x,y,z).getNormalized();
+ nbVerts++;
+ }
+ }
+
+ nbVerts = 0;
+ // now create triangle soup data
+ for (int i = 0; i < nSeg; i++)
+ {
+ for (int j = 0; j < nSeg; j++)
+ {
+ // add one triangle
+ verts[nbVerts] = tempVertexBuffer[ (nSeg+1) * i + j];
+ normals[nbVerts] = tempNormalBuffer[ (nSeg+1) * i + j];
+ nbVerts++;
+
+ verts[nbVerts] = tempVertexBuffer[ (nSeg+1) * i + j+1];
+ normals[nbVerts] = tempNormalBuffer[ (nSeg+1) * i + j+1];
+ nbVerts++;
+
+ verts[nbVerts] = tempVertexBuffer[ (nSeg+1) * (i+1) + j+1];
+ normals[nbVerts] = tempNormalBuffer[ (nSeg+1) * (i+1) + j+1];
+ nbVerts++;
+
+ // add another triangle
+ verts[nbVerts] = tempVertexBuffer[ (nSeg+1) * i + j];
+ normals[nbVerts] = tempNormalBuffer[ (nSeg+1) * i + j];
+ nbVerts++;
+
+ verts[nbVerts] = tempVertexBuffer[ (nSeg+1) * (i+1) + j+1];
+ normals[nbVerts] = tempNormalBuffer[ (nSeg+1) * (i+1) + j+1];
+ nbVerts++;
+
+ verts[nbVerts] = tempVertexBuffer[ (nSeg+1) * (i+1) + j];
+ normals[nbVerts] = tempNormalBuffer[ (nSeg+1) * (i+1) + j];
+ nbVerts++;
+
+ }
+ }
+
+ return true;
+}
+
+void RenderPhysX3Debug::addSphereExt(const PxVec3& sphereCenter, float sphereRadius, const RendererColor& color, PxU32 renderFlags)
+{
+ if(renderFlags & RENDER_DEBUG_WIREFRAME)
+ {
+ const PxU32 nbVerts = NB_CIRCLE_PTS;
+ PxVec3 pts[NB_CIRCLE_PTS];
+
+ generatePolygon(nbVerts, pts, ORIENTATION_XY, sphereRadius, 0.0f);
+ addCircle(nbVerts, pts, color, sphereCenter);
+
+ generatePolygon(nbVerts, pts, ORIENTATION_XZ, sphereRadius, 0.0f);
+ addCircle(nbVerts, pts, color, sphereCenter);
+
+ generatePolygon(nbVerts, pts, ORIENTATION_YZ, sphereRadius, 0.0f);
+ addCircle(nbVerts, pts, color, sphereCenter);
+ }
+
+ if(renderFlags & RENDER_DEBUG_SOLID)
+ {
+ static bool initDone = false;
+ static PxU32 nbVerts;
+ static PxVec3 verts[MAX_TEMP_VERTEX_BUFFER*6];
+ static PxVec3 normals[MAX_TEMP_VERTEX_BUFFER*6];
+
+ if (!initDone)
+ {
+ generateSphere(16, nbVerts, verts, normals);
+ initDone = true;
+ }
+
+ PxU32 i = 0;
+ while ( i < nbVerts )
+ {
+ addTriangle( sphereCenter + sphereRadius * verts[i], sphereCenter + sphereRadius * verts[i+1], sphereCenter + sphereRadius * verts[i+2],
+ normals[i], normals[i+1], normals[i+2], color);
+ i += 3;
+ }
+ }
+}
+#undef MAX_TEMP_VERTEX_BUFFFER
+
+static inline PxU32 minArgument(const PxVec3 &v)
+{
+ PxU32 j = 0;
+ if ( v[j] > v[1]) j = 1;
+ if ( v[j] > v[2]) j = 2;
+ return j;
+}
+static inline PxVec3 abs(const PxVec3 &v)
+{
+ return PxVec3( PxAbs(v.x), PxAbs(v.y), PxAbs(v.z));
+}
+
+void RenderPhysX3Debug::addConeExt(float r0, float r1, const PxVec3& p0, const PxVec3& p1 , const RendererColor& color, PxU32 renderFlags)
+{
+ PxVec3 axis = p1 - p0;
+ PxReal length = axis.magnitude();
+ PxReal rdiff = r0 - r1;
+ PxReal sinAngle = rdiff / length;
+ PxReal x0 = r0 * sinAngle;
+ PxReal x1 = r1 * sinAngle;
+ PxVec3 center = 0.5f * (p0 + p1);
+
+ if (length < fabs(rdiff))
+ return;
+
+ PxReal r0p = sqrt(r0 * r0 - x0 * x0);
+ PxReal r1p = sqrt(r1 * r1 - x1 * x1);
+
+ if (length == 0.0f)
+ axis = PxVec3(1,0,0);
+ else
+ axis.normalize();
+
+ PxVec3 axis1(0.0f);
+ axis1[minArgument(abs(axis))] = 1.0f;
+ axis1 = axis1.cross(axis);
+ axis1.normalize();
+
+ PxVec3 axis2 = axis.cross(axis1);
+ axis2.normalize();
+
+ PxMat44 m;
+ m.column0 = PxVec4(axis, 0.0f);
+ m.column1 = PxVec4(axis1, 0.0f);
+ m.column2 = PxVec4(axis2, 0.0f);
+ m.column3 = PxVec4(center, 1.0f);
+
+ PxTransform tr(m);
+
+#define NUM_CONE_VERTS 72
+ const PxU32 nbVerts = NUM_CONE_VERTS;
+
+ PxVec3 pts0[NUM_CONE_VERTS] ;
+ PxVec3 pts1[NUM_CONE_VERTS];
+ PxVec3 normals[NUM_CONE_VERTS] ;
+
+ const float step = PxTwoPi / float(nbVerts);
+ for (PxU32 i = 0; i < nbVerts; i++)
+ {
+ const float angle = float(i) * step;
+ const float x = cosf(angle);
+ const float y = sinf(angle);
+
+ PxVec3 p = PxVec3(0.0f, x, y);
+
+ pts0[i] = tr.transform(r0p * p + PxVec3(-0.5f * length + x0,0,0));
+ pts1[i] = tr.transform(r1p * p + PxVec3(0.5f * length + x1, 0, 0));
+
+ normals[i] = tr.q.rotate(p.getNormalized());
+ normals[i] = x0 * axis + r0p * normals[i];
+ normals[i].normalize();
+ }
+#undef NUM_CONE_VERTS
+
+ if(renderFlags & RENDER_DEBUG_WIREFRAME)
+ {
+ for(PxU32 i=0;i<nbVerts;i++)
+ {
+ addLine(pts1[i], pts0[i], color);
+ }
+ }
+
+ if(renderFlags & RENDER_DEBUG_SOLID)
+ {
+ for(PxU32 i=0;i<nbVerts;i++)
+ {
+ const PxU32 j = (i+1) % nbVerts;
+ addTriangle(pts0[i], pts1[j], pts0[j], normals[i], normals[j], normals[j], color);
+ addTriangle(pts0[i], pts1[i], pts1[j], normals[i], normals[i], normals[j], color);
+ }
+ }
+
+}
+
+void RenderPhysX3Debug::addCone(float radius, float height, const PxTransform& tr, const RendererColor& color, PxU32 renderFlags)
+{
+ const PxU32 nbVerts = NB_CIRCLE_PTS;
+ PxVec3 pts[NB_CIRCLE_PTS];
+ generatePolygon(nbVerts, pts, ORIENTATION_XZ, radius, 0.0f, &tr);
+
+ const PxVec3 tip = tr.transform(PxVec3(0.0f, height, 0.0f));
+
+ if(renderFlags & RENDER_DEBUG_WIREFRAME)
+ {
+ addCircle(nbVerts, pts, color, PxVec3(0));
+ for(PxU32 i=0;i<nbVerts;i++)
+ {
+ addLine(tip, pts[i], color); // side of the cone
+ addLine(tr.p, pts[i], color); // base disk of the cone
+ }
+ }
+
+ if(renderFlags & RENDER_DEBUG_SOLID)
+ {
+ for(PxU32 i=0;i<nbVerts;i++)
+ {
+ const PxU32 j = (i+1) % nbVerts;
+ addTriangle(tip, pts[i], pts[j], color);
+ addTriangle(tr.p, pts[i], pts[j], color);
+ }
+ }
+}
+
+void RenderPhysX3Debug::addCylinder(float radius, float height, const PxTransform& tr, const RendererColor& color, PxU32 renderFlags)
+{
+ const PxU32 nbVerts = NB_CIRCLE_PTS;
+ PxVec3 pts[NB_CIRCLE_PTS];
+ generatePolygon(nbVerts, pts, ORIENTATION_XZ, radius, 0.0f, &tr);
+
+ PxTransform tr2 = tr;
+ tr2.p = tr.transform(PxVec3(0.0f, height, 0.0f));
+ PxVec3 pts2[NB_CIRCLE_PTS];
+ generatePolygon(nbVerts, pts2, ORIENTATION_XZ, radius, 0.0f, &tr2);
+
+ if(renderFlags & RENDER_DEBUG_WIREFRAME)
+ {
+ for(PxU32 i=0;i<nbVerts;i++)
+ {
+ const PxU32 j = (i+1) % nbVerts;
+ addLine(pts[i], pts[j], color); // circle
+ addLine(pts2[i], pts2[j], color); // circle
+ }
+
+ for(PxU32 i=0;i<nbVerts;i++)
+ {
+ addLine(pts[i], pts2[i], color); // side
+ addLine(tr.p, pts[i], color); // disk
+ addLine(tr2.p, pts2[i], color); // disk
+ }
+ }
+
+ if(renderFlags & RENDER_DEBUG_SOLID)
+ {
+ for(PxU32 i=0;i<nbVerts;i++)
+ {
+ const PxU32 j = (i+1) % nbVerts;
+ addTriangle(tr.p, pts[i], pts[j], color);
+ addTriangle(tr2.p, pts2[i], pts2[j], color);
+ addTriangle(pts[i], pts[j], pts2[j], color);
+ addTriangle(pts[i], pts2[j], pts2[i], color);
+ }
+ }
+}
+
+
+void RenderPhysX3Debug::addStar(const PxVec3& p, const float size, const RendererColor& color )
+{
+ const PxVec3 up(0.f, size, 0.f);
+ const PxVec3 right(size, 0.f, 0.f);
+ const PxVec3 forwards(0.f, 0.f, size);
+ addLine(p + up, p - up, color);
+ addLine(p + right, p - right, color);
+ addLine(p + forwards, p - forwards, color);
+}
+
+void RenderPhysX3Debug::addCapsule(const PxCapsuleGeometry& cg, const PxTransform& tr, const RendererColor& color, PxU32 renderFlags)
+{
+ PxTransform pose = PxTransform(PxVec3(0.f), PxQuat(PxPi/2, PxVec3(0,0,1)));
+ pose = tr * pose;
+
+ PxVec3 p0(0, -cg.halfHeight, 0);
+ PxVec3 p1(0, cg.halfHeight, 0);
+
+ p0 = pose.transform(p0);
+ p1 = pose.transform(p1);
+
+ pose.p = p0;
+ /*PxTransform pose = PxTransform(PxVec3(0.f), PxQuat(PxPi/2, PxVec3(0,0,1)));
+ pose = tr * pose;*/
+
+ //const PxReal height = cg.halfHeight;
+ //const PxVec3 p0 = tr.p - PxVec3(0, height, 0);
+ //const PxVec3 p1 = tr.p + PxVec3(0, height, 0);
+ addCapsule(p0, p1, cg.radius, 2*cg.halfHeight, pose, color, renderFlags);
+}
+
+void RenderPhysX3Debug::addCapsule(const PxVec3& p0, const PxVec3& p1, const float radius, const float height, const PxTransform& tr, const RendererColor& color, PxU32 renderFlags)
+{
+ addSphere(p0, radius, color, renderFlags);
+ addSphere(p1, radius, color, renderFlags);
+ addCylinder(radius, height, tr, color, renderFlags);
+}
+
+void RenderPhysX3Debug::addRectangle(float width, float length, const PxTransform& tr, const RendererColor& color)
+{
+ PxMat33 m33 = PxMat33(tr.q);
+ PxVec3 Axis1 = m33.column1;
+ PxVec3 Axis2 = m33.column2;
+
+ Axis1 *= length;
+ Axis2 *= width;
+
+ PxVec3 pts[4];
+ pts[0] = tr.p + Axis1 + Axis2 ;
+ pts[1] = tr.p - Axis1 + Axis2 ;
+ pts[2] = tr.p - Axis1 - Axis2 ;
+ pts[3] = tr.p + Axis1 - Axis2 ;
+
+ addTriangle(pts[0], pts[1], pts[2], color);
+ addTriangle(pts[0], pts[2], pts[3], color);
+}
+
+void RenderPhysX3Debug::addGeometry(const PxGeometry& geom, const PxTransform& tr, const RendererColor& color, PxU32 renderFlags)
+{
+ switch(geom.getType())
+ {
+ case PxGeometryType::eBOX:
+ {
+ addBox(static_cast<const PxBoxGeometry&>(geom), tr, color, renderFlags);
+ }
+ break;
+ case PxGeometryType::eSPHERE:
+ {
+ addSphere(static_cast<const PxSphereGeometry&>(geom), tr, color, renderFlags);
+ }
+ break;
+ case PxGeometryType::eCAPSULE:
+ {
+ addCapsule(static_cast<const PxCapsuleGeometry&>(geom), tr, color, renderFlags);
+ }
+ break;
+ case PxGeometryType::eCONVEXMESH:
+ {
+ addConvex(static_cast<const PxConvexMeshGeometry&>(geom), tr, color, renderFlags);
+ }
+ break;
+ case PxGeometryType::ePLANE:
+ case PxGeometryType::eTRIANGLEMESH:
+ case PxGeometryType::eHEIGHTFIELD:
+ default:
+ {
+ PX_ASSERT(!"Not supported!");
+ break;
+ }
+ }
+}
+
+void RenderPhysX3Debug::addConvex(const PxConvexMeshGeometry& cg, const PxTransform& tr, const RendererColor& color, PxU32 renderFlags)
+{
+ const PxConvexMesh& mesh = *cg.convexMesh;
+
+ const PxMat33 rot = PxMat33(tr.q) * cg.scale.toMat33();
+
+ // PT: you can't use PxTransform with a non-uniform scaling
+ const PxMat44 globalPose(rot, tr.p);
+ const PxU32 polygonCount = mesh.getNbPolygons();
+ const PxU8* indexBuffer = mesh.getIndexBuffer();
+ const PxVec3* vertexBuffer = mesh.getVertices();
+
+ if(renderFlags & RENDER_DEBUG_WIREFRAME)
+ {
+ for(PxU32 i=0; i<polygonCount; i++)
+ {
+ PxHullPolygon data;
+ mesh.getPolygonData(i, data);
+
+ const PxU32 vertexCount = data.mNbVerts;
+ PxU32 i0 = indexBuffer[vertexCount-1];
+ PxU32 i1 = *indexBuffer++;
+ addLine(globalPose.transform(vertexBuffer[i0]), globalPose.transform(vertexBuffer[i1]), color);
+ for(PxU32 j=1; j<vertexCount; j++)
+ {
+ i0 = indexBuffer[-1];
+ i1 = *indexBuffer++;
+ addLine(globalPose.transform(vertexBuffer[i0]), globalPose.transform(vertexBuffer[i1]), color);
+ }
+ }
+ }
+
+ if(renderFlags & RENDER_DEBUG_SOLID)
+ {
+ for(PxU32 i=0; i<polygonCount; i++)
+ {
+ PxHullPolygon data;
+ mesh.getPolygonData(i, data);
+
+ const PxU32 vertexCount = data.mNbVerts;
+
+ const PxVec3& v0 = vertexBuffer[indexBuffer[0]];
+ for(PxU32 j=0; j<vertexCount-2; j++)
+ {
+ const PxVec3& v1 = vertexBuffer[indexBuffer[j+1]];
+ const PxVec3& v2 = vertexBuffer[indexBuffer[j+2]];
+
+ addTriangle(globalPose.transform(v0), globalPose.transform(v1), globalPose.transform(v2), color);
+ }
+ indexBuffer += vertexCount;
+ }
+ }
+}
+
+void RenderPhysX3Debug::addArrow(const PxVec3& posA, const PxVec3& posB, const RendererColor& color)
+{
+ const PxVec3 t0 = (posB - posA).getNormalized();
+ const PxVec3 a = PxAbs(t0.x)<0.707f ? PxVec3(1,0,0): PxVec3(0,1,0);
+ const PxVec3 t1 = t0.cross(a).getNormalized();
+ const PxVec3 t2 = t0.cross(t1).getNormalized();
+
+ addLine(posA, posB, color);
+ addLine(posB, posB - t0*0.15 + t1 * 0.15, color);
+ addLine(posB, posB - t0*0.15 - t1 * 0.15, color);
+ addLine(posB, posB - t0*0.15 + t2 * 0.15, color);
+ addLine(posB, posB - t0*0.15 - t2 * 0.15, color);
+}
diff --git a/PhysX_3.4/Samples/SampleBase/RenderPhysX3Debug.h b/PhysX_3.4/Samples/SampleBase/RenderPhysX3Debug.h
new file mode 100644
index 00000000..26ecda19
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RenderPhysX3Debug.h
@@ -0,0 +1,100 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef RENDER_PHYSX3_DEBUG_H
+#define RENDER_PHYSX3_DEBUG_H
+
+#include <SamplePointDebugRender.h>
+#include <SampleLineDebugRender.h>
+#include <SampleTriangleDebugRender.h>
+#include "SampleAllocator.h"
+
+ enum RenderPhysX3DebugFlag
+ {
+ RENDER_DEBUG_WIREFRAME = (1<<0),
+ RENDER_DEBUG_SOLID = (1<<1),
+
+ RENDER_DEBUG_DEFAULT = RENDER_DEBUG_SOLID//RENDER_DEBUG_WIREFRAME//|RENDER_DEBUG_SOLID
+ };
+
+ namespace physx
+ {
+ class PxRenderBuffer;
+ class PxConvexMeshGeometry;
+ class PxCapsuleGeometry;
+ class PxSphereGeometry;
+ class PxBoxGeometry;
+ class PxGeometry;
+ }
+ class Camera;
+
+ class RenderPhysX3Debug : public SampleFramework::SamplePointDebugRender
+ , public SampleFramework::SampleLineDebugRender
+ , public SampleFramework::SampleTriangleDebugRender
+ , public SampleAllocateable
+ {
+ public:
+ RenderPhysX3Debug(SampleRenderer::Renderer& renderer, SampleFramework::SampleAssetManager& assetmanager);
+ virtual ~RenderPhysX3Debug();
+
+ void addAABB(const PxBounds3& box, const SampleRenderer::RendererColor& color, PxU32 renderFlags = RENDER_DEBUG_DEFAULT);
+ void addOBB(const PxVec3& boxCenter, const PxVec3& boxExtents, const PxMat33& boxRot, const SampleRenderer::RendererColor& color, PxU32 renderFlags = RENDER_DEBUG_DEFAULT);
+ void addSphere(const PxVec3& sphereCenter, float sphereRadius, const SampleRenderer::RendererColor& color, PxU32 renderFlags = RENDER_DEBUG_DEFAULT);
+
+ void addBox(const PxBoxGeometry& bg, const PxTransform& tr, const SampleRenderer::RendererColor& color, PxU32 renderFlags = RENDER_DEBUG_DEFAULT);
+
+ void addSphere(const PxSphereGeometry& sg, const PxTransform& tr, const SampleRenderer::RendererColor& color, PxU32 renderFlags = RENDER_DEBUG_DEFAULT);
+ void addCone(float radius, float height, const PxTransform& tr, const SampleRenderer::RendererColor& color, PxU32 renderFlags = RENDER_DEBUG_DEFAULT);
+
+ void addSphereExt(const PxVec3& sphereCenter, float sphereRadius, const SampleRenderer::RendererColor& color, PxU32 renderFlags = RENDER_DEBUG_DEFAULT);
+ void addConeExt(float radius0, float radius1, const PxVec3& p0, const PxVec3& p1 , const SampleRenderer::RendererColor& color, PxU32 renderFlags = RENDER_DEBUG_DEFAULT);
+
+ void addCylinder(float radius, float height, const PxTransform& tr, const SampleRenderer::RendererColor& color, PxU32 renderFlags = RENDER_DEBUG_DEFAULT);
+ void addStar(const PxVec3& p, const float size, const SampleRenderer::RendererColor& color );
+
+ void addCapsule(const PxVec3& p0, const PxVec3& p1, const float radius, const float height, const PxTransform& tr, const SampleRenderer::RendererColor& color, PxU32 renderFlags = RENDER_DEBUG_DEFAULT);
+ void addCapsule(const PxCapsuleGeometry& cg, const PxTransform& tr, const SampleRenderer::RendererColor& color, PxU32 renderFlags = RENDER_DEBUG_DEFAULT);
+
+ void addGeometry(const PxGeometry& geom, const PxTransform& tr, const SampleRenderer::RendererColor& color, PxU32 renderFlags = RENDER_DEBUG_DEFAULT);
+
+ void addRectangle(float width, float length, const PxTransform& tr, const SampleRenderer::RendererColor& color);
+ void addConvex(const PxConvexMeshGeometry& cg, const PxTransform& tr, const SampleRenderer::RendererColor& color, PxU32 renderFlags = RENDER_DEBUG_DEFAULT);
+
+ void addArrow(const PxVec3& posA, const PxVec3& posB, const SampleRenderer::RendererColor& color);
+
+ void update(const PxRenderBuffer& debugRenderable);
+ void update(const PxRenderBuffer& debugRenderable, const Camera& camera);
+ void queueForRender();
+ void clear();
+ private:
+ void addBox(const PxVec3* pts, const SampleRenderer::RendererColor& color, PxU32 renderFlags);
+ void addCircle(PxU32 nbPts, const PxVec3* pts, const SampleRenderer::RendererColor& color, const PxVec3& offset);
+ };
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/RenderSphereActor.cpp b/PhysX_3.4/Samples/SampleBase/RenderSphereActor.cpp
new file mode 100644
index 00000000..e5c669f7
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RenderSphereActor.cpp
@@ -0,0 +1,48 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "RenderSphereActor.h"
+#include "RendererCapsuleShape.h"
+
+using namespace physx;
+using namespace SampleRenderer;
+
+RenderSphereActor::RenderSphereActor(Renderer& renderer, PxReal radius)
+{
+ RendererShape* rs = new RendererCapsuleShape(renderer, 0.0f, radius);
+ setRenderShape(rs);
+}
+
+RenderSphereActor::RenderSphereActor(const RenderSphereActor& src) : RenderBaseActor(src)
+{
+}
+
+RenderSphereActor::~RenderSphereActor()
+{
+}
diff --git a/PhysX_3.4/Samples/SampleBase/RenderSphereActor.h b/PhysX_3.4/Samples/SampleBase/RenderSphereActor.h
new file mode 100644
index 00000000..2d05fe87
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RenderSphereActor.h
@@ -0,0 +1,44 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef RENDER_SPHERE_ACTOR_H
+#define RENDER_SPHERE_ACTOR_H
+
+#include "RenderBaseActor.h"
+#include "foundation/PxSimpleTypes.h"
+
+ class RenderSphereActor : public RenderBaseActor
+ {
+ public:
+ RenderSphereActor(SampleRenderer::Renderer& renderer, PxReal radius);
+ RenderSphereActor(const RenderSphereActor&);
+ virtual ~RenderSphereActor();
+ };
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/RenderTexture.cpp b/PhysX_3.4/Samples/SampleBase/RenderTexture.cpp
new file mode 100644
index 00000000..62a42f20
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RenderTexture.cpp
@@ -0,0 +1,109 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SamplePreprocessor.h"
+#include "RendererMemoryMacros.h"
+#include "RenderTexture.h"
+#include "Renderer.h"
+#include "RendererTexture2DDesc.h"
+
+using namespace physx;
+using namespace SampleRenderer;
+
+RenderTexture::RenderTexture(Renderer& renderer, PxU32 id, PxU32 width, PxU32 height, const void* data) :
+ mID (id),
+ mTexture (NULL),
+ mOwnsTexture (true)
+{
+ RendererTexture2DDesc tdesc;
+
+#if !defined(RENDERER_PS3)
+ tdesc.format = RendererTexture2D::FORMAT_B8G8R8A8;
+#else
+ tdesc.format = RendererTexture2D::FORMAT_R8G8B8A8;
+#endif
+
+ tdesc.width = width;
+ tdesc.height = height;
+ tdesc.numLevels = 1;
+/*
+ tdesc.filter;
+ tdesc.addressingU;
+ tdesc.addressingV;
+ tdesc.renderTarget;
+*/
+ PX_ASSERT(tdesc.isValid());
+ mTexture = renderer.createTexture2D(tdesc);
+ PX_ASSERT(mTexture);
+
+ const PxU32 componentCount = 4;
+
+ if(mTexture)
+ {
+ PxU32 pitch = 0;
+ void* buffer = mTexture->lockLevel(0, pitch);
+ PX_ASSERT(buffer);
+ if(buffer)
+ {
+ PxU8* levelDst = (PxU8*)buffer;
+ const PxU8* levelSrc = (PxU8*)data;
+ const PxU32 levelWidth = mTexture->getWidthInBlocks();
+ const PxU32 levelHeight = mTexture->getHeightInBlocks();
+ const PxU32 rowSrcSize = levelWidth * mTexture->getBlockSize();
+ PX_UNUSED(rowSrcSize);
+ PX_ASSERT(rowSrcSize <= pitch); // the pitch can't be less than the source row size.
+ for(PxU32 row=0; row<levelHeight; row++)
+ {
+ // copy per pixel to handle RBG case, based on component count
+ for(PxU32 col=0; col<levelWidth; col++)
+ {
+ *levelDst++ = levelSrc[0];
+ *levelDst++ = levelSrc[1];
+ *levelDst++ = levelSrc[2];
+ *levelDst++ = 0xFF; //alpha
+ levelSrc += componentCount;
+ }
+ }
+ }
+ mTexture->unlockLevel(0);
+ }
+}
+
+RenderTexture::RenderTexture(Renderer& renderer, PxU32 id, RendererTexture2D* texture) :
+ mID (id),
+ mTexture (texture),
+ mOwnsTexture (false)
+{
+}
+
+RenderTexture::~RenderTexture()
+{
+ if(mOwnsTexture)
+ SAFE_RELEASE(mTexture);
+}
diff --git a/PhysX_3.4/Samples/SampleBase/RenderTexture.h b/PhysX_3.4/Samples/SampleBase/RenderTexture.h
new file mode 100644
index 00000000..ed0b9382
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/RenderTexture.h
@@ -0,0 +1,55 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef RENDER_TEXTURE_H
+#define RENDER_TEXTURE_H
+
+#include "RenderBaseObject.h"
+#include "common/PxPhysXCommonConfig.h"
+#include "foundation/PxVec3.h"
+#include <RendererTexture2D.h>
+
+namespace SampleRenderer
+{
+ class Renderer;
+}
+
+ class RenderTexture : public RenderBaseObject
+ {
+ public:
+ RenderTexture(SampleRenderer::Renderer& renderer, PxU32 id, PxU32 width, PxU32 height, const void* data);
+ RenderTexture(SampleRenderer::Renderer& renderer, PxU32 id, SampleRenderer::RendererTexture2D* texture);
+ virtual ~RenderTexture();
+
+ PxU32 mID;
+ SampleRenderer::RendererTexture2D* mTexture;
+ bool mOwnsTexture;
+ };
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/SampleAllocator.cpp b/PhysX_3.4/Samples/SampleBase/SampleAllocator.cpp
new file mode 100644
index 00000000..62338625
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SampleAllocator.cpp
@@ -0,0 +1,332 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include <stdio.h>
+#include <assert.h>
+#include "SampleAllocator.h"
+#include "RendererMemoryMacros.h"
+#include "foundation/PxAssert.h"
+#include "foundation/PxErrorCallback.h"
+#include "PsString.h"
+
+PxErrorCallback& getSampleErrorCallback();
+
+#if defined(WIN32)
+// on win32 we only have 8-byte alignment guaranteed, but the CRT provides special aligned allocation
+// fns
+#include <malloc.h>
+#include <crtdbg.h>
+
+ static void* platformAlignedAlloc(size_t size)
+ {
+ return _aligned_malloc(size, 16);
+ }
+
+ static void platformAlignedFree(void* ptr)
+ {
+ _aligned_free(ptr);
+ }
+#elif PX_LINUX_FAMILY
+ static void* platformAlignedAlloc(size_t size)
+ {
+ return ::memalign(16, size);
+ }
+
+ static void platformAlignedFree(void* ptr)
+ {
+ ::free(ptr);
+ }
+#else
+
+// on Win64 we get 16-byte alignment by default
+ static void* platformAlignedAlloc(size_t size)
+ {
+ void *ptr = ::malloc(size);
+ PX_ASSERT((reinterpret_cast<size_t>(ptr) & 15)==0);
+ return ptr;
+ }
+
+ static void platformAlignedFree(void* ptr)
+ {
+ ::free(ptr);
+ }
+#endif
+
+
+#define DEBUG_IDENTIFIER 0xBeefBabe
+#define DEBUG_DEALLOCATED 0xDeadDead
+#define INVALID_ID 0xffffffff
+#define MEMBLOCKSTART 64
+
+#if PX_DEBUG || PX_PROFILE
+static void print(const char* buffer)
+{
+ shdfnd::printFormatted("%s", buffer);
+#if PX_WINDOWS
+ if(buffer) { _RPT0(_CRT_WARN, buffer); }
+#endif
+}
+#endif
+
+#if PX_DEBUG || PX_PROFILE
+ struct DebugBlock
+ {
+ const char* mFilename;
+#if !PX_P64_FAMILY
+ PxU32 mPad0;
+#endif
+
+ const char* mHandle;
+#if !PX_P64_FAMILY
+ PxU32 mPadHandle;
+#endif
+ PxU32 mCheckValue;
+ PxU32 mSize;
+ PxU32 mSlotIndex;
+ PxU32 mLine;
+ };
+
+PX_COMPILE_TIME_ASSERT(!(sizeof(DebugBlock)&15));
+#endif
+
+PxSampleAllocator::PxSampleAllocator() :
+ mMemBlockList (NULL),
+ mMemBlockListSize (0),
+ mFirstFree (INVALID_ID),
+ mMemBlockUsed (0),
+ mNbAllocatedBytes (0),
+ mHighWaterMark (0),
+ mTotalNbAllocs (0),
+ mNbAllocs (0)
+{
+#if PX_DEBUG || PX_PROFILE
+ // Initialize the Memory blocks list (DEBUG mode only)
+ mMemBlockList = (void**)::malloc(MEMBLOCKSTART*sizeof(void*));
+ memset(mMemBlockList, 0, MEMBLOCKSTART*sizeof(void*));
+ mMemBlockListSize = MEMBLOCKSTART;
+#endif
+}
+
+PxSampleAllocator::~PxSampleAllocator()
+{
+#if PX_DEBUG || PX_PROFILE
+ char buffer[4096];
+ if(mNbAllocatedBytes)
+ {
+ sprintf(buffer, "Memory leak detected: %d bytes non released\n", mNbAllocatedBytes);
+ print(buffer);
+ }
+ if(mNbAllocs)
+ {
+ sprintf(buffer, "Remaining allocs: %d\n", mNbAllocs);
+ print(buffer);
+ }
+ sprintf(buffer, "Total nb alloc: %d\n", mTotalNbAllocs);
+ print(buffer);
+ sprintf(buffer, "High water mark: %d Kb\n", mHighWaterMark/1024);
+ print(buffer);
+
+ // Scanning for memory leaks
+ if(mMemBlockList && mNbAllocs)
+ {
+ PxU32 NbLeaks = 0;
+ sprintf(buffer, "\n\n SampleAllocator: Memory leaks detected :\n\n");
+ print(buffer);
+
+ for(PxU32 i=0; i<mMemBlockUsed; i++)
+ {
+ if(size_t(mMemBlockList[i])&1)
+ continue;
+
+ const DebugBlock* DB = (const DebugBlock*)mMemBlockList[i];
+ sprintf(buffer, " Address 0x%p, %d bytes, allocated in: %s(%d):\n\n", DB+1, DB->mSize, DB->mFilename, DB->mLine);
+ print(buffer);
+
+ NbLeaks++;
+ }
+
+ sprintf(buffer, "\n Dump complete (%d leaks)\n\n", NbLeaks);
+ print(buffer);
+ }
+ // Free the Memory Block list
+ if(mMemBlockList) ::free(mMemBlockList);
+ mMemBlockList = NULL;
+#endif
+}
+
+void* PxSampleAllocator::allocate(size_t size, const char* typeName, const char* filename, int line)
+{
+ if(!size)
+ return NULL;
+
+#if PX_DEBUG || PX_PROFILE
+ Ps::MutexT<Ps::RawAllocator>::ScopedLock lock(mMutex);
+
+ // Allocate one debug block in front of each real allocation
+ const size_t neededSize = size + sizeof(DebugBlock);
+ void* ptr = platformAlignedAlloc(neededSize);
+
+ if (NULL != ptr)
+ {
+ // Fill debug block
+ DebugBlock* DB = (DebugBlock*)ptr;
+ DB->mCheckValue = DEBUG_IDENTIFIER;
+ DB->mSize = PxU32(size);
+ DB->mLine = line;
+ DB->mSlotIndex = INVALID_ID;
+ DB->mFilename = filename;
+ DB->mHandle = typeName ? typeName : "";
+
+ // Update global stats
+ mTotalNbAllocs++;
+ mNbAllocs++;
+ mNbAllocatedBytes += PxU32(size);
+ if(mNbAllocatedBytes>mHighWaterMark)
+ mHighWaterMark = mNbAllocatedBytes;
+
+ // Insert the allocated block in the debug memory block list
+ if(mMemBlockList)
+ {
+ if(mFirstFree!=INVALID_ID)
+ {
+ // Recycle old location
+ PxU32 NextFree = (PxU32)(size_t)(mMemBlockList[mFirstFree]);
+ if(NextFree!=INVALID_ID)
+ NextFree>>=1;
+
+ mMemBlockList[mFirstFree] = ptr;
+ DB->mSlotIndex = mFirstFree;
+
+ mFirstFree = NextFree;
+ }
+ else
+ {
+ if(mMemBlockUsed==mMemBlockListSize)
+ {
+ // Allocate a bigger block
+ void** tps = (void**)::malloc((mMemBlockListSize+MEMBLOCKSTART)*sizeof(void*));
+ // Copy already used part
+ memcpy(tps, mMemBlockList, mMemBlockListSize*sizeof(void*));
+ // Initialize remaining part
+ void* Next = tps + mMemBlockListSize;
+ memset(Next, 0, MEMBLOCKSTART*sizeof(void*));
+
+ // Free previous memory, setup new pointer
+ ::free(mMemBlockList);
+ mMemBlockList = tps;
+ // Setup new size
+ mMemBlockListSize += MEMBLOCKSTART;
+ }
+
+ mMemBlockList[mMemBlockUsed] = ptr;
+ DB->mSlotIndex = mMemBlockUsed++;
+ }
+ }
+ return ((PxU8*)ptr) + sizeof(DebugBlock);
+ }
+#else
+ void* ptr = platformAlignedAlloc(size);
+ if (NULL != ptr)
+ return ptr;
+#endif
+ getSampleErrorCallback().reportError(PxErrorCode::eOUT_OF_MEMORY, "NULL ptr returned\n", __FILE__, __LINE__);
+ return NULL;
+}
+
+void PxSampleAllocator::deallocate(void* memory)
+{
+ if(!memory)
+ return;
+
+#if PX_DEBUG || PX_PROFILE
+ Ps::MutexT<Ps::RawAllocator>::ScopedLock lock(mMutex);
+
+ DebugBlock* DB = ((DebugBlock*)memory)-1;
+
+ // Check we allocated it
+ if(DB->mCheckValue!=DEBUG_IDENTIFIER)
+ {
+ shdfnd::printFormatted("Error: free unknown memory!!\n");
+ // ### should we really continue??
+ return;
+ }
+
+ // Update global stats
+ mNbAllocatedBytes -= DB->mSize;
+ mNbAllocs--;
+
+ // Remove the block from the Memory block list
+ if(mMemBlockList)
+ {
+ PxU32 FreeSlot = DB->mSlotIndex;
+ assert(mMemBlockList[FreeSlot]==DB);
+
+ PxU32 NextFree = mFirstFree;
+ if(NextFree!=INVALID_ID)
+ {
+ NextFree<<=1;
+ NextFree|=1;
+ }
+
+ mMemBlockList[FreeSlot] = (void*)size_t(NextFree);
+ mFirstFree = FreeSlot;
+ }
+
+ // ### should be useless since we'll release the memory just afterwards
+ DB->mCheckValue = DEBUG_DEALLOCATED;
+ DB->mSize = 0;
+ DB->mHandle = 0;
+ DB->mFilename = NULL;
+ DB->mSlotIndex = INVALID_ID;
+ DB->mLine = INVALID_ID;
+
+ platformAlignedFree(DB);
+#else
+ platformAlignedFree(memory);
+#endif
+}
+
+static PxSampleAllocator* gAllocator = NULL;
+
+void initSampleAllocator()
+{
+ PX_ASSERT(!gAllocator);
+ gAllocator = new PxSampleAllocator;
+}
+
+void releaseSampleAllocator()
+{
+ DELETESINGLE(gAllocator);
+}
+
+PxSampleAllocator* getSampleAllocator()
+{
+ PX_ASSERT(gAllocator);
+ return gAllocator;
+}
diff --git a/PhysX_3.4/Samples/SampleBase/SampleAllocator.h b/PhysX_3.4/Samples/SampleBase/SampleAllocator.h
new file mode 100644
index 00000000..b7d1573c
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SampleAllocator.h
@@ -0,0 +1,87 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef SAMPLE_ALLOCATOR_H
+#define SAMPLE_ALLOCATOR_H
+
+#include "foundation/PxAllocatorCallback.h"
+#include "common/PxPhysXCommonConfig.h"
+#include "PsMutex.h"
+#include "PxTkNamespaceMangle.h"
+
+using namespace physx;
+
+ class PxSampleAllocator : public PxAllocatorCallback
+ {
+ public:
+ PxSampleAllocator();
+ ~PxSampleAllocator();
+
+ virtual void* allocate(size_t size, const char* typeName, const char* filename, int line);
+ void* allocate(size_t size, const char* filename, int line) { return allocate(size, NULL, filename, line); }
+ virtual void deallocate(void* ptr);
+
+ protected:
+ Ps::MutexT<Ps::RawAllocator> mMutex;
+
+ void** mMemBlockList;
+ PxU32 mMemBlockListSize;
+ PxU32 mFirstFree;
+ PxU32 mMemBlockUsed;
+
+ public:
+ PxI32 mNbAllocatedBytes;
+ PxI32 mHighWaterMark;
+ PxI32 mTotalNbAllocs;
+ PxI32 mNbAllocs;
+ };
+
+ void initSampleAllocator();
+ void releaseSampleAllocator();
+ PxSampleAllocator* getSampleAllocator();
+
+ class SampleAllocateable
+ {
+ public:
+ PX_FORCE_INLINE void* operator new (size_t, void* ptr) { return ptr; }
+ PX_FORCE_INLINE void* operator new (size_t size, const char* handle, const char * filename, int line) { return getSampleAllocator()->allocate(size, handle, filename, line); }
+ PX_FORCE_INLINE void* operator new[] (size_t size, const char* handle, const char * filename, int line) { return getSampleAllocator()->allocate(size, handle, filename, line); }
+ PX_FORCE_INLINE void operator delete (void* p) { getSampleAllocator()->deallocate(p); }
+ PX_FORCE_INLINE void operator delete (void* p, PxU32, const char*, int) { getSampleAllocator()->deallocate(p); }
+ PX_FORCE_INLINE void operator delete (void* p, const char*, const char *, int) { getSampleAllocator()->deallocate(p); }
+ PX_FORCE_INLINE void operator delete[] (void* p) { getSampleAllocator()->deallocate(p); }
+ PX_FORCE_INLINE void operator delete[] (void* p, PxU32, const char*, int) { getSampleAllocator()->deallocate(p); }
+ PX_FORCE_INLINE void operator delete[] (void* p, const char*, const char *, int) { getSampleAllocator()->deallocate(p); }
+ };
+
+ #define SAMPLE_ALLOC(x) getSampleAllocator()->allocate(x, 0, __FILE__, __LINE__)
+ #define SAMPLE_FREE(x) if(x) { getSampleAllocator()->deallocate(x); x = NULL; }
+ #define SAMPLE_NEW(x) new(#x, __FILE__, __LINE__) x
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/SampleAllocatorSDKClasses.h b/PhysX_3.4/Samples/SampleBase/SampleAllocatorSDKClasses.h
new file mode 100644
index 00000000..6f64440a
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SampleAllocatorSDKClasses.h
@@ -0,0 +1,47 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef SAMPLE_ALLOCATOR_SDK_CLASSES_H
+#define SAMPLE_ALLOCATOR_SDK_CLASSES_H
+
+#include "SampleAllocator.h"
+#include "foundation/PxVec3.h"
+#include "PsSync.h"
+#include "geometry/PxBoxGeometry.h"
+#include "RendererColor.h"
+#include "vehicle/PxVehicleSDK.h"
+
+ // PT: this is used to allocate SDK classes through the SampleAllocator
+
+ class PxVec3Alloc : public PxVec3, public SampleAllocateable { public: };
+ class PsSyncAlloc : public Ps::Sync, public SampleAllocateable { public: };
+ class PxBoxGeometryAlloc : public PxBoxGeometry, public SampleAllocateable { public: };
+ class RendererColorAlloc : public SampleRenderer::RendererColor, public SampleAllocateable { public: };
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/SampleArray.h b/PhysX_3.4/Samples/SampleBase/SampleArray.h
new file mode 100644
index 00000000..37a1a261
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SampleArray.h
@@ -0,0 +1,51 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+
+#ifndef SAMPLE_ARRAY
+#define SAMPLE_ARRAY
+
+#include "PsArray.h"
+#include "PsInlineArray.h"
+#include "PsHashMap.h"
+#include "PsAllocator.h"
+#include "Test.h"
+
+
+template<typename T>
+class SampleArray : public Ps::Array<T, Ps::RawAllocator>
+{
+public:
+ PX_INLINE explicit SampleArray() : Ps::Array<T, Ps::RawAllocator>() {}
+ PX_INLINE explicit SampleArray(PxU32 size, const T& a = T()) : Ps::Array<T, Ps::RawAllocator>(size, a) {}
+};
+
+
+template<typename T, PxU32 N>
+class SampleInlineArray : public Ps::InlineArray<T, N, Ps::RawAllocator> {};
+
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/SampleBaseInputEventIds.h b/PhysX_3.4/Samples/SampleBase/SampleBaseInputEventIds.h
new file mode 100644
index 00000000..a829a2d3
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SampleBaseInputEventIds.h
@@ -0,0 +1,95 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+#ifndef SAMPLE_BASE_INPUT_EVENT_IDS_H
+#define SAMPLE_BASE_INPUT_EVENT_IDS_H
+
+#include <SampleFrameworkInputEventIds.h>
+
+// InputEvents used by SampleBase
+enum SampleBaseInputEventIds
+{
+ SAMPLE_BASE_FIRST = NUM_SAMPLE_FRAMEWORK_INPUT_EVENT_IDS,
+
+ PICKUP ,
+
+ SPAWN_DEBUG_OBJECT ,
+
+ PAUSE_SAMPLE ,
+ STEP_ONE_FRAME ,
+ TOGGLE_VISUALIZATION ,
+ DECREASE_DEBUG_RENDER_SCALE ,
+ INCREASE_DEBUG_RENDER_SCALE ,
+ HIDE_GRAPHICS ,
+ WIREFRAME ,
+ TOGGLE_PVD_CONNECTION ,
+ SHOW_HELP ,
+ SHOW_DESCRIPTION ,
+ SHOW_EXTENDED_HELP ,
+ VARIABLE_TIMESTEP,
+ DELETE_PICKED,
+
+ QUIT,
+ MENU_VISUALIZATIONS,
+ MENU_SAMPLES,
+
+ MENU_ESCAPE,
+ MENU_UP,
+ MENU_DOWN,
+ MENU_LEFT,
+ MENU_RIGHT,
+ MENU_SELECT,
+
+ MENU_QUICK_UP,
+ MENU_QUICK_DOWN,
+ MENU_QUICK_LEFT,
+ MENU_QUICK_RIGHT,
+
+ TOGGLE_CPU_GPU,
+
+ MOUSE_LOOK_BUTTON,
+
+ CONSOLE_OPEN,
+ CONSOLE_ESCAPE,
+ CONSOLE_BACKSPACE,
+ CONSOLE_ENTER,
+ CONSOLE_SCROLL_UP,
+ CONSOLE_SCROLL_DOWN,
+ CONSOLE_LIST_COMMAND_UP,
+ CONSOLE_LIST_COMMAND_DOWN,
+
+ NEXT_PAGE,
+ PREVIOUS_PAGE,
+
+ RUN_NEXT_SAMPLE,
+ RUN_PREVIOUS_SAMPLE,
+
+ PROFILE_ONLY_PVD,
+
+ NUM_SAMPLE_BASE_INPUT_EVENT_IDS,
+};
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/SampleCamera.cpp b/PhysX_3.4/Samples/SampleBase/SampleCamera.cpp
new file mode 100644
index 00000000..c86d55dd
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SampleCamera.cpp
@@ -0,0 +1,481 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SampleCamera.h"
+#include "SampleUtils.h"
+#include "RenderPhysX3Debug.h"
+#include "RendererColor.h"
+
+using namespace SampleRenderer;
+
+// PT: the base camera code should be the same for all cameras, regardless of how
+// the camera is controlled. For example this should deal with VFC, etc.
+
+Camera::Camera() :
+ mProjMatrix (degtorad(45.0f), 1.0f, 1.0f, 100.0f),
+ mFOV (0.0f),
+ mNearPlane (0.0f),
+ mFarPlane (0.0f),
+ mDirtyProj (true),
+ mDirtyView (true)
+{
+ mViewMatrix = PxTransform(PxIdentity);
+ mPos = PxVec3(0);
+ mRot = PxVec3(0);
+
+ mDrawDebugData = false;
+ mFreezeFrustum = false;
+ mPerformVFC = true;
+}
+
+Camera::~Camera()
+{
+}
+
+// PT: TODO: copied from SampleApplication. Refactor.
+static PxMat33 EulerToMat33(const PxVec3 &e)
+{
+ float c1 = cosf(e.z);
+ float s1 = sinf(e.z);
+ float c2 = cosf(e.y);
+ float s2 = sinf(e.y);
+ float c3 = cosf(e.x);
+ float s3 = sinf(e.x);
+ PxMat33 m(PxVec3(c1*c2, -s1*c2, s2),
+ PxVec3((s1*c3)+(c1*s2*s3), (c1*c3)-(s1*s2*s3),-c2*s3),
+ PxVec3((s1*s3)-(c1*s2*c3), (c1*s3)+(s1*s2*c3), c2*c3));
+
+ return m;
+}
+
+void Camera::updateInternals()
+{
+ if(mDirtyProj)
+ {
+ mDirtyProj = false;
+ mProjMatrix = RendererProjection(degtorad(mFOV), mViewport.computeRatio(), mNearPlane, mFarPlane);
+ }
+ if(mDirtyView)
+ {
+ mDirtyView = false;
+
+ mViewMatrix.q = PxQuat(EulerToMat33(mRot));
+ mViewMatrix.p = mPos;
+ }
+}
+
+PxVec3 Camera::getViewDir() const
+{
+ const PxTransform& camPose = getViewMatrix();
+ PxVec3 forward = PxMat33(camPose.q)[2];
+ return -forward;
+}
+
+void Camera::lookAt(const PxVec3& position, const PxVec3& target)
+{
+ PxVec3 dir, right, up;
+ Ps::computeBasis(position, target, dir, right, up);
+
+ PxTransform view;
+ view.p = position;
+ view.q = PxQuat(PxMat33(-right, up, -dir));
+ setView(view);
+}
+
+
+ enum FrustumPlaneIndex
+ {
+ FRUSTUM_PLANE_LEFT = 0, //!< Left clipping plane
+ FRUSTUM_PLANE_RIGHT = 1, //!< Right clipping plane
+ FRUSTUM_PLANE_TOP = 2, //!< Top clipping plane
+ FRUSTUM_PLANE_BOTTOM = 3, //!< Bottom clipping plane
+ FRUSTUM_PLANE_NEAR = 4, //!< Near clipping plane
+ FRUSTUM_PLANE_FAR = 5, //!< Far clipping plane (must be last for infinite far clip)
+
+ FRUSTUM_PLANE_FORCE_DWORD = 0x7fffffff
+ };
+
+static PxMat44 convertViewMatrix(const PxTransform& eye)
+{
+ PxTransform viewMatrix = eye.getInverse();
+ PxMat44 mat44 = PxMat44(viewMatrix).getTranspose();
+
+ float m[16];
+ memcpy(m, mat44.front(), sizeof m);
+
+ PxMat44 view44;
+ view44.column0.x = m[0];
+ view44.column0.y = m[1];
+ view44.column0.z = m[2];
+ view44.column0.w = m[3];
+ view44.column1.x = m[4];
+ view44.column1.y = m[5];
+ view44.column1.z = m[6];
+ view44.column1.w = m[7];
+ view44.column2.x = m[8];
+ view44.column2.y = m[9];
+ view44.column2.z = m[10];
+ view44.column2.w = m[11];
+ view44.column3.x = m[12];
+ view44.column3.y = m[13];
+ view44.column3.z = m[14];
+ view44.column3.w = m[15];
+
+PxMat44 tmpmat = view44.getTranspose(); view44 = tmpmat;
+
+ return view44;
+}
+
+static PxMat44 convertProjMatrix(const RendererProjection& proj)
+{
+ float renderProjMatrix[16];
+ proj.getColumnMajor44(renderProjMatrix);
+
+ PxMat44 proj44;
+ proj44.column0.x = renderProjMatrix[0];
+ proj44.column0.y = renderProjMatrix[1];
+ proj44.column0.z = renderProjMatrix[2];
+ proj44.column0.w = renderProjMatrix[3];
+ proj44.column1.x = renderProjMatrix[4];
+ proj44.column1.y = renderProjMatrix[5];
+ proj44.column1.z = renderProjMatrix[6];
+ proj44.column1.w = renderProjMatrix[7];
+ proj44.column2.x = renderProjMatrix[8];
+ proj44.column2.y = renderProjMatrix[9];
+ proj44.column2.z = renderProjMatrix[10];
+ proj44.column2.w = renderProjMatrix[11];
+ proj44.column3.x = renderProjMatrix[12];
+ proj44.column3.y = renderProjMatrix[13];
+ proj44.column3.z = renderProjMatrix[14];
+ proj44.column3.w = renderProjMatrix[15];
+
+//PxMat44 tmpmat = proj44.getTranspose(); proj44 = tmpmat;
+
+ return proj44;
+}
+
+void Camera::BuildFrustum()
+{
+ if(mFreezeFrustum)
+ return;
+
+ // PT: a better way is to extract the planes from the view-proj matrix but it has some subtle differences with D3D/GL.
+ // Building the frustum explicitly is just easier here (although not as efficient)
+
+ const PxReal ratio = mViewport.computeRatio();
+
+ const PxReal Tan = tanf(degtorad(0.5f * mFOV)) / ratio;
+
+ const PxReal nearCoeff = mNearPlane * Tan;
+ const PxReal farCoeff = mFarPlane * Tan;
+
+ const PxReal rightCoeff = ratio;
+ const PxReal upCoeff = 1.0f;
+
+ const PxTransform& view = getViewMatrix();
+ PxMat33 mat33(view.q);
+ PxVec3 right = mat33[0];
+ PxVec3 up = mat33[1];
+ PxVec3 forward =-mat33[2];
+
+ mFrustum[0] = mPos + forward*mNearPlane - right*nearCoeff*rightCoeff + up*nearCoeff*upCoeff;
+ mFrustum[1] = mPos + forward*mNearPlane - right*nearCoeff*rightCoeff - up*nearCoeff*upCoeff;
+ mFrustum[2] = mPos + forward*mNearPlane + right*nearCoeff*rightCoeff - up*nearCoeff*upCoeff;
+ mFrustum[3] = mPos + forward*mNearPlane + right*nearCoeff*rightCoeff + up*nearCoeff*upCoeff;
+
+ mFrustum[4] = mPos + forward*mFarPlane - right*farCoeff*rightCoeff + up*farCoeff*upCoeff;
+ mFrustum[5] = mPos + forward*mFarPlane - right*farCoeff*rightCoeff - up*farCoeff*upCoeff;
+ mFrustum[6] = mPos + forward*mFarPlane + right*farCoeff*rightCoeff - up*farCoeff*upCoeff;
+ mFrustum[7] = mPos + forward*mFarPlane + right*farCoeff*rightCoeff + up*farCoeff*upCoeff;
+
+ if(1)
+ {
+ mPlanes[0] = PxPlane(mFrustum[4], mFrustum[1], mFrustum[5]);
+ mPlanes[1] = PxPlane(mFrustum[6], mFrustum[3], mFrustum[7]);
+ mPlanes[2] = PxPlane(mFrustum[4], mFrustum[7], mFrustum[3]);
+ mPlanes[3] = PxPlane(mFrustum[1], mFrustum[6], mFrustum[5]);
+ mPlanes[4] = PxPlane(mFrustum[0], mFrustum[2], mFrustum[1]);
+ mPlanes[5] = PxPlane(mFrustum[5], mFrustum[7], mFrustum[4]);
+
+ {
+ for(int i=0;i<6;i++)
+ {
+ mPlanes[i].n = -mPlanes[i].n;
+ mPlanes[i].d = -mPlanes[i].d;
+ }
+ }
+ }
+
+ if(0)
+ {
+ //
+ const PxVec3 axisX(1.0f, 0.0f, 0.0f);
+ const PxVec3 axisY(0.0f, 1.0f, 0.0f);
+ const PxVec3 axisZ(0.0f, 0.0f, 1.0f);
+
+ PxQuat RotX(degtorad(0.5f * mFOV), axisX);
+ PxQuat RotY(degtorad(0.5f * mFOV), axisY);
+ PxQuat RotZ(degtorad(0.5f * mFOV), axisZ);
+
+ PxVec3 tmp1 = RotY.rotate(-axisX);
+ PxVec3 tmp11 = view.q.rotate(tmp1); // Plane0
+ mPlanes[0].n = tmp11;
+ mPlanes[0].d = - mPos.dot(mPlanes[0].n);
+ //
+
+ RotY = PxQuat(-degtorad(0.5f * mFOV), axisY);
+
+ PxVec3 tmpy = RotY.rotate(axisX);
+ PxVec3 tmpyy = view.q.rotate(tmpy); // Plane1
+ mPlanes[1].n = tmpyy;
+ mPlanes[1].d = - mPos.dot(mPlanes[1].n);
+
+ //
+
+ RotX = PxQuat(degtorad(0.5f * mFOV)/ratio, axisX);
+ PxVec3 tmpx = RotX.rotate(axisY);
+ PxVec3 tmpxx = view.q.rotate(tmpx); // Plane2?
+ mPlanes[2].n = tmpxx;
+ mPlanes[2].d = - mPos.dot(mPlanes[2].n);
+
+ //
+
+ RotX = PxQuat(-degtorad(0.5f * mFOV)/ratio, axisX);
+ tmpx = RotX.rotate(axisY);
+ tmpxx = view.q.rotate(tmpx); // -Plane3?
+ mPlanes[3].n = -tmpxx;
+ mPlanes[3].d = - mPos.dot(mPlanes[3].n);
+
+ //
+
+ mPlanes[4].n = -forward;
+ mPlanes[4].d = - (mPos.dot(mPlanes[4].n) + forward.dot(mPlanes[4].n)*mNearPlane);
+
+ mPlanes[5].n = forward;
+ mPlanes[5].d = - (mPos.dot(mPlanes[5].n) + forward.dot(mPlanes[5].n)*mFarPlane);
+ }
+
+
+ if(0)
+ {
+ PxMat44 proj44 = convertProjMatrix(mProjMatrix);
+ PxMat44 view44 = convertViewMatrix(view);
+// PxMat44 combo44 = view44 * proj44;
+ PxMat44 combo44 = proj44 * view44;
+
+ PxReal combo[4][4];
+ PxReal* dst = &combo[0][0];
+ memcpy(dst, &combo44, sizeof(PxReal)*16);
+
+ // D3D:
+ // -w' < x' < w'
+ // -w' < y' < w'
+ // 0 < z' < w'
+ //
+ // GL:
+ // -w' < x' < w'
+ // -w' < y' < w'
+ // -w' < z' < w'
+
+ // Left clipping plane
+ mPlanes[FRUSTUM_PLANE_LEFT].n.x = -(combo[0][3] + combo[0][0]);
+ mPlanes[FRUSTUM_PLANE_LEFT].n.y = -(combo[1][3] + combo[1][0]);
+ mPlanes[FRUSTUM_PLANE_LEFT].n.z = -(combo[2][3] + combo[2][0]);
+ mPlanes[FRUSTUM_PLANE_LEFT].d = -(combo[3][3] + combo[3][0]);
+
+ // Right clipping plane
+ mPlanes[FRUSTUM_PLANE_RIGHT].n.x = -(combo[0][3] - combo[0][0]);
+ mPlanes[FRUSTUM_PLANE_RIGHT].n.y = -(combo[1][3] - combo[1][0]);
+ mPlanes[FRUSTUM_PLANE_RIGHT].n.z = -(combo[2][3] - combo[2][0]);
+ mPlanes[FRUSTUM_PLANE_RIGHT].d = -(combo[3][3] - combo[3][0]);
+
+ // Top clipping plane
+ mPlanes[FRUSTUM_PLANE_TOP].n.x = -(combo[0][3] - combo[0][1]);
+ mPlanes[FRUSTUM_PLANE_TOP].n.y = -(combo[1][3] - combo[1][1]);
+ mPlanes[FRUSTUM_PLANE_TOP].n.z = -(combo[2][3] - combo[2][1]);
+ mPlanes[FRUSTUM_PLANE_TOP].d = -(combo[3][3] - combo[3][1]);
+
+ // Bottom clipping plane
+ mPlanes[FRUSTUM_PLANE_BOTTOM].n.x = -(combo[0][3] + combo[0][1]);
+ mPlanes[FRUSTUM_PLANE_BOTTOM].n.y = -(combo[1][3] + combo[1][1]);
+ mPlanes[FRUSTUM_PLANE_BOTTOM].n.z = -(combo[2][3] + combo[2][1]);
+ mPlanes[FRUSTUM_PLANE_BOTTOM].d = -(combo[3][3] + combo[3][1]);
+
+ // Near clipping plane
+ if(1)
+ {
+ // OpenGL path
+ mPlanes[FRUSTUM_PLANE_NEAR].n.x = -(combo[0][3] + combo[0][2]);
+ mPlanes[FRUSTUM_PLANE_NEAR].n.y = -(combo[1][3] + combo[1][2]);
+ mPlanes[FRUSTUM_PLANE_NEAR].n.z = -(combo[2][3] + combo[2][2]);
+ mPlanes[FRUSTUM_PLANE_NEAR].d = -(combo[3][3] + combo[3][2]);
+ }
+ else
+ {
+ // D3D path
+ mPlanes[FRUSTUM_PLANE_NEAR].n.x = - combo[0][2];
+ mPlanes[FRUSTUM_PLANE_NEAR].n.y = - combo[1][2];
+ mPlanes[FRUSTUM_PLANE_NEAR].n.z = - combo[2][2];
+ mPlanes[FRUSTUM_PLANE_NEAR].d = - combo[3][2];
+ }
+
+ // Far clipping plane (must be last for infinite far clip)
+ mPlanes[FRUSTUM_PLANE_FAR].n.x = -(combo[0][3] - combo[0][2]);
+ mPlanes[FRUSTUM_PLANE_FAR].n.y = -(combo[1][3] - combo[1][2]);
+ mPlanes[FRUSTUM_PLANE_FAR].n.z = -(combo[2][3] - combo[2][2]);
+ mPlanes[FRUSTUM_PLANE_FAR].d = -(combo[3][3] - combo[3][2]);
+
+ // Normalize if needed
+ for(PxU32 i=0;i<6;i++)
+ {
+// mPlanes[i].normalize();
+ mPlanes[i].n.normalize();
+// mPlanes[i].normal = -mPlanes[i].normal;
+// mPlanes[i].d = -mPlanes[i].d;
+ mPlanes[i].d *= 0.5f;
+ }
+ }
+}
+
+ // Following code from Umbra/dPVS.
+
+ //------------------------------------------------------------------------
+ //
+ // Function: DPVS::intersectAABBFrustum()
+ //
+ // Description: Determines whether an AABB intersects a frustum
+ //
+ // Parameters: a = reference to AABB (defined by minimum & maximum vectors)
+ // p = array of pre-normalized clipping planes
+ // outClipMask = output clip mask (if function returns 'true')
+ // inClipMask = input clip mask (indicates which planes are active)
+ //
+ // Returns: true if AABB intersects the frustum, false otherwise
+ //
+ // Intersection of AABB and a frustum. The frustum may
+ // contain 0-32 planes (active planes are defined by inClipMask).
+ // If AABB intersects the frustum, an output clip mask is returned
+ // as well (indicating which planes are crossed by the AABB). This
+ // information can be used to optimize testing of child nodes or
+ // objects inside the nodes (pass value as 'inClipMask' next time).
+ //
+ // This is a variant of the classic "fast" AABB/frustum
+ // intersection tester. AABBs that are not culled away by any single
+ // plane are classified as "intersecting" even though the AABB may
+ // actually be outside the convex volume formed by the planes.
+ //------------------------------------------------------------------------
+
+static PX_FORCE_INLINE bool planesAABBOverlap(const PxBounds3& a, const PxPlane* p, PxU32& out_clip_mask, PxU32 in_clip_mask)
+ {
+ //------------------------------------------------------------------------
+ // Convert the AABB from (minimum,maximum) form into (center,half-diagonal).
+ // Note that we could get rid of these six subtractions and three
+ // multiplications if the AABB was originally expressed in (center,
+ // half-diagonal) form.
+ //------------------------------------------------------------------------
+
+ PxVec3 m = a.getCenter(); // get center of AABB ((minimum+maximum)*0.5f)
+ PxVec3 d = a.maximum; d-=m; // get positive half-diagonal (maximum - center)
+
+ //------------------------------------------------------------------------
+ // Evaluate through all active frustum planes. We determine the relation
+ // between the AABB and a plane by using the concept of "near" and "far"
+ // vertices originally described by Zhang (and later by Moeller). Our
+ // variant here uses 3 fabs ops, 6 muls, 7 adds and two floating point
+ // comparisons per plane. The routine early-exits if the AABB is found
+ // to be outside any of the planes. The loop also constructs a new output
+ // clip mask. Most FPUs have a native single-cycle fabsf() operation.
+ //------------------------------------------------------------------------
+
+ PxU32 Mask = 1; // current mask index (1,2,4,8,..)
+ PxU32 TmpOutClipMask = 0; // initialize output clip mask into empty.
+
+ while(Mask<=in_clip_mask) // keep looping while we have active planes left...
+ {
+ if(in_clip_mask & Mask) // if clip plane is active, process it..
+ {
+ const float NP = d.x*PxAbs(p->n.x) + d.y*PxAbs(p->n.y) + d.z*PxAbs(p->n.z);
+ const float MP = m.x*p->n.x + m.y*p->n.y + m.z*p->n.z + p->d;
+
+ if(NP < MP) // near vertex behind the clip plane...
+ return false; // .. so there is no intersection..
+ if((-NP) < MP) // near and far vertices on different sides of plane..
+ TmpOutClipMask |= Mask; // .. so update the clip mask...
+ }
+ Mask+=Mask; // mk = (1<<plane)
+ p++; // advance to next plane
+ }
+
+ out_clip_mask = TmpOutClipMask; // copy output value (temp used to resolve aliasing!)
+ return true; // indicate that AABB intersects frustum
+ }
+
+PlaneAABBCode Camera::cull(const PxBounds3& aabb) const
+{
+ const PxU32 nbFrustumPlanes = 6; // PT: can sometimes be 5 with infinite far clip plane
+ const PxU32 frustumPlanesMask = (1<<nbFrustumPlanes)-1;
+
+ PxU32 outClipMask;
+ if(!planesAABBOverlap(aabb, mPlanes, outClipMask, frustumPlanesMask))
+ return PLANEAABB_EXCLUSION;
+
+ if(outClipMask)
+ return PLANEAABB_INTERSECT;
+
+ return PLANEAABB_INCLUSION;
+}
+
+void Camera::drawDebug(RenderPhysX3Debug* debug)
+{
+ if(mDrawDebugData)
+ {
+/* for(PxU32 i=0;i<8;i++)
+ {
+ debug->addLine(mFrustum[i], mFrustum[i]+PxVec3(1,0,0), RendererColor(255,0,0));
+ debug->addLine(mFrustum[i], mFrustum[i]+PxVec3(0,1,0), RendererColor(0, 255,0));
+ debug->addLine(mFrustum[i], mFrustum[i]+PxVec3(0,0,1), RendererColor(0, 0, 255));
+ }*/
+
+ const RendererColor lineColor(255, 255, 0);
+ debug->addLine(mFrustum[0], mFrustum[1], lineColor);
+ debug->addLine(mFrustum[1], mFrustum[2], lineColor);
+ debug->addLine(mFrustum[2], mFrustum[3], lineColor);
+ debug->addLine(mFrustum[3], mFrustum[0], lineColor);
+
+ debug->addLine(mFrustum[4], mFrustum[5], lineColor);
+ debug->addLine(mFrustum[5], mFrustum[6], lineColor);
+ debug->addLine(mFrustum[6], mFrustum[7], lineColor);
+ debug->addLine(mFrustum[7], mFrustum[4], lineColor);
+
+ debug->addLine(mFrustum[0], mFrustum[4], lineColor);
+ debug->addLine(mFrustum[3], mFrustum[7], lineColor);
+ debug->addLine(mFrustum[1], mFrustum[5], lineColor);
+ debug->addLine(mFrustum[6], mFrustum[2], lineColor);
+ }
+}
diff --git a/PhysX_3.4/Samples/SampleBase/SampleCamera.h b/PhysX_3.4/Samples/SampleBase/SampleCamera.h
new file mode 100644
index 00000000..5abd18ff
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SampleCamera.h
@@ -0,0 +1,157 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef SAMPLE_CAMERA_H
+#define SAMPLE_CAMERA_H
+
+#include "SampleAllocator.h"
+#include "RendererProjection.h"
+#include "foundation/PxPlane.h"
+
+ class RenderPhysX3Debug;
+
+ struct Viewport : public SampleAllocateable
+ {
+ Viewport() : mClientWidth(0), mClientHeight(0), mWindowWidth(0), mWindowHeight(0) {}
+
+ PxU32 mClientWidth;
+ PxU32 mClientHeight;
+ PxU32 mWindowWidth;
+ PxU32 mWindowHeight;
+
+ PX_FORCE_INLINE PxReal computeRatio() const { return PxReal(mWindowWidth)/PxReal(mWindowHeight); }
+ };
+
+ enum PlaneAABBCode
+ {
+ PLANEAABB_EXCLUSION,
+ PLANEAABB_INTERSECT,
+ PLANEAABB_INCLUSION
+ };
+
+ class Camera : public SampleAllocateable
+ {
+ public:
+ Camera();
+ ~Camera();
+
+ ///////////////////////////////////////////////////////////////////////////////
+
+ // Projection part
+
+ PX_FORCE_INLINE PxReal getFOV() const { return mFOV; }
+ PX_FORCE_INLINE PxReal getNearPlane() const { return mNearPlane; }
+ PX_FORCE_INLINE PxReal getFarPlane() const { return mFarPlane; }
+ PX_FORCE_INLINE PxU32 getScreenWidth() const { return mViewport.mClientWidth; }
+ PX_FORCE_INLINE PxU32 getScreenHeight() const { return mViewport.mClientHeight; }
+
+ PX_FORCE_INLINE void setFOV(PxReal fov) { mFOV = fov; mDirtyProj = true; }
+ PX_FORCE_INLINE void setNearPlane(PxReal d) { mNearPlane = d; mDirtyProj = true; }
+ PX_FORCE_INLINE void setFarPlane(PxReal d) { mFarPlane = d; mDirtyProj = true; }
+ PX_FORCE_INLINE void setScreenSize(PxU32 clientWidth, PxU32 clientHeight, PxU32 windowWidth, PxU32 windowHeight)
+ {
+ mViewport.mClientWidth = clientWidth;
+ mViewport.mClientHeight = clientHeight;
+ mViewport.mWindowWidth = windowWidth;
+ mViewport.mWindowHeight = windowHeight;
+ mDirtyProj = true;
+ }
+
+ PX_FORCE_INLINE const SampleRenderer::RendererProjection&
+ getProjMatrix() const
+ {
+ if(mDirtyProj)
+ const_cast<Camera*>(this)->updateInternals();
+
+ return mProjMatrix;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////
+
+ // View part
+
+ PX_FORCE_INLINE const PxVec3& getPos() const { return mPos; }
+ PX_FORCE_INLINE const PxVec3& getRot() const { return mRot; }
+
+ PX_FORCE_INLINE void setPos(const PxVec3& pos) { mPos = pos; mDirtyView = true; }
+ PX_FORCE_INLINE void setRot(const PxVec3& rot) { mRot = rot; mDirtyView = true; }
+ PX_FORCE_INLINE void setView(const PxTransform& view) { mViewMatrix = view; mPos = view.p; mDirtyView = false; }
+
+ PX_FORCE_INLINE const PxTransform& getViewMatrix() const
+ {
+ if(mDirtyView)
+ const_cast<Camera*>(this)->updateInternals();
+
+ return mViewMatrix;
+ }
+
+ PxVec3 getViewDir() const;
+ void lookAt(const PxVec3& position, const PxVec3& target);
+
+ ///////////////////////////////////////////////////////////////////////////////
+
+ PX_FORCE_INLINE const PxVec3* getFrustumVerts() const { return mFrustum; }
+
+ ///////////////////////////////////////////////////////////////////////////////
+
+ // Culling
+
+ PlaneAABBCode cull(const PxBounds3& aabb) const;
+ bool mDrawDebugData;
+ bool mFreezeFrustum;
+ bool mPerformVFC;
+
+ ///////////////////////////////////////////////////////////////////////////////
+
+ void drawDebug(RenderPhysX3Debug*);
+ private:
+ mutable SampleRenderer::RendererProjection
+ mProjMatrix;
+ mutable PxTransform mViewMatrix;
+
+ PxVec3 mPos;
+ PxVec3 mRot;
+
+ Viewport mViewport;
+ PxReal mFOV;
+ PxReal mNearPlane;
+ PxReal mFarPlane;
+
+ PxVec3 mFrustum[8]; //!< Frustum's vertices
+ PxPlane mPlanes[6]; //!< Frustum's planes
+
+ bool mDirtyProj;
+ bool mDirtyView;
+
+ void updateInternals();
+ public:
+ void BuildFrustum();
+ };
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/SampleCameraController.cpp b/PhysX_3.4/Samples/SampleBase/SampleCameraController.cpp
new file mode 100644
index 00000000..161a0928
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SampleCameraController.cpp
@@ -0,0 +1,274 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SamplePreprocessor.h"
+#include "SampleCameraController.h"
+#include "SampleCamera.h"
+#include "SampleApplication.h"
+#include "SamplePlatform.h"
+#include "PsUtilities.h"
+#include "SampleBaseInputEventIds.h"
+#include <SampleFrameworkInputEventIds.h>
+#include "SampleUserInputDefines.h"
+
+#include <SampleUserInputIds.h>
+
+using namespace physx;
+using namespace SampleRenderer;
+using namespace SampleFramework;
+
+// PT: this replicates the default SampleApplication behaviour, but with a much better design. We
+// want to be able to isolate & replace the camera controlling code easily.
+
+static const float g_smoothCamBaseVel = 6.0f;
+static const float g_smoothCamPosLerp = 0.4f;
+static const float g_smoothCamFastMul = 4.0f;
+
+static const float g_smoothCamRotSpeed = 0.005f;
+static const float g_smoothCamRotLerp = 0.4f;
+
+static PxReal gGamepadYawInc = 0.0f;
+static PxReal gGamepadPitchInc = 0.0f;
+static PxReal gGamepadForwardInc = 0.0f;
+static PxReal gGamepadLateralInc = 0.0f;
+
+static PxVec3 QuatToEuler(const PxQuat& q)
+{
+ PxVec3 dir = -PxMat33(q)[2];
+ PxReal r = PxSqrt(dir.x * dir.x + dir.z * dir.z);
+ PxVec3 rot(0.0f, PxHalfPi, 0.0f);
+ if (r != 0.0f)
+ {
+ rot.x = -PxAtan(dir.y / r);
+ rot.y = PxAsin(dir.x / r);
+ if (dir.z > 0.0f)
+ rot.y = PxPi - rot.y;
+ }
+
+ return rot;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+DefaultCameraController::DefaultCameraController() :
+ mMouseButtonDown (false),
+ mKeyFWDown (false),
+ mKeyBKDown (false),
+ mKeyRTDown (false),
+ mKeyLTDown (false),
+ mKeyUpDown (false),
+ mKeyDownDown (false),
+ mKeyShiftDown (false),
+ mCameraSpeed (0.f),
+ mCameraSpeedMultiplier (1.f),
+ mMouseLookOnMB (true),
+ mMouseSensitivity (1.f)
+{
+ mTargetEyePos = PxVec3(0);
+ mTargetEyeRot = PxVec3(0);
+ mEyePos = PxVec3(0);
+ mEyeRot = PxVec3(0);
+}
+
+DefaultCameraController::~DefaultCameraController()
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void DefaultCameraController::init(const PxVec3& pos, const PxVec3& rot)
+{
+ mTargetEyePos = mEyePos = pos;
+ mTargetEyeRot = mEyeRot = rot;
+}
+
+void DefaultCameraController::init(const PxTransform& pose)
+{
+ init(pose.p, QuatToEuler(pose.q));
+}
+
+void DefaultCameraController::onPointerInputEvent(const InputEvent& ie, physx::PxU32 x, physx::PxU32 y, physx::PxReal dx, physx::PxReal dy, bool val)
+{
+ switch (ie.m_Id)
+ {
+ case CAMERA_MOUSE_LOOK:
+ {
+ if (!mMouseLookOnMB || mMouseButtonDown)
+ onMouseDelta(static_cast<physx::PxI32>(dx), static_cast<physx::PxI32>(dy));
+ }
+ break;
+ case MOUSE_LOOK_BUTTON:
+ {
+ mMouseButtonDown = val;
+ }
+ break;
+ }
+
+}
+
+void DefaultCameraController::onMouseDelta(PxI32 dx, PxI32 dy)
+{
+ mTargetEyeRot.x -= dy * mMouseSensitivity * g_smoothCamRotSpeed;
+ mTargetEyeRot.y += dx * mMouseSensitivity * g_smoothCamRotSpeed;
+}
+
+void DefaultCameraController::collectInputEvents(std::vector<const InputEvent*>& inputEvents)
+{
+ //digital keyboard events
+ DIGITAL_INPUT_EVENT_DEF(CAMERA_MOVE_FORWARD, SCAN_CODE_FORWARD, XKEY_W, X1KEY_W, PS3KEY_W, PS4KEY_W, AKEY_UNKNOWN, SCAN_CODE_FORWARD, IKEY_UNKNOWN, SCAN_CODE_FORWARD, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(CAMERA_MOVE_BACKWARD, SCAN_CODE_BACKWARD, XKEY_S, X1KEY_S, PS3KEY_S, PS4KEY_S, AKEY_UNKNOWN, SCAN_CODE_BACKWARD, IKEY_UNKNOWN, SCAN_CODE_BACKWARD, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(CAMERA_MOVE_UP, SCAN_CODE_UP, XKEY_E, X1KEY_E, PS3KEY_E, PS4KEY_E, AKEY_UNKNOWN, SCAN_CODE_UP, IKEY_UNKNOWN, SCAN_CODE_UP, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(CAMERA_MOVE_DOWN, SCAN_CODE_DOWN, XKEY_C, X1KEY_C, PS3KEY_C, PS4KEY_C, AKEY_UNKNOWN, SCAN_CODE_DOWN, IKEY_UNKNOWN, SCAN_CODE_DOWN, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(CAMERA_MOVE_LEFT, SCAN_CODE_LEFT, XKEY_A, X1KEY_A, PS3KEY_A, PS4KEY_A, AKEY_UNKNOWN, SCAN_CODE_LEFT, IKEY_UNKNOWN, SCAN_CODE_LEFT, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(CAMERA_MOVE_RIGHT, SCAN_CODE_RIGHT, XKEY_D, X1KEY_D, PS3KEY_D, PS4KEY_D, AKEY_UNKNOWN, SCAN_CODE_RIGHT, IKEY_UNKNOWN, SCAN_CODE_RIGHT, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(CAMERA_SHIFT_SPEED, SCAN_CODE_LEFT_SHIFT, XKEY_SHIFT, X1KEY_SHIFT, PS3KEY_SHIFT, PS4KEY_SHIFT, AKEY_UNKNOWN, OSXKEY_SHIFT, IKEY_UNKNOWN, LINUXKEY_SHIFT, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(CAMERA_SPEED_INCREASE, WKEY_ADD, XKEY_ADD, X1KEY_ADD, PS3KEY_ADD, PS4KEY_ADD, AKEY_UNKNOWN, OSXKEY_ADD, IKEY_UNKNOWN, LINUXKEY_ADD, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(CAMERA_SPEED_DECREASE, WKEY_SUBTRACT, XKEY_SUBTRACT, X1KEY_SUBTRACT, PS3KEY_SUBTRACT, PS4KEY_SUBTRACT, AKEY_UNKNOWN, OSXKEY_SUBTRACT, IKEY_UNKNOWN, LINUXKEY_SUBTRACT, WIIUKEY_UNKNOWN);
+
+ //digital mouse events
+ DIGITAL_INPUT_EVENT_DEF(MOUSE_LOOK_BUTTON, MOUSE_BUTTON_LEFT, XKEY_UNKNOWN, X1KEY_UNKNOWN, PS3KEY_UNKNOWN, PS4KEY_UNKNOWN, AKEY_UNKNOWN, MOUSE_BUTTON_LEFT, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, WIIUKEY_UNKNOWN);
+
+ //digital gamepad events
+ DIGITAL_INPUT_EVENT_DEF(CAMERA_SPEED_INCREASE, GAMEPAD_LEFT_STICK, GAMEPAD_LEFT_STICK, GAMEPAD_LEFT_STICK, GAMEPAD_LEFT_STICK, GAMEPAD_LEFT_STICK, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_LEFT_STICK);
+ DIGITAL_INPUT_EVENT_DEF(CAMERA_SPEED_DECREASE, GAMEPAD_RIGHT_STICK, GAMEPAD_RIGHT_STICK, GAMEPAD_RIGHT_STICK, GAMEPAD_LEFT_STICK, GAMEPAD_LEFT_STICK, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK);
+
+ //analog gamepad events
+ ANALOG_INPUT_EVENT_DEF(CAMERA_GAMEPAD_ROTATE_LEFT_RIGHT, GAMEPAD_ROTATE_SENSITIVITY, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, LINUXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK_X);
+ ANALOG_INPUT_EVENT_DEF(CAMERA_GAMEPAD_ROTATE_UP_DOWN, GAMEPAD_ROTATE_SENSITIVITY, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, LINUXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK_Y);
+ ANALOG_INPUT_EVENT_DEF(CAMERA_GAMEPAD_MOVE_LEFT_RIGHT, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, LINUXKEY_UNKNOWN, GAMEPAD_LEFT_STICK_X);
+ ANALOG_INPUT_EVENT_DEF(CAMERA_GAMEPAD_MOVE_FORWARD_BACK, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, LINUXKEY_UNKNOWN, GAMEPAD_LEFT_STICK_Y);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void DefaultCameraController::onDigitalInputEvent(const SampleFramework::InputEvent& ie, bool val)
+{
+ if(val)
+ {
+ if(ie.m_Id == CAMERA_MOVE_FORWARD) mKeyFWDown = true;
+ else if(ie.m_Id == CAMERA_MOVE_UP) mKeyUpDown = true;
+ else if(ie.m_Id == CAMERA_MOVE_BACKWARD) mKeyBKDown = true;
+ else if(ie.m_Id == CAMERA_MOVE_LEFT) mKeyLTDown = true;
+ else if(ie.m_Id == CAMERA_MOVE_RIGHT) mKeyRTDown = true;
+ else if(ie.m_Id == CAMERA_SHIFT_SPEED) mKeyShiftDown = true;
+ else if(ie.m_Id == CAMERA_MOVE_DOWN) mKeyDownDown = true;
+ else if(ie.m_Id == CAMERA_SPEED_DECREASE) mCameraSpeedMultiplier *= 0.5f;
+ else if(ie.m_Id == CAMERA_SPEED_INCREASE) mCameraSpeedMultiplier *= 2.0f;
+ }
+ else
+ {
+ if(ie.m_Id == CAMERA_MOVE_FORWARD) mKeyFWDown = false;
+ else if(ie.m_Id == CAMERA_MOVE_UP) mKeyUpDown = false;
+ else if(ie.m_Id == CAMERA_MOVE_BACKWARD) mKeyBKDown = false;
+ else if(ie.m_Id == CAMERA_MOVE_LEFT) mKeyLTDown = false;
+ else if(ie.m_Id == CAMERA_MOVE_RIGHT) mKeyRTDown = false;
+ else if(ie.m_Id == CAMERA_SHIFT_SPEED) mKeyShiftDown = false;
+ else if(ie.m_Id == CAMERA_MOVE_DOWN) mKeyDownDown = false;
+ }
+}
+
+static PX_FORCE_INLINE PxReal remapAxisValue(PxReal absolutePosition)
+{
+ return absolutePosition * absolutePosition * absolutePosition * 5.0f;
+}
+
+void DefaultCameraController::onAnalogInputEvent(const SampleFramework::InputEvent& ie, float val)
+{
+ if(ie.m_Id == CAMERA_GAMEPAD_ROTATE_LEFT_RIGHT)
+ {
+ gGamepadYawInc = remapAxisValue(val);
+ }
+ else if(ie.m_Id == CAMERA_GAMEPAD_ROTATE_UP_DOWN)
+ {
+ gGamepadPitchInc = - remapAxisValue(val);
+ }
+ else if(ie.m_Id == CAMERA_GAMEPAD_MOVE_LEFT_RIGHT)
+ {
+ gGamepadLateralInc = - val;
+ }
+ else if(ie.m_Id == CAMERA_GAMEPAD_MOVE_FORWARD_BACK)
+ {
+ gGamepadForwardInc = val;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+// PT: TODO: refactor this
+static PxMat33 EulerToMat33(const PxVec3 &e)
+{
+ float c1 = cosf(e.z);
+ float s1 = sinf(e.z);
+ float c2 = cosf(e.y);
+ float s2 = sinf(e.y);
+ float c3 = cosf(e.x);
+ float s3 = sinf(e.x);
+ PxMat33 m(PxVec3(c1*c2, -s1*c2, s2),
+ PxVec3((s1*c3)+(c1*s2*s3), (c1*c3)-(s1*s2*s3),-c2*s3),
+ PxVec3((s1*s3)-(c1*s2*c3), (c1*s3)+(s1*s2*c3), c2*c3));
+
+ return m;
+}
+
+void DefaultCameraController::update(Camera& camera, PxReal dtime)
+{
+ // PT: copied from SampleApplication::onMouseMove
+
+ const float eyeCap = 1.5f;
+
+ mTargetEyeRot.x += gGamepadPitchInc * dtime;
+ mTargetEyeRot.y += gGamepadYawInc * dtime;
+
+ if(mTargetEyeRot.x > eyeCap) mTargetEyeRot.x = eyeCap;
+ if(mTargetEyeRot.x < -eyeCap) mTargetEyeRot.x = -eyeCap;
+ mEyeRot += (mTargetEyeRot - mEyeRot) * g_smoothCamRotLerp;
+
+ const PxMat33 tmp = EulerToMat33(mEyeRot);
+ const PxVec3 forward = -tmp[2];
+ const PxVec3 right = -tmp[0];
+
+ const PxReal padEyeSpeed = mCameraSpeed == 0.f ? g_smoothCamBaseVel * mCameraSpeedMultiplier * dtime * g_smoothCamFastMul : mCameraSpeed;
+ mTargetEyePos += forward * padEyeSpeed * gGamepadForwardInc;
+ mTargetEyePos += right * padEyeSpeed * gGamepadLateralInc;
+
+ const PxReal keyEyeSpeed = mCameraSpeed == 0.f ? g_smoothCamBaseVel * mCameraSpeedMultiplier * dtime * (mKeyShiftDown ? g_smoothCamFastMul : 1.0f) : mCameraSpeed;
+ if(mKeyFWDown) mTargetEyePos -= tmp[2] * keyEyeSpeed;
+ if(mKeyBKDown) mTargetEyePos += tmp[2] * keyEyeSpeed;
+ if(mKeyLTDown) mTargetEyePos -= tmp[0] * keyEyeSpeed;
+ if(mKeyRTDown) mTargetEyePos += tmp[0] * keyEyeSpeed;
+ if(mKeyUpDown) mTargetEyePos += tmp[1] * keyEyeSpeed;
+ if(mKeyDownDown) mTargetEyePos -= tmp[1] * keyEyeSpeed;
+
+ mEyePos += (mTargetEyePos - mEyePos) * g_smoothCamPosLerp;
+
+ camera.setPos(mEyePos);
+ camera.setRot(mEyeRot);
+}
+
+///////////////////////////////////////////////////////////////////////////////
diff --git a/PhysX_3.4/Samples/SampleBase/SampleCameraController.h b/PhysX_3.4/Samples/SampleBase/SampleCameraController.h
new file mode 100644
index 00000000..6b2dd190
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SampleCameraController.h
@@ -0,0 +1,103 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef SAMPLE_CAMERA_CONTROLLER_H
+#define SAMPLE_CAMERA_CONTROLLER_H
+
+#include "SampleAllocator.h"
+#include "RendererWindow.h"
+#include <SampleUserInput.h>
+#include "foundation/PxVec3.h"
+
+namespace SampleFramework {
+ class SamplePlatform;
+}
+
+class Camera;
+
+class CameraController : public SampleAllocateable
+{
+ public:
+ virtual ~CameraController() {}
+
+ virtual void onPointerInputEvent(const SampleFramework::InputEvent& ie, physx::PxU32 x, physx::PxU32 y, physx::PxReal dx, physx::PxReal dy, bool val) {}
+
+ virtual void onAnalogInputEvent(const SampleFramework::InputEvent& , float val) {}
+ virtual void onDigitalInputEvent(const SampleFramework::InputEvent& , bool val) {}
+
+ virtual void update(Camera& camera, PxReal dtime) {}
+ virtual void collectInputEvents(std::vector<const SampleFramework::InputEvent*>& inputEvents) {}
+ virtual PxReal getCameraSpeed() { return 0; }
+};
+
+class DefaultCameraController : public CameraController
+{
+ public:
+ DefaultCameraController();
+ virtual ~DefaultCameraController();
+
+ void init(const PxVec3& pos, const PxVec3& rot);
+ void init(const PxTransform& pose);
+ void setCameraSpeed(const PxReal speed) { mCameraSpeed = speed; }
+ PxReal getCameraSpeed() { return mCameraSpeed; }
+ void setMouseLookOnMouseButton(bool mouseLookOnMB) { mMouseLookOnMB = mouseLookOnMB; }
+ void setMouseSensitivity(PxReal mouseSensitivity) { mMouseSensitivity = mouseSensitivity; }
+
+ // Implements CameraController
+ void onMouseDelta(PxI32 dx, PxI32 dy);
+
+ virtual void onAnalogInputEvent(const SampleFramework::InputEvent& , float val);
+ virtual void onDigitalInputEvent(const SampleFramework::InputEvent& , bool val);
+ virtual void onPointerInputEvent(const SampleFramework::InputEvent& ie, physx::PxU32 x, physx::PxU32 y, physx::PxReal dx, physx::PxReal dy, bool val);
+
+ virtual void collectInputEvents(std::vector<const SampleFramework::InputEvent*>& inputEvents);
+
+ virtual void update(Camera& camera, PxReal dtime);
+
+ protected:
+ PxVec3 mTargetEyePos;
+ PxVec3 mTargetEyeRot;
+ PxVec3 mEyePos;
+ PxVec3 mEyeRot;
+
+ bool mMouseButtonDown;
+ bool mKeyFWDown;
+ bool mKeyBKDown;
+ bool mKeyRTDown;
+ bool mKeyLTDown;
+ bool mKeyUpDown;
+ bool mKeyDownDown;
+ bool mKeyShiftDown;
+ PxReal mCameraSpeed;
+ PxReal mCameraSpeedMultiplier;
+ bool mMouseLookOnMB;
+ PxReal mMouseSensitivity;
+ };
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/SampleCharacterHelpers.cpp b/PhysX_3.4/Samples/SampleBase/SampleCharacterHelpers.cpp
new file mode 100644
index 00000000..9337ae01
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SampleCharacterHelpers.cpp
@@ -0,0 +1,578 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include <stdio.h>
+
+#include "SampleCharacterHelpers.h"
+
+#include "AcclaimLoader.h"
+#include "PsMathUtils.h"
+#include "SampleAllocatorSDKClasses.h"
+#include "SampleArray.h"
+
+///////////////////////////////////////////////////////////////////////////////
+static Acclaim::Bone* getBoneFromName(Acclaim::ASFData &data, const char *name)
+{
+ // use a simple linear search -> probably we could use hash map if performance is an issue
+ for (PxU32 i = 0; i < data.mNbBones; i++)
+ {
+ if (strcmp(name, data.mBones[i].mName) == 0)
+ return &data.mBones[i];
+ }
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+inline PxQuat EulerAngleToQuat(const PxVec3 &rot)
+{
+ PxQuat qx(Ps::degToRad(rot.x), PxVec3(1.0f, 0.0f, 0.0f));
+ PxQuat qy(Ps::degToRad(rot.y), PxVec3(0.0f, 1.0f, 0.0f));
+ PxQuat qz(Ps::degToRad(rot.z), PxVec3(0.0f, 0.0f, 1.0f));
+ return qz * qy * qx;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static PxTransform computeBoneTransform(PxTransform &rootTransform, Acclaim::Bone &bone, PxVec3* boneFrameData)
+{
+ using namespace Acclaim;
+
+ //PxTransform rootTransform(PxVec3(0.0f), PxQuat(PxIdentity));
+ PxTransform parentTransform = (bone.mParent) ?
+ computeBoneTransform(rootTransform, *bone.mParent, boneFrameData) : rootTransform;
+
+ PxQuat qWorld = EulerAngleToQuat(bone.mAxis);
+ PxVec3 offset = bone.mLength * bone.mDirection;
+ PxQuat qDelta = PxQuat(PxIdentity);
+ PxVec3 boneData = boneFrameData[bone.mID-1];
+
+ if (bone.mDOF & BoneDOFFlag::eRX)
+ qDelta = PxQuat(Ps::degToRad(boneData.x), PxVec3(1.0f, 0.0f, 0.0f)) * qDelta;
+ if (bone.mDOF & BoneDOFFlag::eRY)
+ qDelta = PxQuat(Ps::degToRad(boneData.y), PxVec3(0.0f, 1.0f, 0.0f)) * qDelta;
+ if (bone.mDOF & BoneDOFFlag::eRZ)
+ qDelta = PxQuat(Ps::degToRad(boneData.z), PxVec3(0.0f, 0.0f, 1.0f)) * qDelta;
+
+ PxQuat boneOrientation = qWorld * qDelta * qWorld.getConjugate();
+
+ PxTransform boneTransform(boneOrientation.rotate(offset), boneOrientation);
+
+ return parentTransform.transform(boneTransform);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static PxTransform computeBoneTransformRest(Acclaim::Bone &bone)
+{
+ using namespace Acclaim;
+
+ PxTransform parentTransform = (bone.mParent) ?
+ computeBoneTransformRest(*bone.mParent) : PxTransform(PxVec3(0.0f), PxQuat(PxIdentity));
+
+ PxVec3 offset = bone.mLength * bone.mDirection;
+
+ PxTransform boneTransform(offset, PxQuat(PxIdentity));
+
+ return parentTransform.transform(boneTransform);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+Character::Character() :
+ mCurrentMotion(NULL),
+ mTargetMotion(NULL),
+ mBlendCounter(0),
+ mCharacterScale(1.0f),
+ mASFData(NULL),
+ mCharacterPose(PxVec3(0.0f), PxQuat(PxIdentity)),
+ mFrameTime(0.0f)
+{
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+int Character::addMotion(const char* amcFileName, PxU32 start, PxU32 end)
+{
+ Acclaim::AMCData AMCData;
+
+ if (Acclaim::readAMCData(amcFileName, *mASFData, AMCData) == false)
+ {
+ AMCData.release();
+ return -1;
+ }
+
+ if (AMCData.mNbFrames == 0)
+ {
+ AMCData.release();
+ return -1;
+ }
+
+ if (end >= AMCData.mNbFrames)
+ end = AMCData.mNbFrames - 1;
+
+ Motion* motion = SAMPLE_NEW(Motion)();
+
+ if (buildMotion(AMCData, *motion, start, end) == false)
+ {
+ SAMPLE_FREE(motion);
+ AMCData.release();
+ return -1;
+ }
+
+ mMotions.pushBack(motion);
+ mCurrentMotion = motion;
+
+ // set the frame counter to 0
+ mFrameTime = 0.0f;
+
+ AMCData.release();
+
+ return mMotions.size() - 1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+bool Character::buildMotion(Acclaim::AMCData &amcData, Motion &motion, PxU32 start, PxU32 end)
+{
+ using namespace Acclaim;
+
+ if (mASFData == NULL)
+ return false;
+
+ motion.mNbFrames = end - start + 1;
+ motion.mMotionData = SAMPLE_NEW(MotionData)[motion.mNbFrames];
+
+ // compute bounds of all the motion data on normalized frame
+ PxBounds3 bounds = PxBounds3::empty();
+ for (PxU32 i = start; i < end; i++)
+ {
+ Acclaim::FrameData &frameData = amcData.mFrameData[i];
+
+ PxTransform rootTransform(PxVec3(0.0f), EulerAngleToQuat(frameData.mRootOrientation));
+
+ for (PxU32 j = 0; j < mASFData->mNbBones; j++)
+ {
+ PxTransform t = computeBoneTransform(rootTransform, mASFData->mBones[j], frameData.mBoneFrameData);
+ bounds.include(t.p);
+ }
+ }
+
+ Acclaim::FrameData& firstFrame = amcData.mFrameData[0];
+ Acclaim::FrameData& lastFrame = amcData.mFrameData[amcData.mNbFrames-1];
+
+ // compute direction vector
+ motion.mDistance = mCharacterScale * (lastFrame.mRootPosition - firstFrame.mRootPosition).magnitude();
+
+ PxVec3 firstPosition = firstFrame.mRootPosition;
+ PX_UNUSED(firstPosition);
+ PxVec3 firstAngles = firstFrame.mRootOrientation;
+ PxQuat firstOrientation = EulerAngleToQuat(PxVec3(0, firstAngles.y, 0));
+
+ for (PxU32 i = 0; i < motion.mNbFrames; i++)
+ {
+ Acclaim::FrameData& frameData = amcData.mFrameData[i+start];
+ MotionData &motionData = motion.mMotionData[i];
+
+ // normalize y-rot by computing inverse quat from first frame
+ // this makes all the motion aligned in the same (+ z) direction.
+ PxQuat currentOrientation = EulerAngleToQuat(frameData.mRootOrientation);
+ PxQuat qdel = firstOrientation.getConjugate() * currentOrientation;
+ PxTransform rootTransform(PxVec3(0.0f), qdel);
+
+ for (PxU32 j = 0; j < mNbBones; j++)
+ {
+ PxTransform boneTransform = computeBoneTransform(rootTransform, mASFData->mBones[j], frameData.mBoneFrameData);
+ motionData.mBoneTransform[j] = boneTransform;
+ }
+
+ //PxReal y = mCharacterScale * (frameData.mRootPosition.y - firstPosition.y) - bounds.minimum.y;
+ motionData.mRootTransform = PxTransform(PxVec3(0.0f, -bounds.minimum.y, 0.0f), PxQuat(PxIdentity));
+ }
+
+ // now make the motion cyclic by linear interpolating root position and joint angles
+ const PxU32 windowSize = 10;
+ for (PxU32 i = 0; i <= windowSize; i++)
+ {
+ PxU32 j = motion.mNbFrames - 1 - windowSize + i;
+
+ PxReal t = PxReal(i) / PxReal(windowSize);
+
+ MotionData& motion_i = motion.mMotionData[0];
+ MotionData& motion_j = motion.mMotionData[j];
+
+ // lerp root translation
+ PxVec3 blendedRootPos = (1.0f - t) * motion_j.mRootTransform.p + t * motion_i.mRootTransform.p;
+ for (PxU32 k = 0; k < mNbBones; k++)
+ {
+ PxVec3 pj = motion_j.mRootTransform.p + motion_j.mBoneTransform[k].p;
+ PxVec3 pi = motion_i.mRootTransform.p + motion_i.mBoneTransform[k].p;
+
+ PxVec3 p = (1.0f - t) * pj + t * pi;
+ motion_j.mBoneTransform[k].p = p - blendedRootPos;
+ }
+ motion_j.mRootTransform.p = blendedRootPos;
+ }
+
+ return true;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// we apply pose blending if there is transition from one motion to another
+bool
+Character::computeFramePose()
+{
+ PxU32 frameNo = PxU32(mFrameTime);
+ if (frameNo >= mCurrentMotion->mNbFrames)
+ return false;
+
+ MotionData& motionData = mCurrentMotion->mMotionData[frameNo];
+
+ // compute blended motion when a target motion is set
+ if (mTargetMotion)
+ {
+ // first pose from target motion data
+ MotionData& targetData = mTargetMotion->mMotionData[0];
+ PxReal t = PxReal(mBlendCounter) / 10.0f;
+
+ for (PxU32 i = 0; i < mNbBones; i++)
+ {
+ mCurrentBoneTransform[i].p = t * motionData.mBoneTransform[i].p +
+ (1.0f - t) * targetData.mBoneTransform[i].p;
+ mCurrentBoneTransform[i].q = motionData.mBoneTransform[i].q;
+ }
+ mCurrentRootTransform.p = t * motionData.mRootTransform.p +
+ (1.0f - t) * targetData.mRootTransform.p;
+ mCurrentRootTransform.q = targetData.mRootTransform.q;
+
+ }
+ else
+ {
+ for (PxU32 i = 0; i < mNbBones; i++)
+ mCurrentBoneTransform[i] = motionData.mBoneTransform[i];
+ mCurrentRootTransform = motionData.mRootTransform;
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+bool Character::create(const char *asfFileName, PxReal scale)
+{
+ mCharacterScale = scale;
+
+ if (readSetup(asfFileName) == false)
+ return false;
+
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+bool Character::faceToward(const PxVec3& targetDir, PxReal angleLimitPerFrame)
+{
+ PxVec3 oldDir = mCharacterPose.q.rotate(PxVec3(0,0,1));
+ PxVec3 up(0,1,0);
+ PxVec3 newDir = PxVec3(targetDir.x, 0, targetDir.z).getNormalized();
+ PxVec3 right = -1.0f * oldDir.cross(up);
+
+ PxReal cos = newDir.dot(oldDir);
+ PxReal sin = newDir.dot(right);
+ PxReal angle = atan2(sin, cos);
+
+ PxReal limit = angleLimitPerFrame * (PxPi / 180.0f);
+ if (angle > limit) angle = limit;
+ else if (angle < -limit) angle = -limit;
+
+ PxQuat qdel(angle, up);
+
+ mCharacterPose.q = qdel * mCharacterPose.q;
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+bool
+Character::getFramePose(PxTransform &rootTransform, SampleArray<PxVec3> &positions, SampleArray<PxU32> &indexBuffers)
+{
+ if (mCurrentMotion == NULL)
+ return false;
+
+ PxU32 frameNo = PxU32(mFrameTime);
+ if (frameNo >= mCurrentMotion->mNbFrames)
+ return false;
+
+ positions.resize(mNbBones+1);
+
+ // copy precomputed bone position in local space
+ positions[0] = PxVec3(0.0f); // root position
+ for (PxU32 i = 0; i < mNbBones; i++)
+ positions[i+1] = mCurrentBoneTransform[i].p;
+
+ // copy capsule index data
+ indexBuffers.resize(mASFData->mNbBones * 2);
+ for (PxU32 i = 0; i < mASFData->mNbBones; i++)
+ {
+ Acclaim::Bone& bone = mASFData->mBones[i];
+ indexBuffers[i*2] = bone.mID;
+ indexBuffers[i*2+1] = (bone.mParent) ? bone.mParent->mID : 0;
+ }
+
+ // compute root transform
+ rootTransform = mCharacterPose.transform(mCurrentRootTransform);
+
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+bool Character::move(PxReal speed, bool jump, bool active )
+{
+ if (mCurrentMotion == NULL)
+ return false;
+
+ if (mBlendCounter > 0)
+ mBlendCounter--;
+
+ if (mTargetMotion && (mBlendCounter == 0))
+ {
+ mBlendCounter = 0;
+ mCurrentMotion = mTargetMotion;
+ mFrameTime = 0.0f;
+ mTargetMotion = NULL;
+ }
+
+ PxU32 nbFrames = mCurrentMotion->mNbFrames;
+ PxReal distance = mCurrentMotion->mDistance;
+
+ PxReal frameDelta = 0.0f;
+ const PxReal angleLimitPerFrame = 3.0f;
+
+ if (jump)
+ {
+ frameDelta = 1.0f;
+ }
+ else if (active && (mBlendCounter == 0))
+ {
+ // compute target orientation
+ PxVec3 dir = mTargetPosition - mCharacterPose.p;
+ dir.y = 0.0f;
+ PxReal curDistance = dir.magnitude();
+
+ if (curDistance > 0.01f)
+ faceToward(dir, angleLimitPerFrame);
+
+ frameDelta = speed * PxReal(nbFrames) * (curDistance / distance);
+ }
+ else
+ {
+ frameDelta = 0;
+ }
+
+ mCharacterPose.p = mTargetPosition;
+
+ mFrameTime += frameDelta;
+ PxU32 frameNo = PxU32(mFrameTime);
+
+ if (frameNo >= nbFrames)
+ {
+ if (jump)
+ mFrameTime = PxReal(nbFrames) - 1.0f;
+ else
+ mFrameTime = 0.0f;
+ }
+
+ // compute pose of all the bones at current frame (results are used by both getFramePose and Skin)
+ computeFramePose();
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+bool Character::readSetup(const char* asfFileName)
+{
+ if (mASFData) mASFData->release();
+
+ mASFData = new Acclaim::ASFData;
+
+ if (Acclaim::readASFData(asfFileName, *mASFData) == false)
+ {
+ delete mASFData;
+ mASFData = NULL;
+ return false;
+ }
+
+ mNbBones = mASFData->mNbBones;
+
+ // scale bone length
+ for (PxU32 i = 0; i < mASFData->mNbBones; i++)
+ {
+ Acclaim::Bone& bone = mASFData->mBones[i];
+
+ bone.mLength *= mCharacterScale;
+ }
+
+ return true;
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+void Character::release()
+{
+ for (PxU32 i = 0; i < mMotions.size(); i++)
+ {
+ if (mMotions[i])
+ mMotions[i]->release();
+ }
+ if (mASFData) mASFData->release();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+void Character::resetMotion(PxReal firstFrame)
+{
+ mFrameTime = firstFrame;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+bool Character::setGlobalPose(const PxTransform &transform)
+{
+ mCharacterPose.p = transform.p;
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+bool Character::setGoalPosition(const PxVec3 pos)
+{
+ mGoalPosition = pos;
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+bool Character::setMotion(PxU32 id, bool init)
+{
+ if (id >= mMotions.size())
+ return false;
+
+ if (init)
+ {
+ mCurrentMotion = mMotions[id];
+ mTargetMotion = NULL;
+
+ computeFramePose();
+ return true;
+ }
+
+ if (mCurrentMotion == NULL)
+ {
+ mCurrentMotion = mMotions[id];
+ return true;
+ }
+
+ if (mCurrentMotion == mMotions[id])
+ return true;
+
+ if (mTargetMotion == mMotions[id])
+ return true;
+
+ mTargetMotion = mMotions[id];
+ mBlendCounter = 10;
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+bool Character::setTargetPosition(const PxVec3 pos)
+{
+ mTargetPosition = pos;
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+bool Character::setForward(void)
+{
+ PxVec3 p = mCharacterPose.p;
+
+ PxVec3 dir = mGoalPosition - p;
+ dir.normalize();
+
+ dir = mCharacterPose.q.rotate(dir);
+
+ PxU32 nbFrames = mCurrentMotion->mNbFrames;
+ PxReal distance = mCurrentMotion->mDistance;
+
+ PxReal frameDelta = distance / PxReal(nbFrames);
+
+ mTargetPosition = p + frameDelta * dir;
+
+ return true;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+bool
+Skin::bindToCharacter(Character &character, SampleArray<PxVec4> &positions)
+{
+ // currently we just bind everything to the 'thorax' (between neck and clavicles).
+ // Modify this if you need to do more elaborate skin binding
+
+ mBindPos.resize(positions.size());
+ Acclaim::Bone* bone = getBoneFromName(*character.mASFData, "thorax");
+ if (bone == NULL)
+ return false;
+
+ PxTransform boneTransform = computeBoneTransformRest(*bone);
+ PxTransform boneTransformInv = boneTransform.getInverse();
+
+ mBoneID = bone->mID - 1;
+
+ for (PxU32 i = 0; i < positions.size(); i++)
+ {
+ mBindPos[i] = boneTransformInv.transform(
+ reinterpret_cast<const PxVec3&>(positions[i]));
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+bool
+Skin::computeNewPositions(Character &character, SampleArray<PxVec3> &particlePositions)
+{
+ if (character.mCurrentMotion == NULL)
+ return false;
+
+ PxTransform t = character.mCurrentBoneTransform[mBoneID];
+ particlePositions.resize(mBindPos.size());
+
+ for (PxU32 i = 0; i < mBindPos.size(); i++)
+ particlePositions[i] = t.transform(mBindPos[i]);
+
+ return true;
+}
+
+
diff --git a/PhysX_3.4/Samples/SampleBase/SampleCharacterHelpers.h b/PhysX_3.4/Samples/SampleBase/SampleCharacterHelpers.h
new file mode 100644
index 00000000..e2ccd087
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SampleCharacterHelpers.h
@@ -0,0 +1,152 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef SAMPLE_CHARACTER_HELPERS_H
+#define SAMPLE_CHARACTER_HELPERS_H
+
+#include "foundation/PxBounds3.h"
+#include "foundation/PxFlags.h"
+#include "foundation/PxTransform.h"
+
+#include "SampleAllocator.h"
+#include "SampleArray.h"
+#include "AcclaimLoader.h"
+
+
+class Character;
+
+///////////////////////////////////////////////////////////////////////////////
+class Skin
+{
+public:
+ bool bindToCharacter(Character& character, SampleArray<PxVec4> &positions);
+ bool computeNewPositions(Character& characeter, SampleArray<PxVec3> &positions);
+
+protected:
+ SampleArray<PxVec3> mBindPos;
+ int mBoneID;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Helper class to read and setup motion clip
+// This class provides enough functionality to create a moving stickman character and use it
+// for samples and tests.
+class Character
+{
+ ///////////////////////////////////////////////////////////////////////////////
+ struct MotionData : public SampleAllocateable
+ {
+ PxTransform mRootTransform;
+ PxTransform mBoneTransform[MAX_BONE_NUMBER];
+ };
+
+ struct Motion : public SampleAllocateable
+ {
+ MotionData* mMotionData;
+ PxU32 mNbFrames;
+ PxReal mDistance; // distance from first to last frame
+ public:
+ void release() { SAMPLE_FREE(mMotionData); delete this; }
+ };
+
+public:
+ Character();
+
+ virtual ~Character() { release(); }
+
+ /// read a motion clip from .amc file, returns a motion handle or -1 if amc file is invalid.
+ int addMotion(const char* amcFileName, PxU32 start = 0, PxU32 end = 10000);
+
+ /// create character from .asf setup
+ bool create(const char* asfFileName, PxReal scale = 1.0f);
+
+ /// orient this character in the given direction
+ bool faceToward(const PxVec3 &dir, PxReal angleLimitPerFrame = 360.0f);
+
+ /// create a pose info enough to create stickman
+ bool getFramePose(PxTransform &rootTransform, SampleArray<PxVec3> &positions, SampleArray<PxU32> &indexBuffers);
+
+ /// set next pose from the motion clip (speed = 1.0 will match original motion clip)
+ bool move(PxReal speed = 1.0f, bool jump = false, bool active = true);
+
+ /// reset motion to first frame
+ void resetMotion(PxReal firstFrame = 0.0f);
+
+ /// move forward
+ bool setForward();
+
+ /// set global pose
+ bool setGlobalPose(const PxTransform &transform);
+
+ /// set goal position
+ bool setGoalPosition(const PxVec3 pos);
+
+ /// select motion
+ bool setMotion(PxU32 motionhandle, bool init = false);
+
+ /// set target position
+ bool setTargetPosition(const PxVec3 pos);
+
+protected:
+
+ /// build internal motion data from raw amc data
+ bool buildMotion(Acclaim::AMCData&, Motion&, PxU32 start, PxU32 end);
+
+ /// compute per-frame pose cache
+ bool computeFramePose();
+
+ /// read a motion clip from .amc file
+ bool readSetup(const char* asfFileName);
+
+ /// release memory
+ void release();
+
+private:
+ SampleArray<Motion*> mMotions;
+ PxTransform mCurrentBoneTransform[MAX_BONE_NUMBER];
+ PxTransform mCurrentRootTransform;
+ Motion* mCurrentMotion;
+ Motion* mTargetMotion;
+ PxU32 mBlendCounter;
+ PxReal mCharacterScale;
+
+ Acclaim::ASFData* mASFData;
+ PxU32 mNbBones;
+
+ PxVec3 mGoalPosition;
+ PxVec3 mTargetPosition;
+ PxTransform mCharacterPose; // transformation of the character itself
+ PxReal mFrameTime;
+
+
+ friend class Skin;
+};
+
+#endif // SAMPLE_CHARACTER_HELPERS
diff --git a/PhysX_3.4/Samples/SampleBase/SampleConsole.cpp b/PhysX_3.4/Samples/SampleBase/SampleConsole.cpp
new file mode 100644
index 00000000..f27c5882
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SampleConsole.cpp
@@ -0,0 +1,609 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include <ctype.h>
+#include "SamplePreprocessor.h"
+#include "SampleConsole.h"
+#include "RendererMemoryMacros.h"
+#include "Renderer.h"
+#include "PsString.h"
+#include "PsUtilities.h"
+#include "SampleBaseInputEventIds.h"
+#include <SampleUserInputIds.h>
+
+#include "SampleUserInputDefines.h"
+
+using namespace SampleRenderer;
+using namespace SampleFramework;
+
+#define NB_LINES 14
+
+// EXIT: a basic command to hide the console
+// Usage: exit
+void Console::BasicCmdexit(Console* console, const char* text, void* user_data)
+{
+ console->setActive(false);
+}
+
+// CLS: a basic command to clear the console
+// Usage: cls
+void Console::BasicCmdcls(Console* console, const char* text, void* user_data)
+{
+ console->clear();
+}
+
+// PROMPT: a basic command to set the prompt
+// Usage: prompt [text]
+void Console::BasicCmdSetPrompt(Console* console, const char* text, void* user_data)
+{
+ console->setPrompt(text);
+}
+
+// CMDLIST: a basic command to display a list of all possible commands
+// Usage: cmdlist <= display all possible commands
+// cmdlist [command] <= check whether a command exists or not
+void Console::BasicCmdcmdlist(Console* console, const char* text, void* user_data)
+{
+ ConsoleCommand* pcmd;
+ if(!text)
+ {
+ for(int i=0;i<256;i++)
+ {
+ pcmd = console->mCmds[i];
+ while(pcmd)
+ {
+ console->out(pcmd->fullcmd);
+ pcmd = pcmd->next;
+ }
+ }
+ }
+ else
+ {
+ int i = text[0];
+ if( (i >= 'A') && (i<='Z') )
+ i -= 'A' - 'a';
+ pcmd = console->mCmds[i];
+ while(pcmd)
+ {
+ if(Ps::strncmp(pcmd->fullcmd, text, strlen(text)) == 0)
+ console->out(pcmd->fullcmd);
+ pcmd = pcmd->next;
+ }
+ }
+}
+
+// CMDHIST: a basic command to display command history
+// Usage: cmdhist
+void Console::BasicCmdcmdhist(Console* console, const char* text, void* user_data)
+{
+ long index = console->mNewcmd - console->mNumcmdhist;
+ for(long i=0;i<console->mNumcmdhist;i++)
+ {
+ if( index > CONSOLE_MAX_HIST )
+ index -= CONSOLE_MAX_HIST;
+ console->out(console->mCmdhist[index] );
+ index++;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Constructor.
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+Console::Console(SampleFramework::SamplePlatform* plt) :
+ mViewBottom (0),
+ mNewline (0),
+ mIsActive (false)
+{
+ strcpy(mLastChar, "-");
+ strcpy(mPrompt, ">");
+ resetCol();
+
+ mNbCmds = 0;
+ mNewcmd = 0;
+ mNumcmdhist = 0;
+ mCurcmd = 0;
+ mUserData = 0;
+
+ for(PxU32 i=0;i<CONSOLE_MAX_COMMAND_NB;i++)
+ mCmds[i] = NULL;
+
+ // Create console
+ addCmd("exit", BasicCmdexit);
+ addCmd("cmdlist", BasicCmdcmdlist);
+ addCmd("cls", BasicCmdcls);
+ addCmd("cmdhist", BasicCmdcmdhist);
+ addCmd("prompt", BasicCmdSetPrompt);
+
+ clear();
+ cmdClear();
+
+ out("PhysX Samples console");
+ out("");
+ out("Type cmdlist to display all possible commands.");
+ out("Use PageUp / PageDown to scroll the window.");
+ out("Use arrow keys to recall old commands.");
+ out("Use ESC to exit.");
+ out("");
+
+ advance();
+ strcpy(mBuffer[mNewline].mText, mPrompt);
+ strcat(mBuffer[mNewline].mText, mLastChar);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Destructor.
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+Console::~Console()
+{
+ destroy();
+}
+
+void Console::resetCol()
+{
+ mCol = (PxI32)strlen(mPrompt);
+}
+
+void Console::setPrompt(const char* text)
+{
+ if(!text)
+ return;
+ const PxU32 Length = (PxU32)strlen(text);
+ if(Length>255)
+ return;
+ strcpy(mPrompt, text);
+}
+
+// Advance the console one line
+void Console::advance()
+{
+ mNewline--;
+ if(mNewline<0)
+ mNewline += CONSOLE_MAX_ROW;
+
+ mBuffer[mNewline].mText[0] = '\0';
+ mViewBottom = mNewline;
+}
+
+// Clear the console text buffer
+void Console::clear()
+{
+ for(PxU32 i=0;i<CONSOLE_MAX_ROW;i++)
+ {
+ for(PxU32 j=0;j<CONSOLE_MAX_COL;j++)
+ mBuffer[i].mText[j] = '\0';
+
+ mBuffer[i].mColor = RendererColor(255,255,255);
+ }
+ mNewline = 0;
+ mViewBottom = 0;
+}
+
+// Clear the console text buffer
+void Console::cmdClear()
+{
+ for(PxU32 i=0;i<CONSOLE_MAX_HIST;i++)
+ for(PxU32 j=0;j<CONSOLE_MAX_COL;j++)
+ mCmdhist[i][j] = '\0';
+ mNewcmd = 0;
+ mNumcmdhist = 0;
+ mCurcmd = 0;
+}
+
+// Write a string to the console
+void Console::out(const char* string)
+{
+ advance();
+
+ if(string)
+ {
+ size_t Length = strlen(string);
+ if(Length>=CONSOLE_MAX_COL-1)
+ {
+ PX_ASSERT(0);
+ strcpy(mBuffer[mNewline].mText, "CONSOLE LINE TOO LONG!");
+ }
+ else
+ strcpy(mBuffer[mNewline].mText, string);
+ }
+}
+
+// Process an instruction
+// called after the user hits enter
+void Console::process()
+{
+ // Discard prompt
+ char cmd[1024];
+ long Index = (long)strlen(mPrompt);
+ strcpy(cmd, &mBuffer[mNewline].mText[Index]);
+
+ // Keep track of command in history buffer
+ strcpy(mCmdhist[mNewcmd], cmd);
+ mNewcmd = mNewcmd % CONSOLE_MAX_HIST;
+ mNewcmd++;
+ mCurcmd = 0;
+ mNumcmdhist++;
+ if(mNumcmdhist>CONSOLE_MAX_HIST) mNumcmdhist = CONSOLE_MAX_HIST;
+
+ mBuffer[mNewline].mColor = 0xffeeeeee;
+
+ // Extract param and execute command
+ char* cmdparam;
+ cmdparam = strchr(cmd, ' ');
+ if(cmdparam)
+ {
+ *cmdparam=0;
+ cmdparam++;
+ }
+
+ if(!execCmd(cmd, cmdparam))
+ out("Invalid command");
+}
+
+
+
+// up and down arrow
+// for command history
+void Console::cmdHistory()
+{
+ if( mCurcmd != -1 )
+ {
+ char buf[256];
+ long cmdnum;
+ strcpy(buf, mPrompt);
+ cmdnum = mNewcmd - mCurcmd;
+ if( cmdnum < 0 )
+ cmdnum += CONSOLE_MAX_HIST;
+ strcat(buf, mCmdhist[cmdnum]);
+ strcat(buf, mLastChar);
+ strcpy(mBuffer[mNewline].mText, buf);
+ mCol = (PxI32)strlen(buf)-1;
+ }
+}
+
+bool Console::findBestCommand(char* best_command, const char* text, PxU32& tabIndex) const
+{
+ if(!text || !best_command)
+ return false;
+
+ const size_t length = strlen(text);
+ if(length>1023)
+ return false;
+
+ char tmp[1024];
+ strcpy(tmp, text);
+ Ps::strlwr(tmp);
+
+ const unsigned char i = tmp[0];
+
+ ConsoleCommand* FirstCommand = NULL;
+ ConsoleCommand* BestCommand = NULL;
+ ConsoleCommand* pcmd = mCmds[i];
+ PxU32 currentIndex = 0;
+ while(pcmd && !BestCommand)
+ {
+ char tmp2[1024];
+ strcpy(tmp2, pcmd->fullcmd);
+ Ps::strlwr(tmp2);
+ if(Ps::strncmp(tmp, tmp2, length)== 0)
+ {
+ if(!currentIndex)
+ FirstCommand = pcmd;
+
+ if(currentIndex>=tabIndex)
+ BestCommand = pcmd;
+ currentIndex++;
+ }
+ pcmd = pcmd->next;
+ }
+
+ if(BestCommand)
+ {
+ tabIndex++;
+ strcpy(best_command, BestCommand->fullcmd);
+ return true;
+ }
+
+ tabIndex = 0;
+ if(currentIndex && FirstCommand)
+ {
+ tabIndex++;
+ strcpy(best_command, FirstCommand->fullcmd);
+ return true;
+ }
+ return false;
+}
+
+// Try to execute a command
+bool Console::execCmd(const char* cmd, const char* param)
+{
+ if(!cmd)
+ return false;
+
+ int HashIndex = cmd[0];
+ HashIndex = tolower(HashIndex);
+
+ ConsoleCommand* pcmd = mCmds[HashIndex];
+
+ while(pcmd)
+ {
+ if(Ps::stricmp(cmd, pcmd->fullcmd) == 0)
+ {
+ pcmd->function(this, param, mUserData);
+ return true;
+ }
+ else pcmd = pcmd->next;
+ }
+ return false;
+}
+
+// Destroy the console
+void Console::destroy()
+{
+ // clean up command list
+ for(PxU32 i=0;i<256;i++)
+ {
+ if(mCmds[i])
+ {
+ ConsoleCommand* pcmd = mCmds[i];
+ while(pcmd)
+ {
+ ConsoleCommand* next = pcmd->next;
+ DELETESINGLE(pcmd);
+ pcmd = next;
+ }
+ }
+ }
+}
+
+// Add a command
+void Console::addCmd(const char* full_cmd, void (*function)(Console*, const char *, void*))
+{
+ if(!full_cmd) return; // Command must be defined
+ if(!function) return; // Function must be defines
+ if(strlen(full_cmd)>=CONSOLE_MAX_COMMAND_LENGTH) return;
+ if(mNbCmds==CONSOLE_MAX_COMMAND_NB) return;
+ mNbCmds++;
+
+ int HashIndex = full_cmd[0];
+ HashIndex = tolower(HashIndex);
+
+ ConsoleCommand* pcmd = mCmds[HashIndex];
+ if(!pcmd)
+ {
+ mCmds[HashIndex] = SAMPLE_NEW(ConsoleCommand);
+ pcmd = mCmds[HashIndex];
+ }
+ else
+ {
+ while(pcmd->next)
+ {
+ pcmd = pcmd->next;
+ }
+ pcmd->next = SAMPLE_NEW(ConsoleCommand);
+ pcmd = pcmd->next;
+ }
+ strcpy(pcmd->fullcmd, full_cmd);
+ pcmd->function = function;
+ pcmd->next = NULL;
+}
+
+bool Console::render(Renderer* rnd)
+{
+ if(!rnd)
+ return false;
+ if(!mIsActive)
+ return true;
+
+ const PxU32 NbLines = NB_LINES;
+ const PxU32 FntHeight = 14;
+
+ PxU32 width, height;
+ rnd->getWindowSize(width, height);
+
+ const RendererColor backColor(3, 3, 39);
+
+ ScreenQuad sq;
+ sq.mX0 = 0.0f;
+ sq.mY0 = 20.0f/float(height);
+ sq.mX1 = 1.0f;
+ sq.mY1 = (20.0f + float((NbLines+2)*FntHeight))/float(height);
+ sq.mLeftUpColor = backColor;
+ sq.mRightUpColor = backColor;
+ sq.mLeftDownColor = backColor;
+ sq.mRightDownColor = backColor;
+ sq.mAlpha = 0.8f;
+
+ rnd->drawScreenQuad(sq);
+
+ PxU32 TextY = 24 + NbLines*FntHeight;
+
+ const PxReal scale = 0.4f;
+ const PxReal shadowOffset = 0.0f;
+
+ long temp = mViewBottom;
+ for(PxU32 i=0;i<NbLines;i++)
+ {
+ rnd->print(10, TextY, mBuffer[temp].mText, scale, shadowOffset, mBuffer[temp].mColor);
+
+ temp = (temp + 1) % CONSOLE_MAX_ROW;
+ TextY -= FntHeight; //size should come from renderer
+ }
+ return true;
+}
+
+
+// Process a single character
+static bool gTabMode = false;
+static PxU32 gTabIndex = 0;
+static char gTabCmd[1024];
+void Console::in(PxU32 wparam)
+{
+ if(!mIsActive)
+ return;
+
+ if ((wparam >= 'a' && wparam <= 'z') || (wparam >= 'A' && wparam <= 'Z') || (wparam >= '0' && wparam <= '9') || wparam == ' ' || wparam == '.' || wparam == '-' || wparam == '_')
+ {
+ gTabMode = false;
+ if(mCol >= CONSOLE_MAX_COL-2) // We need 2 extra characters for the cursor and the final 0
+ return;
+ mBuffer[mNewline].mText[mCol++] = (char)wparam; // Append new character
+ mBuffer[mNewline].mText[mCol] = mLastChar[0]; // Append cursor
+ mBuffer[mNewline].mText[mCol+1] = '\0';
+ }
+}
+
+void Console::collectInputEvents(std::vector<const SampleFramework::InputEvent*>& inputEvents)
+{
+ //digital keyboard events
+ DIGITAL_INPUT_EVENT_DEF(CONSOLE_OPEN, WKEY_TAB, XKEY_TAB, X1KEY_TAB, PS3KEY_TAB, PS4KEY_TAB, AKEY_UNKNOWN, OSXKEY_TAB, IKEY_UNKNOWN, LINUXKEY_TAB, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(CONSOLE_ESCAPE, WKEY_ESCAPE, XKEY_ESCAPE, X1KEY_ESCAPE, PS3KEY_ESCAPE, PS4KEY_ESCAPE, AKEY_UNKNOWN, OSXKEY_ESCAPE, IKEY_UNKNOWN, LINUXKEY_ESCAPE, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(CONSOLE_ENTER, WKEY_RETURN, XKEY_RETURN, X1KEY_RETURN, PS3KEY_RETURN, PS4KEY_RETURN, AKEY_UNKNOWN, OSXKEY_RETURN, IKEY_UNKNOWN, LINUXKEY_RETURN, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(CONSOLE_BACKSPACE, WKEY_BACKSPACE, XKEY_BACKSPACE, X1KEY_BACKSPACE, PS3KEY_BACKSPACE, PS4KEY_BACKSPACE, AKEY_UNKNOWN, OSXKEY_BACKSPACE, IKEY_UNKNOWN, LINUXKEY_BACKSPACE, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(CONSOLE_LIST_COMMAND_UP, WKEY_UP, XKEY_UP, X1KEY_UP, PS3KEY_UP, PS4KEY_UP, AKEY_UNKNOWN, OSXKEY_UP, IKEY_UNKNOWN, LINUXKEY_UP, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(CONSOLE_LIST_COMMAND_DOWN, WKEY_DOWN, XKEY_DOWN, X1KEY_DOWN, PS3KEY_DOWN, PS4KEY_DOWN, AKEY_UNKNOWN, OSXKEY_DOWN, IKEY_UNKNOWN, LINUXKEY_DOWN, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(CONSOLE_SCROLL_UP, WKEY_PRIOR, XKEY_PRIOR, X1KEY_PRIOR, PS3KEY_PRIOR, PS4KEY_PRIOR, AKEY_UNKNOWN, OSXKEY_PRIOR, IKEY_UNKNOWN, LINUXKEY_PRIOR, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(CONSOLE_SCROLL_DOWN, WKEY_NEXT, XKEY_NEXT, X1KEY_NEXT, PS3KEY_NEXT, PS4KEY_NEXT, AKEY_UNKNOWN, OSXKEY_NEXT, IKEY_UNKNOWN, LINUXKEY_NEXT, WIIUKEY_UNKNOWN);
+}
+
+//return true if we processed the key
+void Console::onDigitalInputEvent(const SampleFramework::InputEvent& ie, bool val)
+{
+ //if (val)
+ {
+
+ if (!mIsActive)
+ {
+
+ if (ie.m_Id == CONSOLE_OPEN)
+ {
+ mIsActive = true;
+ return;
+ }
+ }
+ else
+ {
+ if (!val)
+ {
+ switch (ie.m_Id)
+ {
+ case CONSOLE_OPEN:
+ if(!gTabMode)
+ {
+ gTabMode = true;
+
+ // Discard last character
+ mBuffer[mNewline].mText[mCol] = '\0';
+
+ // Discard prompt
+ long Index = (long)strlen(mPrompt);
+ strcpy(gTabCmd, &mBuffer[mNewline].mText[Index]);
+ }
+ char BestCmd[1024];
+ if(findBestCommand(BestCmd, gTabCmd, gTabIndex))
+ {
+ strcpy(mBuffer[mNewline].mText, mPrompt);
+ strcat(mBuffer[mNewline].mText, BestCmd);
+ strcat(mBuffer[mNewline].mText, mLastChar);
+ mCol = PxI32(strlen(mPrompt) + strlen(BestCmd));
+ }
+ else
+ {
+ gTabMode = false;
+ mBuffer[mNewline].mText[mCol] = mLastChar[0]; // Append cursor
+ mBuffer[mNewline].mText[mCol+1] = '\0';
+ }
+ break;
+ case CONSOLE_BACKSPACE:
+ gTabMode = false;
+ if(mCol>(long)strlen(mPrompt))
+ {
+ mBuffer[mNewline].mText[mCol] = '\0';
+ mBuffer[mNewline].mText[mCol-1] = mLastChar[0];
+ mCol--;
+ }
+ break;
+ case CONSOLE_ENTER:
+ gTabMode = false;
+ mBuffer[mNewline].mText[mCol] = '\0';
+ process();
+ advance();
+ strcpy(mBuffer[mNewline].mText, mPrompt);
+ strcat(mBuffer[mNewline].mText, mLastChar);
+ resetCol();
+ break;
+ case CONSOLE_ESCAPE:
+ mIsActive = false;
+ gTabMode = false;
+ break;
+ case CONSOLE_LIST_COMMAND_UP:
+ mCurcmd++;
+ if( mCurcmd > mNumcmdhist )
+ mCurcmd = mNumcmdhist;
+ cmdHistory();
+ break;
+ case CONSOLE_LIST_COMMAND_DOWN:
+ mCurcmd--;
+ if( mCurcmd <= 0 )
+ mCurcmd = 0;
+ cmdHistory();
+ break;
+ case CONSOLE_SCROLL_UP:
+ mViewBottom++;
+ if(mViewBottom >= CONSOLE_MAX_ROW) mViewBottom -= CONSOLE_MAX_ROW;
+ if(mViewBottom == mNewline - NB_LINES) mViewBottom--;
+ break;
+ case CONSOLE_SCROLL_DOWN:
+ mViewBottom--;
+ if(mViewBottom < 0) mViewBottom += CONSOLE_MAX_ROW;
+ if(mViewBottom == mNewline-1) mViewBottom = mNewline;
+ break;
+ }
+ }
+ }
+ }
+}
+
+void Console::onKeyDown(SampleFramework::SampleUserInput::KeyCode keyCode, PxU32 param)
+{
+ //sschirm doesn't compile on snc
+ //const int keyparam = (int)param;
+
+
+ if (mIsActive)
+ {
+ if(param)
+ in(param);
+ }
+
+
+}
diff --git a/PhysX_3.4/Samples/SampleBase/SampleConsole.h b/PhysX_3.4/Samples/SampleBase/SampleConsole.h
new file mode 100644
index 00000000..3938060d
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SampleConsole.h
@@ -0,0 +1,134 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef SAMPLE_CONSOLE_H
+#define SAMPLE_CONSOLE_H
+
+#include "common/PxPhysXCommonConfig.h"
+#include "RendererColor.h"
+#include "RendererWindow.h"
+#include "SampleAllocator.h"
+#include <SampleUserInput.h>
+#include <SamplePlatform.h>
+
+ #define CONSOLE_KEY 222
+ #define CONSOLE_MAX_COL 80
+ #define CONSOLE_MAX_ROW 200
+ #define CONSOLE_MAX_HIST 30
+
+
+namespace SampleRenderer
+{
+ class Renderer;
+}
+
+ struct ConsoleRow : public SampleAllocateable
+ {
+ SampleRenderer::RendererColor mColor;
+ char mText[CONSOLE_MAX_COL];
+ };
+
+ #define CONSOLE_MAX_COMMAND_LENGTH 48
+ #define CONSOLE_MAX_COMMAND_NB 256
+ class Console;
+ struct ConsoleCommand : public SampleAllocateable
+ {
+ char fullcmd[CONSOLE_MAX_COMMAND_LENGTH];
+ void (*function)(Console* console, const char* text, void* user_data);
+ struct ConsoleCommand* next;
+ };
+
+ enum ConsoleInputKey
+ {
+ CONSOLE_KEY_PRIOR,
+ CONSOLE_KEY_NEXT,
+
+ CONSOLE_KEY_UP,
+ CONSOLE_KEY_DOWN,
+ };
+
+ class Console : public SampleAllocateable
+ {
+ public:
+ Console(SampleFramework::SamplePlatform* plt);
+ ~Console();
+
+ bool render(SampleRenderer::Renderer* rnd);
+ void onKeyDown(SampleFramework::SampleUserInput::KeyCode keyCode, PxU32 param);
+ void onDigitalInputEvent(const SampleFramework::InputEvent& ie, bool val);
+ void collectInputEvents(std::vector<const SampleFramework::InputEvent*>& inputEvents);
+ void out(const char* string);
+ void addCmd(const char* full_cmd, void (*function)(Console*, const char*, void*));
+
+ void clear();
+ void setPrompt(const char* text);
+
+ bool isActive() const { return mIsActive; }
+ void setActive(bool b) { mIsActive = b; }
+ void setUserData(void* userData) { mUserData = userData; }
+
+
+ static void BasicCmdexit(Console* console, const char* text, void* user_data);
+ static void BasicCmdcls(Console* console, const char* text, void* user_data);
+ static void BasicCmdSetPrompt(Console* console, const char* text, void* user_data);
+ static void BasicCmdcmdlist(Console* console, const char* text, void* user_data);
+ static void BasicCmdcmdhist(Console* console, const char* text, void* user_data);
+
+
+ private:
+ char mCmdhist[CONSOLE_MAX_HIST][CONSOLE_MAX_COL];
+ long mNewcmd;
+ long mNumcmdhist;
+ long mCurcmd;
+ long mNbCmds;
+ ConsoleCommand* mCmds[CONSOLE_MAX_COMMAND_NB];
+ void* mUserData;
+
+ ConsoleRow mBuffer[CONSOLE_MAX_ROW];
+ char mPrompt[256];
+ char mLastChar[2];
+ PxI32 mViewBottom;
+ PxI32 mNewline;
+ PxI32 mCol;
+ bool mIsActive;
+
+ // Internal methods
+ void cmdClear();
+ void advance();
+ void resetCol();
+ void process();
+ void in(PxU32 wparam);
+ void cmdHistory();
+ bool execCmd(const char* cmd, const char* param);
+ void destroy();
+ bool findBestCommand(char* best_command, const char* text, PxU32& tabIndex) const;
+
+ };
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/SampleInputMappingAsset.cpp b/PhysX_3.4/Samples/SampleBase/SampleInputMappingAsset.cpp
new file mode 100644
index 00000000..f5bf7d8c
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SampleInputMappingAsset.cpp
@@ -0,0 +1,264 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "PhysXSample.h"
+#include "SampleInputMappingAsset.h"
+#include "ODBlock.h"
+#include "PxTkFile.h"
+
+using namespace SampleFramework;
+
+static const int MAPPING_VERSION = 4;
+
+SampleInputMappingAsset::SampleInputMappingAsset(SampleFramework::File* file, const char *path, bool empty,PxU32 userInputCS, PxU32 inputEventCS)
+: mSettingsBlock(NULL), mMapping(NULL) , mFile(file) , mPath(path), mUserInputCS(userInputCS), mInputEventCS(inputEventCS)
+{
+ mSampleInputData.reserve(128);
+
+ PX_ASSERT(file);
+
+ mIsOk = true;
+ if(empty)
+ {
+ createNewFile(false);
+ }
+ else
+ {
+ mMapping = new ODBlock();
+ if (!mMapping->loadScript(file))
+ {
+ shdfnd::printFormatted("ODS parse error: %s in file: %s\n", mMapping->lastError, path);
+ mIsOk = false;
+ createNewFile(true);
+ }
+ else
+ {
+ mSettingsBlock = mMapping->getBlock("InputMapping");
+ if (!mSettingsBlock)
+ {
+ shdfnd::printFormatted("No \"InputEventSettings\" block found!\n");
+ mIsOk = false;
+ createNewFile(true);
+ }
+ else
+ {
+ int versionNumber = 0;
+ if(!mSettingsBlock->getBlockInt("Version",&versionNumber))
+ {
+ mIsOk = false;
+ createNewFile(true);
+ }
+ else
+ {
+ if(versionNumber != MAPPING_VERSION)
+ {
+ mIsOk = false;
+ createNewFile(true);
+ }
+ else
+ {
+ if(!checksumCheck())
+ {
+ mIsOk = false;
+ createNewFile(true);
+ }
+ else
+ {
+ loadData(mSettingsBlock);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+bool SampleInputMappingAsset::checksumCheck()
+{
+ PxU32 userInputCS = 0;
+ if(!mSettingsBlock->getBlockU32("UserInputCS",&userInputCS))
+ {
+ return false;
+ }
+
+ PxU32 inputEventCS = 0;
+ if(!mSettingsBlock->getBlockU32("InputEventCS",&inputEventCS))
+ {
+ return false;
+ }
+
+ if(mUserInputCS != userInputCS)
+ {
+ return false;
+ }
+
+ if(mInputEventCS != inputEventCS)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+SampleInputMappingAsset::~SampleInputMappingAsset()
+{
+ if(mFile)
+ {
+ fclose(mFile);
+ }
+
+ if(mMapping)
+ delete mMapping;
+}
+
+void SampleInputMappingAsset::loadData(ODBlock* odsSettings)
+{
+ odsSettings->reset();
+ while (odsSettings->moreSubBlocks())
+ {
+ ODBlock* subBlock = odsSettings->nextSubBlock();
+ subBlock->reset();
+
+ SampleInputData inputData;
+ if (!strcmp(subBlock->ident(), "Map"))
+ {
+ if (subBlock->moreTerminals())
+ {
+ const char* p = subBlock->nextTerminal();
+ strcpy(inputData.m_UserInputName, p);
+ }
+ if (subBlock->moreTerminals())
+ {
+ const char* p = subBlock->nextTerminal();
+ strcpy(inputData.m_InputEventName, p);
+ }
+
+ mSampleInputData.push_back(inputData);
+ }
+ }
+}
+
+void SampleInputMappingAsset::addMapping(const char* uiName, const char* ieName)
+{
+ if(!mIsOk)
+ return;
+
+ ODBlock & mapping = *new ODBlock();
+ mapping.ident("Map");
+ mSettingsBlock->addStatement(mapping);
+
+ ODBlock & userInputBlock = *new ODBlock();
+ mapping.addStatement(userInputBlock);
+ userInputBlock.ident(uiName);
+
+ ODBlock & inputEventBlock = *new ODBlock();
+ mapping.addStatement(inputEventBlock);
+ inputEventBlock.ident(ieName);
+}
+
+bool SampleInputMappingAsset::createNewFile(bool rewriteFile)
+{
+ if(rewriteFile)
+ {
+ if(mFile)
+ {
+ fclose(mFile);
+ mFile = NULL;
+ }
+ PxToolkit::fopen_s(&mFile,mPath , "w");
+
+ if(mFile)
+ mIsOk = true;
+ }
+
+ if(mMapping)
+ {
+ delete mMapping;
+ mMapping = NULL;
+ }
+
+ mMapping = new ODBlock();
+ mMapping->ident("InputMapping");
+ mSettingsBlock = mMapping;
+
+ ODBlock & version = *new ODBlock();
+ version.ident("Version");
+ mSettingsBlock->addStatement(version);
+
+ ODBlock & nb = *new ODBlock();
+ version.addStatement(nb);
+ char temps[64];
+ sprintf(temps,"%d",MAPPING_VERSION);
+ nb.ident(temps);
+
+ ODBlock & userInputCSB = *new ODBlock();
+ userInputCSB.ident("UserInputCS");
+ mSettingsBlock->addStatement(userInputCSB);
+
+ ODBlock &nb2 = *new ODBlock();
+ userInputCSB.addStatement(nb2);
+ sprintf(temps,"%d",mUserInputCS);
+ nb2.ident(temps);
+
+ ODBlock & inputEventCSB = *new ODBlock();
+ inputEventCSB.ident("InputEventCS");
+ mSettingsBlock->addStatement(inputEventCSB);
+
+ ODBlock &nb3 = *new ODBlock();
+ inputEventCSB.addStatement(nb3);
+ sprintf(temps,"%d",mInputEventCS);
+ nb3.ident(temps);
+
+ return true;
+}
+
+void SampleInputMappingAsset::saveMappings()
+{
+ if(!mIsOk)
+ return;
+
+ if(mFile)
+ {
+ fclose(mFile);
+ mFile = NULL;
+ }
+ PxToolkit::fopen_s(&mFile,mPath , "w");
+ if(mFile)
+ {
+ mMapping->saveScript(mFile,false);
+ fclose(mFile);
+ }
+
+ mFile = NULL;
+}
+
+bool SampleInputMappingAsset::isOk(void) const
+{
+ return mIsOk;
+}
diff --git a/PhysX_3.4/Samples/SampleBase/SampleInputMappingAsset.h b/PhysX_3.4/Samples/SampleBase/SampleInputMappingAsset.h
new file mode 100644
index 00000000..05cbd0a4
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SampleInputMappingAsset.h
@@ -0,0 +1,66 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef SAMPLE_INPUT_MAPPING_ASSET_H
+#define SAMPLE_INPUT_MAPPING_ASSET_H
+
+#include <SampleUserInput.h>
+#include <ODBlock.h>
+#include "SampleAllocator.h"
+
+class SampleInputMappingAsset : public SampleAllocateable
+{
+public:
+ SampleInputMappingAsset(SampleFramework::File* file, const char *path, bool empty,PxU32 userInputCS, PxU32 inputEventCS);
+ virtual ~SampleInputMappingAsset(void);
+
+ virtual bool isOk(void) const;
+
+ const SampleFramework::T_SampleInputData& getSampleInputData() const { return mSampleInputData; }
+
+ void addMapping(const char* uiName, const char* ieName);
+ void saveMappings();
+
+private:
+ void loadData(ODBlock* odsSettings);
+ bool createNewFile(bool rewriteFile);
+ bool checksumCheck();
+
+private:
+ SampleFramework::T_SampleInputData mSampleInputData;
+ ODBlock* mSettingsBlock;
+ ODBlock* mMapping;
+ SampleFramework::File* mFile;
+ const char* mPath;
+ bool mIsOk;
+ PxU32 mUserInputCS;
+ PxU32 mInputEventCS;
+};
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/SampleMain.cpp b/PhysX_3.4/Samples/SampleBase/SampleMain.cpp
new file mode 100644
index 00000000..9e7a2588
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SampleMain.cpp
@@ -0,0 +1,311 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "foundation/PxAssert.h"
+#include "RendererConfig.h"
+#include "SampleCommandLine.h"
+#include "RendererMemoryMacros.h"
+#include "SampleAllocator.h"
+#include "PhysXSampleApplication.h"
+#include "PxTkFile.h"
+
+using namespace SampleFramework;
+
+#if defined(RENDERER_ANDROID)
+#include "SamplePlatform.h"
+
+struct android_app;
+static android_app* gState;
+#endif
+
+#if defined(RENDERER_IOS) || defined(RENDERER_PS3) || defined(RENDERER_MACOSX)
+// IOS does not easily support instrumenting the event
+// loop like other OSs. Therefore for IOS the (input) event loop
+// and the game loop stay for it in the same thread.
+//
+// PS3 reports a warning when a thread is starved. This happens
+// when gApp tries to start but then needs to wait until the main loop
+// yields. One consequence of this is that the inputs are polled from
+// the main loop before they have been initialized.
+//
+// MACOSX non-deterministically crashed with one thread ran
+// SampleRenderer::createGLView (renderer initialization)
+// and the other SampleRenderer::emitEvents (processing ESC key event).
+// Apparently connecting the glView to the window interfers with
+// OSX event processing for some reason.
+#define SEPARATE_EVENT_LOOP 0
+#else
+#define SEPARATE_EVENT_LOOP 1
+#endif
+
+static PhysXSampleApplication* gApp = NULL;
+static SampleSetup gSettings;
+static SampleCommandLine* gSampleCommandLine = NULL;
+
+void mainInitialize()
+{
+ PX_ASSERT(gSampleCommandLine);
+ const SampleCommandLine& cmdline = *gSampleCommandLine;
+ initSampleAllocator();
+ gApp = SAMPLE_NEW(PhysXSampleApplication)(cmdline);
+
+ gApp->customizeSample(gSettings);
+#if defined(RENDERER_ANDROID)
+ /* We need to register event handling callbacks and process events, while window is not yet shown. */
+ if(!SamplePlatform::platform()->preOpenWindow(gState))
+ {
+ LOG_INFO("SampleMain", "CMD/Input handlers registration failed. Exiting.");
+ return;
+ }
+ while(!SamplePlatform::platform()->isOpen())
+ {
+ SamplePlatform::platform()->update();
+ }
+#endif
+
+ if (gApp->isOpen())
+ gApp->close();
+
+ gApp->open(gSettings.mWidth, gSettings.mHeight, gSettings.mName, gSettings.mFullscreen);
+#if SEPARATE_EVENT_LOOP
+ gApp->start(Ps::Thread::getDefaultStackSize());
+#else
+ if(gApp->isOpen()) gApp->onOpen();
+#endif
+}
+
+void mainTerminate()
+{
+ DELETESINGLE(gApp);
+ DELETESINGLE(gSampleCommandLine);
+ releaseSampleAllocator();
+}
+
+bool mainContinue()
+{
+ if (gApp->isOpen() && !gApp->isCloseRequested())
+ {
+ if(gApp->getInputMutex().trylock())
+ {
+ gApp->handleMouseVisualization();
+ gApp->doInput();
+ gApp->update();
+#if !SEPARATE_EVENT_LOOP
+ gApp->updateEngine();
+#endif
+ gApp->getInputMutex().unlock();
+ }
+ Ps::Thread::yield();
+#if defined(RENDERER_ANDROID)
+ if (SamplePlatform::platform()->isOpen())
+ return true;
+#else
+ return true;
+#endif
+ }
+
+#if SEPARATE_EVENT_LOOP
+ gApp->signalQuit();
+ gApp->waitForQuit();
+#else
+ if (gApp->isOpen() || gApp->isCloseRequested())
+ gApp->close();
+#endif
+
+ return false;
+}
+
+void mainLoop()
+{
+ while(mainContinue());
+}
+
+
+#if defined(RENDERER_ANDROID)
+
+ extern "C" void android_main(struct android_app* state)
+ {
+ gState = state;
+ const char* argv[] = { "dummy", 0 };
+ gSampleCommandLine = new SampleCommandLine(1, argv);
+ mainInitialize();
+
+ const char* argFilePath = getSampleMediaFilename("user/androidCmdLine.cfg");
+ File* argFp = NULL;
+ physx::shdfnd::fopen_s(&argFp, argFilePath, "r");
+ if (argFp)
+ {
+ fclose(argFp);
+ SampleCommandLine pvdCmdline(1, argv, argFilePath);
+ gApp->setPvdParams(pvdCmdline);
+ }
+
+ mainLoop();
+ mainTerminate();
+ exit(0);
+ /* Will not return return code, because NDK's native_app_glue declares this function to return nothing. Too bad. */
+ }
+
+#elif defined(RENDERER_IOS)
+
+ #include "ios/IosSamplePlatform.h"
+
+ int main(int argc, const char *const* argv)
+ {
+ gSampleCommandLine = new SampleCommandLine((unsigned int)argc, argv);
+ SampleFramework::createApplication(mainInitialize, mainContinue, mainTerminate);
+ return 0;
+ }
+
+#elif PX_XBOXONE
+
+namespace SampleFramework
+{
+ void createApplication(void (*initializeFunc)(), bool (*updateFunc)(), void (*terminateFunc)(), SampleCommandLine*& commandLine);
+}
+
+int main(Platform::Array<Platform::String^>^ args)
+{
+ SampleFramework::createApplication(mainInitialize, mainContinue, mainTerminate, gSampleCommandLine);
+ return 0;
+}
+#elif defined(RENDERER_WINDOWS)
+
+ int main()
+ {
+ gSampleCommandLine = new SampleCommandLine(GetCommandLineA());
+ mainInitialize();
+ mainLoop();
+ mainTerminate();
+ return 0;
+ }
+
+#elif defined(RENDERER_XBOX360)
+
+ int main()
+ {
+ const char *argv[32];
+ int argc = 0;
+ volatile LPSTR commandLineString;
+ commandLineString = GetCommandLine(); // xbox call to get command line argument string
+
+ //skip directly modify the process's share command line string ,in case that it be used in elsewhere
+ size_t len = strlen(commandLineString);
+ LPSTR cmdString = (LPSTR)alloca(len+1);
+ memcpy(cmdString, commandLineString,len);
+ cmdString[len] = '\0';
+
+ /* first pull out the application name argv[0] */
+ argv[argc] = strtok(cmdString, " ");
+
+ /* pull out the other args */
+ while (argv[argc] != NULL)
+ {
+ argc++;
+ argv[argc] = strtok(NULL, " ");
+ }
+ gSampleCommandLine = new SampleCommandLine(argc, argv);
+ mainInitialize();
+ mainLoop();
+ mainTerminate();
+ return 0;
+ }
+
+#elif defined(RENDERER_PS3) || defined(RENDERER_PS4)
+
+ int main(int argc, char** argv)
+ {
+ gSampleCommandLine = new SampleCommandLine((unsigned int)argc, argv);
+ mainInitialize();
+ mainLoop();
+ mainTerminate();
+ return 0;
+ }
+
+#elif defined(RENDERER_LINUX)
+
+ int main(int argc, const char *const* argv)
+ {
+ char* commandString = NULL;
+ PxU32 commandLen = 0;
+ const char* specialCommand = "--noXterm";
+ const char* xtermCommand = "xterm -e ";
+ bool foundSpecial = false;
+
+ for(PxU32 i = 0; i < (PxU32)argc; i++)
+ {
+ foundSpecial = foundSpecial || (::strncmp(argv[i], specialCommand, ::strlen(specialCommand)) == 0);
+ commandLen += ::strlen(argv[i]);
+ }
+
+ // extend command line if not chosen differently
+ // and start again with terminal as parent
+ if(!foundSpecial)
+ {
+ // increase size by new commands, spaces between commands and string terminator
+ commandLen += ::strlen(xtermCommand) + ::strlen(specialCommand) + argc + 3;
+ commandString = (char*)::malloc(commandLen * sizeof(char));
+
+ ::strcpy(commandString, xtermCommand);
+ for(PxU32 i = 0; i < (PxU32)argc; i++)
+ {
+ ::strcat(commandString, argv[i]);
+ ::strcat(commandString, " ");
+ }
+ ::strcat(commandString, specialCommand);
+
+ int ret = ::system(commandString);
+ ::free(commandString);
+
+ if(ret < 0)
+ shdfnd::printFormatted("Failed to run %s! If xterm is missing, try running with this parameter: %s\n", argv[0], specialCommand);
+ }
+ else
+ {
+ gSampleCommandLine = new SampleCommandLine((unsigned int)(argc), argv);
+ mainInitialize();
+ mainLoop();
+ mainTerminate();
+ }
+
+ return 0;
+ }
+
+#else
+
+ int main(int argc, const char *const* argv)
+ {
+ gSampleCommandLine = new SampleCommandLine((unsigned int)argc, argv);
+ mainInitialize();
+ mainLoop();
+ mainTerminate();
+ return 0;
+ }
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/SampleMouseFilter.cpp b/PhysX_3.4/Samples/SampleBase/SampleMouseFilter.cpp
new file mode 100644
index 00000000..ec21412f
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SampleMouseFilter.cpp
@@ -0,0 +1,107 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+// Mouse filter from ICE, refactored a bit
+
+#include "SampleMouseFilter.h"
+
+MouseFilter::MouseFilter() :
+ mWeightModifier (0.0f),
+ mHistoryBufferLength (0),
+ mHistoryBufferX (NULL),
+ mHistoryBufferY (NULL)
+{
+}
+
+MouseFilter::MouseFilter(PxU32 length, PxReal weightModifier)
+{
+ mWeightModifier = weightModifier;
+ mHistoryBufferLength = 0;
+ mHistoryBufferX = NULL;
+ mHistoryBufferY = NULL;
+ SetHistoryBufferLength(length);
+}
+
+MouseFilter::~MouseFilter()
+{
+ SAMPLE_FREE(mHistoryBufferX);
+ SAMPLE_FREE(mHistoryBufferY);
+}
+
+bool MouseFilter::SetHistoryBufferLength(PxU32 length)
+{
+ SAMPLE_FREE(mHistoryBufferX);
+ SAMPLE_FREE(mHistoryBufferY);
+
+ mHistoryBufferLength = length;
+ if(length)
+ {
+ mHistoryBufferX = (float*)SAMPLE_ALLOC(sizeof(float)*length);
+ memset(mHistoryBufferX, 0, length*sizeof(float));
+ mHistoryBufferY = (float*)SAMPLE_ALLOC(sizeof(float)*length);
+ memset(mHistoryBufferY, 0, length*sizeof(float));
+ }
+ return true;
+}
+
+void MouseFilter::Apply(PxReal& deltaMouseX, PxReal& deltaMouseY)
+{
+ // Checkings
+ if(!mHistoryBufferX || !mHistoryBufferY) return;
+
+ // Shift the buffer around. If you want performance from this, be sure
+ // to use a circular buffer than these slow memmove()s.
+ memmove(mHistoryBufferX+1, mHistoryBufferX, (mHistoryBufferLength-1)*sizeof(PxReal));
+ memmove(mHistoryBufferY+1, mHistoryBufferY, (mHistoryBufferLength-1)*sizeof(PxReal));
+
+ // Put the current values at the front of the history buffer
+ *mHistoryBufferX = deltaMouseX;
+ *mHistoryBufferY = deltaMouseY;
+
+ // Filter the mouse
+ PxReal CurAverageX = 0.0f;
+ PxReal CurAverageY = 0.0f;
+ PxReal AverageTot = 0.0f;
+ PxReal CurrentWeight = 1.0f;
+ for(PxU32 i=0;i<mHistoryBufferLength;i++)
+ {
+ CurAverageX += mHistoryBufferX[i] * CurrentWeight;
+ CurAverageY += mHistoryBufferY[i] * CurrentWeight;
+
+ // Note! Our total is also weighted
+ AverageTot += 1.0f * CurrentWeight;
+
+ // The weight for the next entry in the history buffer
+ CurrentWeight *= mWeightModifier;
+ }
+
+ // Calculate the final weighted value
+ deltaMouseX = CurAverageX / AverageTot;
+ deltaMouseY = CurAverageY / AverageTot;
+}
diff --git a/PhysX_3.4/Samples/SampleBase/SampleMouseFilter.h b/PhysX_3.4/Samples/SampleBase/SampleMouseFilter.h
new file mode 100644
index 00000000..a37b9685
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SampleMouseFilter.h
@@ -0,0 +1,56 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef SAMPLE_MOUSE_FILTER_H
+#define SAMPLE_MOUSE_FILTER_H
+
+#include "SampleAllocator.h"
+
+ class MouseFilter : public SampleAllocateable
+ {
+ public:
+ MouseFilter();
+ MouseFilter(PxU32 length, PxReal weightModifier);
+ ~MouseFilter();
+
+ PX_INLINE PxReal GetWeightModifier() const { return mWeightModifier; }
+ PX_INLINE void SetWeightModifier(PxReal modifier) { mWeightModifier = modifier; }
+
+ PX_INLINE PxU32 GetHistoryBufferLength() const { return mHistoryBufferLength; }
+ bool SetHistoryBufferLength(PxU32 length);
+
+ void Apply(PxReal& deltaMouseX, PxReal& deltaMouseY);
+ private:
+ PxReal mWeightModifier;
+ PxU32 mHistoryBufferLength;
+ PxReal* mHistoryBufferX;
+ PxReal* mHistoryBufferY;
+ };
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/SamplePreprocessor.h b/PhysX_3.4/Samples/SampleBase/SamplePreprocessor.h
new file mode 100644
index 00000000..4a76fb7f
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SamplePreprocessor.h
@@ -0,0 +1,34 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef SAMPLE_PREPROCESSOR_H
+#define SAMPLE_PREPROCESSOR_H
+
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/SampleRandomPrecomputed.cpp b/PhysX_3.4/Samples/SampleBase/SampleRandomPrecomputed.cpp
new file mode 100644
index 00000000..33eeb44b
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SampleRandomPrecomputed.cpp
@@ -0,0 +1,92 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SampleRandomPrecomputed.h"
+#include "PhysXSample.h"
+#include "SampleAllocator.h"
+#include "PxTkStream.h"
+
+using namespace PxToolkit;
+
+#define WRITE_SEQUENCE 0
+
+PX_FORCE_INLINE PxF32 flip(const PxF32* v)
+{
+ const PxU8* b = (const PxU8*)v;
+ PxF32 f;
+ PxU8* bf = (PxU8*)&f;
+ bf[0] = b[3];
+ bf[1] = b[2];
+ bf[2] = b[1];
+ bf[3] = b[0];
+ return f;
+}
+
+SampleRandomPrecomputed::SampleRandomPrecomputed(PhysXSample& app)
+: mPrecomputedRandomSequence(NULL),
+ mPrecomputedRandomSequenceCount(0)
+{
+ mPrecomputedRandomSequence = (PxF32*)SAMPLE_ALLOC(sizeof(PxF32)*(PRECOMPUTED_RANDOM_SEQUENCE_SIZE+1));
+
+#if WRITE_SEQUENCE
+ char buffer[256];
+ const char* filename = getSampleOutputDirManager().getFilePath("SampleBaseRandomSequence", buffer, false);
+ const PxF32 denom = (1.0f / float(RAND_MAX));
+ for(PxU32 i=0;i<PRECOMPUTED_RANDOM_SEQUENCE_SIZE;i++)
+ {
+ mPrecomputedRandomSequence[i] = float(rand()) * denom;
+ }
+ mPrecomputedRandomSequence[PRECOMPUTED_RANDOM_SEQUENCE_SIZE]=1.0f;
+ PxDefaultFileOutputStream stream(filename);
+ stream.write(mPrecomputedRandomSequence,sizeof(PxF32)*(PRECOMPUTED_RANDOM_SEQUENCE_SIZE+1));
+
+#else
+ const char* filename = getSampleMediaFilename("SampleBaseRandomSequence");
+ PxDefaultFileInputData stream(filename);
+ if(!stream.isValid())
+ app.fatalError("SampleBaseRandomSequence file not found");
+ stream.read(mPrecomputedRandomSequence,sizeof(PxF32)*(PRECOMPUTED_RANDOM_SEQUENCE_SIZE+1));
+
+ const bool mismatch = (1.0f != mPrecomputedRandomSequence[PRECOMPUTED_RANDOM_SEQUENCE_SIZE]);
+ if(mismatch)
+ {
+ for(PxU32 i=0;i<PRECOMPUTED_RANDOM_SEQUENCE_SIZE;i++)
+ {
+ mPrecomputedRandomSequence[i]=flip(&mPrecomputedRandomSequence[i]);
+ }
+ }
+
+#endif
+}
+
+SampleRandomPrecomputed::~SampleRandomPrecomputed()
+{
+ SAMPLE_FREE(mPrecomputedRandomSequence);
+ mPrecomputedRandomSequenceCount=0;
+}
diff --git a/PhysX_3.4/Samples/SampleBase/SampleRandomPrecomputed.h b/PhysX_3.4/Samples/SampleBase/SampleRandomPrecomputed.h
new file mode 100644
index 00000000..2acac578
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SampleRandomPrecomputed.h
@@ -0,0 +1,64 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef SAMPLE_RANDOM_PRECOMPUTED_H
+#define SAMPLE_RANDOM_PRECOMPUTED_H
+
+#include "common/PxPhysXCommonConfig.h"
+#include "foundation/PxAssert.h"
+
+using namespace physx;
+
+class PhysXSample;
+
+class SampleRandomPrecomputed
+{
+public:
+
+ SampleRandomPrecomputed(PhysXSample& app);
+ ~SampleRandomPrecomputed();
+
+ PxF32 getRandom() const {return mPrecomputedRandomSequence[(mPrecomputedRandomSequenceCount++) % PRECOMPUTED_RANDOM_SEQUENCE_SIZE];}
+ PxF32 getRandomInRange(const PxF32 a, const PxF32 b)
+ {
+ PX_ASSERT(b>a);
+ return a + (b-a)*getRandom();
+ }
+
+private:
+
+ enum
+ {
+ PRECOMPUTED_RANDOM_SEQUENCE_SIZE=65536
+ };
+ PxF32* mPrecomputedRandomSequence;
+ mutable PxU32 mPrecomputedRandomSequenceCount;
+};
+
+#endif //SAMPLE_RANDOM_PRECOMPUTED_H
diff --git a/PhysX_3.4/Samples/SampleBase/SampleStepper.cpp b/PhysX_3.4/Samples/SampleBase/SampleStepper.cpp
new file mode 100644
index 00000000..9f3fda8f
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SampleStepper.cpp
@@ -0,0 +1,206 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SampleStepper.h"
+#include "PhysXSample.h"
+#include "PxScene.h"
+
+
+bool DebugStepper::advance(PxScene* scene, PxReal dt, void* scratchBlock, PxU32 scratchBlockSize)
+{
+ mTimer.getElapsedSeconds();
+
+ {
+ PxSceneWriteLock writeLock(*scene);
+ scene->simulate(mStepSize, NULL, scratchBlock, scratchBlockSize);
+ }
+
+ return true;
+}
+
+void DebugStepper::wait(PxScene* scene)
+{
+ mSample->onSubstepPreFetchResult();
+ {
+ PxSceneWriteLock writeLock(*scene);
+ scene->fetchResults(true, NULL);
+ }
+ mSimulationTime = (PxReal)mTimer.getElapsedSeconds();
+ mSample->onSubstep(mStepSize);
+}
+
+void StepperTask::run()
+{
+ mStepper->substepDone(this);
+ release();
+}
+
+void StepperTaskSimulate::run()
+{
+ mStepper->simulate(mCont);
+ mStepper->getSample().onSubstepStart(mStepper->getSubStepSize());
+}
+
+
+void MultiThreadStepper::simulate(physx::PxBaseTask* ownerTask)
+{
+ PxSceneWriteLock writeLock(*mScene);
+
+ mScene->simulate(mSubStepSize, ownerTask, mScratchBlock, mScratchBlockSize);
+}
+
+void MultiThreadStepper::renderDone()
+{
+ if(mFirstCompletionPending)
+ {
+ mCompletion0.removeReference();
+ mFirstCompletionPending = false;
+ }
+}
+
+
+
+bool MultiThreadStepper::advance(PxScene* scene, PxReal dt, void* scratchBlock, PxU32 scratchBlockSize)
+{
+ mScratchBlock = scratchBlock;
+ mScratchBlockSize = scratchBlockSize;
+
+ if(!mSync)
+ mSync = SAMPLE_NEW(PsSyncAlloc);
+
+ substepStrategy(dt, mNbSubSteps, mSubStepSize);
+
+ if(mNbSubSteps == 0) return false;
+
+ mScene = scene;
+
+ mSync->reset();
+
+ mCurrentSubStep = 1;
+
+ mCompletion0.setContinuation(*mScene->getTaskManager(), NULL);
+
+ mSimulationTime = 0.0f;
+ mTimer.getElapsedSeconds();
+
+ // take first substep
+ substep(mCompletion0);
+ mFirstCompletionPending = true;
+
+ return true;
+}
+
+void MultiThreadStepper::substepDone(StepperTask* ownerTask)
+{
+ mSample->onSubstepPreFetchResult();
+
+ {
+#if !PX_PROFILE
+ PxSceneWriteLock writeLock(*mScene);
+#endif
+ mScene->fetchResults(true);
+ }
+
+ PxReal delta = (PxReal)mTimer.getElapsedSeconds();
+ mSimulationTime += delta;
+
+ mSample->onSubstep(mSubStepSize);
+
+ if(mCurrentSubStep>=mNbSubSteps)
+ {
+ mSync->set();
+ }
+ else
+ {
+ StepperTask &s = ownerTask == &mCompletion0 ? mCompletion1 : mCompletion0;
+ s.setContinuation(*mScene->getTaskManager(), NULL);
+ mCurrentSubStep++;
+
+ mTimer.getElapsedSeconds();
+
+ substep(s);
+
+ // after the first substep, completions run freely
+ s.removeReference();
+ }
+}
+
+
+void MultiThreadStepper::substep(StepperTask& completionTask)
+{
+ // setup any tasks that should run in parallel to simulate()
+ mSample->onSubstepSetup(mSubStepSize, &completionTask);
+
+ // step
+ {
+ mSimulateTask.setContinuation(&completionTask);
+ mSimulateTask.removeReference();
+ }
+ // parallel sample tasks are started in mSolveTask (after solve was called which acquires a write lock).
+}
+
+void FixedStepper::substepStrategy(const PxReal stepSize, PxU32& substepCount, PxReal& substepSize)
+{
+ if(mAccumulator > mFixedSubStepSize)
+ mAccumulator = 0.0f;
+
+ // don't step less than the step size, just accumulate
+ mAccumulator += stepSize;
+ if(mAccumulator < mFixedSubStepSize)
+ {
+ substepCount = 0;
+ return;
+ }
+
+ substepSize = mFixedSubStepSize;
+ substepCount = PxMin(PxU32(mAccumulator/mFixedSubStepSize), mMaxSubSteps);
+
+ mAccumulator -= PxReal(substepCount)*substepSize;
+}
+
+void VariableStepper::substepStrategy(const PxReal stepSize, PxU32& substepCount, PxReal& substepSize)
+{
+ if(mAccumulator > mMaxSubStepSize)
+ mAccumulator = 0.0f;
+
+ // don't step less than the min step size, just accumulate
+ mAccumulator += stepSize;
+ if(mAccumulator < mMinSubStepSize)
+ {
+ substepCount = 0;
+ return;
+ }
+
+ substepCount = PxMin(PxU32(PxCeil(mAccumulator/mMaxSubStepSize)), mMaxSubSteps);
+ substepSize = PxMin(mAccumulator/substepCount, mMaxSubStepSize);
+
+ mAccumulator -= PxReal(substepCount)*substepSize;
+}
+
+
diff --git a/PhysX_3.4/Samples/SampleBase/SampleStepper.h b/PhysX_3.4/Samples/SampleBase/SampleStepper.h
new file mode 100644
index 00000000..e271caf7
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SampleStepper.h
@@ -0,0 +1,229 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef SAMPLE_STEPPER_H
+#define SAMPLE_STEPPER_H
+
+#include "SampleAllocator.h"
+#include "SampleAllocatorSDKClasses.h"
+#include "RendererMemoryMacros.h"
+#include "task/PxTask.h"
+#include "PxPhysicsAPI.h"
+#include "PsTime.h"
+
+class PhysXSample;
+
+class Stepper: public SampleAllocateable
+{
+ public:
+ Stepper() : mSample(NULL) {}
+ virtual ~Stepper() {}
+
+ virtual bool advance(PxScene* scene, PxReal dt, void* scratchBlock, PxU32 scratchBlockSize) = 0;
+ virtual void wait(PxScene* scene) = 0;
+ virtual void substepStrategy(const PxReal stepSize, PxU32& substepCount, PxReal& substepSize) = 0;
+ virtual void postRender(const PxReal stepSize) = 0;
+
+ virtual void setSubStepper(const PxReal stepSize, const PxU32 maxSteps) {}
+ virtual void renderDone() {}
+ virtual void shutdown() {}
+
+ PxReal getSimulationTime() const { return mSimulationTime; }
+
+ PhysXSample& getSample() { return *mSample; }
+ const PhysXSample& getSample() const { return *mSample; }
+ void setSample(PhysXSample* sample) { mSample = sample; }
+
+protected:
+ PhysXSample* mSample;
+ Ps::Time mTimer;
+ PxReal mSimulationTime;
+
+};
+
+class MultiThreadStepper;
+class StepperTask : public physx::PxLightCpuTask
+{
+public:
+ void setStepper(MultiThreadStepper* stepper) { mStepper = stepper; }
+ MultiThreadStepper* getStepper() { return mStepper; }
+ const MultiThreadStepper* getStepper() const { return mStepper; }
+ const char* getName() const { return "Stepper Task"; }
+ void run();
+protected:
+ MultiThreadStepper* mStepper;
+};
+
+class StepperTaskSimulate : public StepperTask
+{
+
+public:
+ StepperTaskSimulate(){}
+ void run();
+};
+
+class MultiThreadStepper : public Stepper
+{
+public:
+ MultiThreadStepper()
+ : mFirstCompletionPending(false)
+ , mScene(NULL)
+ , mSync(NULL)
+ , mCurrentSubStep(0)
+ , mNbSubSteps(0)
+ {
+ mCompletion0.setStepper(this);
+ mCompletion1.setStepper(this);
+ mSimulateTask.setStepper(this);
+ }
+
+ ~MultiThreadStepper() {}
+
+ virtual bool advance(PxScene* scene, PxReal dt, void* scratchBlock, PxU32 scratchBlockSize);
+ virtual void substepDone(StepperTask* ownerTask);
+ virtual void renderDone();
+ virtual void postRender(const PxReal stepSize){}
+
+ // if mNbSubSteps is 0 then the sync will never
+ // be set so waiting would cause a deadlock
+ virtual void wait(PxScene* scene) { if(mNbSubSteps && mSync)mSync->wait(); }
+ virtual void shutdown() { DELETESINGLE(mSync); }
+ virtual void reset() = 0;
+ virtual void substepStrategy(const PxReal stepSize, PxU32& substepCount, PxReal& substepSize) = 0;
+ virtual void simulate(physx::PxBaseTask* ownerTask);
+ PxReal getSubStepSize() const { return mSubStepSize; }
+
+protected:
+ void substep(StepperTask& completionTask);
+
+ // we need two completion tasks because when multistepping we can't submit completion0 from the
+ // substepDone function which is running inside completion0
+ bool mFirstCompletionPending;
+ StepperTaskSimulate mSimulateTask;
+ StepperTask mCompletion0, mCompletion1;
+ PxScene* mScene;
+ PsSyncAlloc* mSync;
+
+ PxU32 mCurrentSubStep;
+ PxU32 mNbSubSteps;
+ PxReal mSubStepSize;
+ void* mScratchBlock;
+ PxU32 mScratchBlockSize;
+};
+
+class DebugStepper : public Stepper
+{
+public:
+ DebugStepper(const PxReal stepSize) : mStepSize(stepSize) {}
+
+ virtual void substepStrategy(const PxReal stepSize, PxU32& substepCount, PxReal& substepSize)
+ {
+ substepCount = 1;
+ substepSize = mStepSize;
+ }
+
+ virtual bool advance(PxScene* scene, PxReal dt, void* scratchBlock, PxU32 scratchBlockSize);
+
+ virtual void postRender(const PxReal stepSize)
+ {
+ }
+
+ virtual void setSubStepper(const PxReal stepSize, const PxU32 maxSteps)
+ {
+ mStepSize = stepSize;
+ }
+
+ virtual void wait(PxScene* scene);
+
+ PxReal mStepSize;
+};
+
+// The way this should be called is:
+// bool stepped = advance(dt)
+//
+// ... reads from the scene graph for rendering
+//
+// if(stepped) renderDone()
+//
+// ... anything that doesn't need access to the physics scene
+//
+// if(stepped) sFixedStepper.wait()
+//
+// Note that per-substep callbacks to the sample need to be issued out of here,
+// between fetchResults and simulate
+
+class FixedStepper : public MultiThreadStepper
+{
+public:
+ FixedStepper(const PxReal subStepSize, const PxU32 maxSubSteps)
+ : MultiThreadStepper()
+ , mAccumulator(0)
+ , mFixedSubStepSize(subStepSize)
+ , mMaxSubSteps(maxSubSteps)
+ {
+ }
+
+ virtual void substepStrategy(const PxReal stepSize, PxU32& substepCount, PxReal& substepSize);
+ virtual void reset() { mAccumulator = 0.0f; }
+
+ virtual void setSubStepper(const PxReal stepSize, const PxU32 maxSteps) { mFixedSubStepSize = stepSize; mMaxSubSteps = maxSteps;}
+
+ virtual void postRender(const PxReal stepSize)
+ {
+ }
+
+ PxReal mAccumulator;
+ PxReal mFixedSubStepSize;
+ PxU32 mMaxSubSteps;
+};
+
+
+class VariableStepper : public MultiThreadStepper
+{
+public:
+ VariableStepper(const PxReal minSubStepSize, const PxReal maxSubStepSize, const PxU32 maxSubSteps)
+ : MultiThreadStepper()
+ , mAccumulator(0)
+ , mMinSubStepSize(minSubStepSize)
+ , mMaxSubStepSize(maxSubStepSize)
+ , mMaxSubSteps(maxSubSteps)
+ {
+ }
+
+ virtual void substepStrategy(const PxReal stepSize, PxU32& substepCount, PxReal& substepSize);
+ virtual void reset() { mAccumulator = 0.0f; }
+
+private:
+ VariableStepper& operator=(const VariableStepper&);
+ PxReal mAccumulator;
+ const PxReal mMinSubStepSize;
+ const PxReal mMaxSubStepSize;
+ const PxU32 mMaxSubSteps;
+};
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/SampleUserInputDefines.h b/PhysX_3.4/Samples/SampleBase/SampleUserInputDefines.h
new file mode 100644
index 00000000..69517783
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SampleUserInputDefines.h
@@ -0,0 +1,138 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef SAMPLE_USER_INPUT_DEFINES_H
+#define SAMPLE_UTILS_H
+
+#if defined(RENDERER_WINDOWS) && !PX_XBOXONE
+
+#define DIGITAL_INPUT_EVENT_DEF(var, winKey, xbox360key, xboxonekey, ps3Key, ps4Key, andrKey, osxKey, iosKey, linuxKey, wiiuKey) {\
+ const SampleFramework::InputEvent* retVal = SampleFramework::SamplePlatform::platform()->getSampleUserInput()->registerInputEvent(SampleFramework::InputEvent(var, false),winKey, #var); \
+ if(retVal) inputEvents.push_back(retVal); }
+#define ANALOG_INPUT_EVENT_DEF(var, sensitivity, winKey, xbox360key, xboxonekey, ps3Key, ps4Key, andrKey, osxKey, iosKey, linuxKey, wiiuKey) {\
+ const SampleFramework::InputEvent* retVal = (SampleFramework::SamplePlatform::platform()->getSampleUserInput()->registerInputEvent(SampleFramework::InputEvent(var, true,sensitivity),winKey, #var)); \
+ if(retVal) inputEvents.push_back(retVal); }
+#define TOUCH_INPUT_EVENT_DEF(var, caption, andrKey, iosKey)
+
+#elif defined(RENDERER_WINDOWS) && PX_XBOXONE
+
+#define DIGITAL_INPUT_EVENT_DEF(var, winKey, xbox360key, xboxonekey, ps3Key, ps4Key, andrKey, osxKey, iosKey, linuxKey, wiiuKey) {\
+ const SampleFramework::InputEvent* retVal = SampleFramework::SamplePlatform::platform()->getSampleUserInput()->registerInputEvent(SampleFramework::InputEvent(var, false),xboxonekey, #var); \
+ if(retVal) inputEvents.push_back(retVal); }
+#define ANALOG_INPUT_EVENT_DEF(var, sensitivity, winKey, xbox360key, xboxonekey, ps3Key, ps4Key, andrKey, osxKey, iosKey, linuxKey, wiiuKey) {\
+ const SampleFramework::InputEvent* retVal = (SampleFramework::SamplePlatform::platform()->getSampleUserInput()->registerInputEvent(SampleFramework::InputEvent(var, true,sensitivity),xboxonekey, #var)); \
+ if(retVal) inputEvents.push_back(retVal); }
+#define TOUCH_INPUT_EVENT_DEF(var, caption, andrKey, iosKey)
+
+#elif defined (RENDERER_XBOX360)
+
+#define DIGITAL_INPUT_EVENT_DEF(var, winKey, xbox360key, xboxonekey, ps3Key, ps4Key, andrKey, osxKey, iosKey, linuxKey, wiiuKey) {\
+ const SampleFramework::InputEvent* retVal = (SampleFramework::SamplePlatform::platform()->getSampleUserInput()->registerInputEvent(SampleFramework::InputEvent(var, false),xbox360key, #var)); \
+ if(retVal) inputEvents.push_back(retVal); }
+#define ANALOG_INPUT_EVENT_DEF(var, sensitivity, winKey, xbox360key, xboxonekey, ps3Key, ps4Key, andrKey, osxKey, iosKey, linuxKey, wiiuKey) {\
+ const SampleFramework::InputEvent* retVal = (SampleFramework::SamplePlatform::platform()->getSampleUserInput()->registerInputEvent(SampleFramework::InputEvent(var, true,sensitivity),xbox360key, #var)); \
+ if(retVal) inputEvents.push_back(retVal); }
+#define TOUCH_INPUT_EVENT_DEF(var, caption, andrKey, iosKey)
+
+#elif defined (RENDERER_PS4)
+
+#define DIGITAL_INPUT_EVENT_DEF(var, winKey, xbox360key, xboxonekey, ps3Key, ps4Key, andrKey, osxKey, iosKey, linuxKey, wiiuKey) {\
+ const SampleFramework::InputEvent* retVal = (SampleFramework::SamplePlatform::platform()->getSampleUserInput()->registerInputEvent(SampleFramework::InputEvent(var, false),ps4Key, #var)); \
+ if(retVal) inputEvents.push_back(retVal); }
+#define ANALOG_INPUT_EVENT_DEF(var, sensitivity, winKey, xbox360key, xboxonekey, ps3Key, ps4Key, andrKey, osxKey, iosKey, linuxKey, wiiuKey) {\
+ const SampleFramework::InputEvent* retVal = (SampleFramework::SamplePlatform::platform()->getSampleUserInput()->registerInputEvent(SampleFramework::InputEvent(var, true,sensitivity),ps4Key, #var)); \
+ if(retVal) inputEvents.push_back(retVal); }
+#define TOUCH_INPUT_EVENT_DEF(var, caption, andrKey, iosKey)
+
+#elif defined (RENDERER_PS3)
+
+#define DIGITAL_INPUT_EVENT_DEF(var, winKey, xbox360key, xboxonekey, ps3Key, ps4Key, andrKey, osxKey, iosKey, linuxKey, wiiuKey) {\
+ const SampleFramework::InputEvent* retVal = (SampleFramework::SamplePlatform::platform()->getSampleUserInput()->registerInputEvent(SampleFramework::InputEvent(var, false),ps3Key, #var)); \
+ if(retVal) inputEvents.push_back(retVal); }
+#define ANALOG_INPUT_EVENT_DEF(var, sensitivity, winKey, xbox360key, xboxonekey, ps3Key, ps4Key, andrKey, osxKey, iosKey, linuxKey, wiiuKey) {\
+ const SampleFramework::InputEvent* retVal = (SampleFramework::SamplePlatform::platform()->getSampleUserInput()->registerInputEvent(SampleFramework::InputEvent(var, true,sensitivity),ps3Key, #var)); \
+ if(retVal) inputEvents.push_back(retVal); }
+#define TOUCH_INPUT_EVENT_DEF(var, caption, andrKey, iosKey)
+
+#elif defined (RENDERER_ANDROID)
+
+#define DIGITAL_INPUT_EVENT_DEF(var, winKey, xbox360key, xboxonekey, ps3Key, ps4Key, andrKey, osxKey, iosKey, linuxKey, wiiuKey) {\
+ const SampleFramework::InputEvent* retVal = (SampleFramework::SamplePlatform::platform()->getSampleUserInput()->registerInputEvent(SampleFramework::InputEvent(var, false),andrKey, #var)); \
+ if(retVal) inputEvents.push_back(retVal); }
+#define ANALOG_INPUT_EVENT_DEF(var, sensitivity, winKey, xbox360key, xboxonekey, ps3Key, ps4Key, andrKey, osxKey, iosKey, linuxKey, wiiuKey) {\
+ const SampleFramework::InputEvent* retVal = (SampleFramework::SamplePlatform::platform()->getSampleUserInput()->registerInputEvent(SampleFramework::InputEvent(var, true,sensitivity),andrKey, #var)); \
+ if(retVal) inputEvents.push_back(retVal); }
+#define TOUCH_INPUT_EVENT_DEF(var, caption, andrKey, iosKey) {\
+ const SampleFramework::InputEvent* retVal = (SampleFramework::SamplePlatform::platform()->getSampleUserInput()->registerTouchInputEvent(SampleFramework::InputEvent(var, false),andrKey,caption, #var)); \
+ if(retVal) inputEvents.push_back(retVal); }
+
+#elif defined (RENDERER_MACOSX)
+
+#define DIGITAL_INPUT_EVENT_DEF(var, winKey, xbox360key, xboxonekey, ps3Key, ps4Key, andrKey, osxKey, iosKey, linuxKey, wiiuKey) {\
+ const SampleFramework::InputEvent* retVal = (SampleFramework::SamplePlatform::platform()->getSampleUserInput()->registerInputEvent(SampleFramework::InputEvent(var, false),osxKey, #var)); \
+ if(retVal) inputEvents.push_back(retVal); }
+#define ANALOG_INPUT_EVENT_DEF(var, sensitivity, winKey, xbox360key, xboxonekey, ps3Key, ps4Key, andrKey, osxKey, iosKey, linuxKey, wiiuKey) {\
+ const SampleFramework::InputEvent* retVal = (SampleFramework::SamplePlatform::platform()->getSampleUserInput()->registerInputEvent(SampleFramework::InputEvent(var, true,sensitivity),osxKey, #var)); \
+ if(retVal) inputEvents.push_back(retVal); }
+#define TOUCH_INPUT_EVENT_DEF(var, caption, andrKey, iosKey)
+
+#elif defined (RENDERER_IOS)
+
+#define DIGITAL_INPUT_EVENT_DEF(var, winKey, xbox360key, xboxonekey, ps3Key, ps4Key, andrKey, osxKey, iosKey, linuxKey, wiiuKey) {\
+ const SampleFramework::InputEvent* retVal = (SampleFramework::SamplePlatform::platform()->getSampleUserInput()->registerInputEvent(SampleFramework::InputEvent(var, false),iosKey, #var)); \
+ if(retVal) inputEvents.push_back(retVal); }
+#define ANALOG_INPUT_EVENT_DEF(var, sensitivity, winKey, xbox360key, xboxonekey, ps3Key, ps4Key, andrKey, osxKey, iosKey, linuxKey, wiiuKey) {\
+ const SampleFramework::InputEvent* retVal = (SampleFramework::SamplePlatform::platform()->getSampleUserInput()->registerInputEvent(SampleFramework::InputEvent(var, true,sensitivity),iosKey, #var)); \
+ if(retVal) inputEvents.push_back(retVal); }
+#define TOUCH_INPUT_EVENT_DEF(var, caption, andrKey, iosKey) {\
+ const SampleFramework::InputEvent* retVal = (SampleFramework::SamplePlatform::platform()->getSampleUserInput()->registerTouchInputEvent(SampleFramework::InputEvent(var, false),iosKey,caption, #var)); \
+ if(retVal) inputEvents.push_back(retVal); }
+
+#elif defined (RENDERER_LINUX)
+
+#define DIGITAL_INPUT_EVENT_DEF(var, winKey, xbox360key, xboxonekey, ps3Key, ps4Key, andrKey, osxKey, iosKey, linuxKey, wiiuKey) {\
+ const SampleFramework::InputEvent* retVal = (SampleFramework::SamplePlatform::platform()->getSampleUserInput()->registerInputEvent(SampleFramework::InputEvent(var, false),linuxKey, #var)); \
+ if(retVal) inputEvents.push_back(retVal); }
+#define ANALOG_INPUT_EVENT_DEF(var, sensitivity, winKey, xbox360key, xboxonekey, ps3Key, ps4Key, andrKey, osxKey, iosKey, linuxKey, wiiuKey) {\
+ const SampleFramework::InputEvent* retVal = (SampleFramework::SamplePlatform::platform()->getSampleUserInput()->registerInputEvent(SampleFramework::InputEvent(var, true,sensitivity),linuxKey, #var)); \
+ if(retVal) inputEvents.push_back(retVal); }
+#define TOUCH_INPUT_EVENT_DEF(var, caption, andrKey, iosKey)
+
+#elif defined (RENDERER_WIIU)
+
+#define DIGITAL_INPUT_EVENT_DEF(var, winKey, xbox360key, xboxonekey, ps3Key, ps4Key, andrKey, osxKey, iosKey, linuxKey, wiiuKey) {\
+ const SampleFramework::InputEvent* retVal = (SampleFramework::SamplePlatform::platform()->getSampleUserInput()->registerInputEvent(SampleFramework::InputEvent(var, false), wiiuKey, #var)); \
+ if(retVal) inputEvents.push_back(retVal); }
+#define ANALOG_INPUT_EVENT_DEF(var, sensitivity, winKey, xbox360key, xboxonekey, ps3Key, ps4Key, andrKey, osxKey, iosKey, linuxKey, wiiuKey) {\
+ const SampleFramework::InputEvent* retVal = (SampleFramework::SamplePlatform::platform()->getSampleUserInput()->registerInputEvent(SampleFramework::InputEvent(var, true,sensitivity), wiiuKey, #var)); \
+ if(retVal) inputEvents.push_back(retVal); }
+#define TOUCH_INPUT_EVENT_DEF(var, caption, andrKey, iosKey)
+
+#endif
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/SampleUtils.h b/PhysX_3.4/Samples/SampleBase/SampleUtils.h
new file mode 100644
index 00000000..e20c2eb8
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/SampleUtils.h
@@ -0,0 +1,47 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef SAMPLE_UTILS_H
+#define SAMPLE_UTILS_H
+
+#include "common/PxPhysXCommonConfig.h"
+#include "foundation/PxVec3.h"
+#include "PsMathUtils.h"
+
+ //Integer representation of a floating-point value.
+ #define PX_IR(x) ((PxU32&)(x))
+
+ // PT: TODO: move those helpers to a shared place, this is also used in the SDK
+
+ PX_INLINE PxReal degtorad(PxReal d)
+ {
+ return d * PxPi / 180.0f;
+ }
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/Test.h b/PhysX_3.4/Samples/SampleBase/Test.h
new file mode 100644
index 00000000..15a02094
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/Test.h
@@ -0,0 +1,39 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+
+#include "Ps.h"
+
+//! \file top level test include file
+
+/* namespace trickery */
+namespace physx
+{
+ // alias shared foundation to something usable
+ namespace Ps = shdfnd;
+}
+// we need this until all our code lives in physx namespace
+using namespace physx;
diff --git a/PhysX_3.4/Samples/SampleBase/TestCloth.h b/PhysX_3.4/Samples/SampleBase/TestCloth.h
new file mode 100644
index 00000000..3794909d
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/TestCloth.h
@@ -0,0 +1,108 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef TEST_CLOTH
+#define TEST_CLOTH
+
+#include "PxShape.h"
+#include "cloth/PxCloth.h"
+
+using namespace physx;
+
+namespace Test
+{
+ class ClothCollision
+ {
+ public:
+ virtual PxU32 addSphere(const PxVec3& position, PxReal radius) = 0;
+ virtual PxU32 addCapsuleIndex(PxU32 i0, PxU32 i1) = 0;
+ virtual PxU32 addCapsule(const PxVec3& position1, PxReal radius1, const PxVec3& position2, PxReal radius2) = 0;
+ virtual PxU32 getNbSpheres() const = 0;
+ virtual const PxClothCollisionSphere* getSpheres() const = 0;
+ virtual void setClothPose(const PxTransform &pose) = 0;
+ virtual void setCapsuleMotion(PxU32 id, const PxVec3 &linear, const PxVec3 &angular) = 0;
+ virtual void setSphereMotion(PxU32 id, const PxVec3 &linear) = 0;
+ virtual void updateMotion(PxReal time, PxReal timestep) = 0;
+ virtual bool generateClothCollisionData(PxClothCollisionData &) const = 0;
+ virtual ~ClothCollision() {};
+ };
+
+ class Cloth
+ {
+ public:
+
+ // border flags
+ enum
+ {
+ NONE = 0,
+ BORDER_TOP = (1 << 0),
+ BORDER_BOTTOM = (1 << 1),
+ BORDER_LEFT = (1 << 2),
+ BORDER_RIGHT = (1 << 3)
+ };
+
+ // solver types
+ enum SolverType
+ {
+ eMIXED = 1 << 0, // eSTIFF for vertical fiber, eFAST for everything else
+ eFAST = 1 << 1, // eFAST for everything
+ eSTIFF = 1 << 2, // eSTIFF for everything
+ eZEROSTRETCH = 1 << 3 // eZEROSTRETCH for zero stretch fiber, eFAST for everything else
+ };
+
+ virtual void detachVertex(PxU32 vertexId) = 0;
+ virtual void attachVertexToWorld(PxU32 vertexId) = 0;
+ virtual void attachVertexToWorld(PxU32 vertexId, const PxVec3& pos) = 0;
+ virtual void attachBorderToWorld(PxU32 borderFlags) = 0;
+ virtual void attachOverlapToShape(PxShape* shape, PxReal radius = 0.1f) = 0;
+ virtual void createVirtualParticles(int numSamples) = 0;
+ virtual ClothCollision& getCollision() = 0;
+ virtual const PxTransform& getClothPose() const = 0;
+ virtual void release() = 0;
+ virtual PxCloth& getCloth() = 0;
+ virtual void setCloth(PxCloth&) = 0;
+ virtual PxU32 getNbParticles() const = 0;
+ virtual PxClothParticle* getParticles() = 0;
+ virtual PxBounds3 getWorldBounds(bool includeColliders = false) = 0;
+ virtual void setClothPose(const PxTransform &pose, bool keepIntertia = true) = 0;
+ virtual void setAnimationSpeed(PxReal) = 0;
+ virtual void setDampingCoefficient(PxReal d) = 0;
+ virtual void setMassScalingCoefficient(PxReal s) = 0;
+ virtual void setMotion(const PxVec3 &linear, const PxVec3 &angular) = 0;
+ virtual void setSolverFrequency(PxReal v) = 0;
+ virtual void setSolverType(Cloth::SolverType solverType) = 0;
+ virtual void setStiffness(PxReal v) = 0;
+ virtual void setSweptContact(bool val) = 0;
+ virtual void setUseGPU(bool val) = 0;
+ virtual void updateMotion(PxReal time, PxReal timestep, bool keepInertia = true) = 0;
+ virtual ~Cloth() {};
+ };
+};
+
+#endif // TEST_CLOTH
diff --git a/PhysX_3.4/Samples/SampleBase/TestClothCollisionHelpers.cpp b/PhysX_3.4/Samples/SampleBase/TestClothCollisionHelpers.cpp
new file mode 100644
index 00000000..a11894ae
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/TestClothCollisionHelpers.cpp
@@ -0,0 +1,213 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+#include "TestClothCollisionHelpers.h"
+
+#include "cloth/PxCloth.h"
+#include "cloth/PxClothCollisionData.h"
+
+//needed for sync primitives.
+#if PX_WINDOWS
+#define NOMINMAX
+# include <windows.h>
+#elif defined(_XBOX)
+# include "xbox360\xtl_XBOX.h"
+#endif
+
+//----------------------------------------------------------------------------//
+Test::ClothCollision::ClothCollision() :
+ mClothPose(PxVec3(0.0f), PxQuat(PxIdentity))
+{
+}
+
+//----------------------------------------------------------------------------//
+void Test::ClothCollision::release()
+{
+ delete this;
+}
+
+//----------------------------------------------------------------------------//
+
+Test::ClothCollision::~ClothCollision()
+{
+ mSphereMotion.clear();
+}
+
+//----------------------------------------------------------------------------//
+PxU32 Test::ClothCollision::addSphere(const PxVec3& position, PxReal radius)
+{
+ PxClothCollisionSphere sphere;
+
+ sphere.pos = position;
+ sphere.radius = radius;
+
+ mSpheres.pushBack(sphere);
+ mOrigPositions.pushBack(sphere.pos);
+ mWorldPositions.pushBack(sphere.pos);
+
+ MotionGenerator mg;
+
+ mg.mTransform.p = position;
+ mSphereMotion.pushBack(mg);
+
+ return mSpheres.size() - 1;
+}
+
+//----------------------------------------------------------------------------//
+PxU32 Test::ClothCollision::addCapsuleIndex(PxU32 i0, PxU32 i1)
+{
+ mCapsuleIndices.pushBack(i0);
+ mCapsuleIndices.pushBack(i1);
+
+ MotionGenerator mg;
+
+ mg.mTransform.p = 0.5f * (mOrigPositions[i0] + mOrigPositions[i1]);
+ mCapsuleMotion.pushBack(mg);
+
+ PX_ASSERT(( mCapsuleIndices.size() % 2) == 0);
+ return (mCapsuleIndices.size() / 2) - 1;
+}
+
+//----------------------------------------------------------------------------//
+PxU32 Test::ClothCollision::addCapsule(const PxVec3& position1, PxReal radius1,
+ const PxVec3& position2, PxReal radius2)
+{
+ PxU32 i0 = addSphere(position1, radius1);
+ PxU32 i1 = addSphere(position2, radius2);
+
+ return addCapsuleIndex(i0, i1);
+}
+
+//----------------------------------------------------------------------------//
+void Test::ClothCollision::setClothPose(const PxTransform &clothPose)
+{
+ mClothPose = clothPose;
+ applyLocalTransform();
+}
+
+//----------------------------------------------------------------------------//
+void Test::ClothCollision::applyLocalTransform()
+{
+ PxTransform clothInv = mClothPose.getInverse();
+
+ PX_ASSERT(mSpheres.size() == mWorldPositions.size());
+
+ Test::Array<PxClothCollisionSphere>::Iterator sp = mSpheres.begin();
+ Test::Array<PxVec3>::Iterator o = mWorldPositions.begin();
+
+ for ( ; sp != mSpheres.end(); ++sp, ++o)
+ {
+ sp->pos = clothInv.transform(*o);
+ }
+}
+
+//----------------------------------------------------------------------------//
+PxU32 Test::ClothCollision::getNbSpheres() const
+{
+ return mSpheres.size();
+}
+
+//----------------------------------------------------------------------------//
+PxU32 Test::ClothCollision::getNbCapsules() const
+{
+ return mCapsuleIndices.size()/2;
+}
+
+//----------------------------------------------------------------------------//
+const PxClothCollisionSphere* Test::ClothCollision::getSpheres() const
+{
+ return mSpheres.begin();
+}
+
+//----------------------------------------------------------------------------//
+const PxU32* Test::ClothCollision::getCapsules() const
+{
+ return mCapsuleIndices.begin();
+}
+
+//----------------------------------------------------------------------------//
+PxBounds3 Test::ClothCollision::getWorldBounds() const
+{
+ PxBounds3 totalBounds = PxBounds3::empty();
+ for (PxU32 i = 0; i < mSpheres.size(); i++)
+ {
+ PxVec3 p = mClothPose.transform(mSpheres[i].pos);
+ PxBounds3 bounds = PxBounds3::centerExtents(p, PxVec3(mSpheres[i].radius));
+ totalBounds.minimum = totalBounds.minimum.minimum(bounds.minimum);
+ totalBounds.maximum = totalBounds.maximum.maximum(bounds.maximum);
+ }
+ return totalBounds;
+}
+
+//----------------------------------------------------------------------------//
+void Test::ClothCollision::setSphereMotion(PxU32 id, const PxVec3 &linear)
+{
+ mSphereMotion[id].mLinear = linear;
+}
+
+//----------------------------------------------------------------------------//
+void Test::ClothCollision::setCapsuleMotion(PxU32 id, const PxVec3 &linear, const PxVec3& angular)
+{
+ mCapsuleMotion[id].mLinear = linear;
+ mCapsuleMotion[id].mAngular = angular;
+}
+
+//----------------------------------------------------------------------------//
+void Test::ClothCollision::updateMotion(PxReal time, PxReal timestep)
+{
+ for (PxU32 i = 0; i < mSphereMotion.size(); i++)
+ mSphereMotion[i].update(time, timestep);
+
+ for (PxU32 i = 0; i < mCapsuleMotion.size(); i++)
+ mCapsuleMotion[i].update(time, timestep);
+
+ // update independent sphere positions first
+ PxU32 nbSpheres = mWorldPositions.size();
+ for (PxU32 i = 0; i < nbSpheres; i++)
+ mWorldPositions[i] = mSphereMotion[i].mTransform.p;
+
+ // update capsule position and orientation
+ PxU32 numCapsules = mCapsuleIndices.size() / 2;
+ PX_ASSERT((mCapsuleIndices.size() % 2) == 0);
+ for (PxU32 i = 0; i < numCapsules; i++)
+ {
+ PxU32 i0 = mCapsuleIndices[i*2];
+ PxU32 i1 = mCapsuleIndices[i*2+1];
+
+ PxTransform transform = mCapsuleMotion[i].mTransform;
+ PxVec3 o0 = mOrigPositions[i0];
+ PxVec3 o1 = mOrigPositions[i1];
+ PxVec3 c = 0.5f * (o0 + o1);
+
+ mWorldPositions[i0] = transform.rotate(o0 - c) + transform.p;
+ mWorldPositions[i1] = transform.rotate(o1 - c) + transform.p;
+ }
+
+ applyLocalTransform();
+}
+
diff --git a/PhysX_3.4/Samples/SampleBase/TestClothCollisionHelpers.h b/PhysX_3.4/Samples/SampleBase/TestClothCollisionHelpers.h
new file mode 100644
index 00000000..54594e26
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/TestClothCollisionHelpers.h
@@ -0,0 +1,98 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef WRAP_CLOTH_H
+#define WRAP_CLOTH_H
+
+//----------------------------------------------------------------------------//
+#include "PxPhysicsAPI.h"
+#include "TestArray.h"
+#include "TestMotionGenerator.h"
+
+#include "cloth/PxCloth.h"
+
+#include "PhysXSample.h"
+
+//----------------------------------------------------------------------------//
+
+namespace physx
+{
+ class PxClothMeshDesc;
+ class PxClothFabric;
+}
+
+namespace Test
+{
+ // wrapper for collision data for cloth
+ class ClothCollision
+ {
+ public:
+ friend class ::RenderClothActor;
+ ClothCollision();
+
+ // Test::ClothCollision
+ virtual PxU32 addSphere(const PxVec3& position, PxReal radius);
+ virtual PxU32 addCapsuleIndex(PxU32 i0, PxU32 i1);
+ virtual PxU32 addCapsule(const PxVec3& position1, PxReal radius1, const PxVec3& position2, PxReal radius2);
+ virtual PxU32 getNbSpheres() const;
+ virtual PxU32 getNbCapsules() const;
+
+ virtual PxBounds3 getWorldBounds() const;
+ virtual const PxClothCollisionSphere* getSpheres() const;
+ virtual const PxU32* getCapsules() const;
+
+ virtual void setClothPose(const PxTransform &clothPose);
+ virtual void setCapsuleMotion(PxU32 id, const PxVec3 &linear, const PxVec3 &angular);
+ virtual void setSphereMotion(PxU32 id, const PxVec3 &linear);
+ virtual void updateMotion(PxReal time, PxReal timestep);
+
+ virtual void release();
+
+
+ virtual ~ClothCollision();
+ protected:
+ // convert sphere positions to local pose of cloth
+ void applyLocalTransform();
+
+ protected:
+ PxTransform mClothPose;
+ Test::Array<PxVec3> mOrigPositions;
+ Test::Array<PxVec3> mWorldPositions;
+ Test::Array<PxClothCollisionSphere> mSpheres;
+ Test::Array<MotionGenerator> mSphereMotion;
+ Test::Array<MotionGenerator> mCapsuleMotion;
+ Test::Array<PxU32> mCapsuleIndices;
+ };
+}
+
+
+//----------------------------------------------------------------------------//
+
+#endif // WRAP_CLOTH_H
+
diff --git a/PhysX_3.4/Samples/SampleBase/TestClothHelpers.cpp b/PhysX_3.4/Samples/SampleBase/TestClothHelpers.cpp
new file mode 100644
index 00000000..3849c774
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/TestClothHelpers.cpp
@@ -0,0 +1,759 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "PxPhysXConfig.h"
+
+#if PX_USE_CLOTH_API
+
+#include "TestClothHelpers.h"
+
+#include "geometry/PxSphereGeometry.h"
+#include "cloth/PxCloth.h"
+#include "cloth/PxClothParticleData.h"
+#include "extensions/PxDefaultStreams.h"
+#include "extensions/PxShapeExt.h"
+#include "PxToolkit.h"
+#include "SampleArray.h"
+#include "PsHashSet.h"
+#include "geometry/PxGeometryQuery.h"
+
+bool Test::ClothHelpers::attachBorder(PxClothParticle* particles, PxU32 numParticles, PxBorderFlags borderFlag)
+{
+ // compute bounds in x and z
+ PxBounds3 bounds = PxBounds3::empty();
+
+ for(PxU32 i = 0; i < numParticles; i++)
+ bounds.include(particles[i].pos);
+
+ PxVec3 skin = bounds.getExtents() * 0.01f;
+ bounds.minimum += skin;
+ bounds.maximum -= skin;
+
+ if (borderFlag & BORDER_LEFT)
+ {
+ for (PxU32 i = 0; i < numParticles; i++)
+ if (particles[i].pos.x <= bounds.minimum.x)
+ particles[i].invWeight = 0.0f;
+ }
+ if (borderFlag & BORDER_RIGHT)
+ {
+ for (PxU32 i = 0; i < numParticles; i++)
+ if (particles[i].pos.x >= bounds.maximum.x)
+ particles[i].invWeight = 0.0f;
+ }
+ if (borderFlag & BORDER_BOTTOM)
+ {
+ for (PxU32 i = 0; i < numParticles; i++)
+ if (particles[i].pos.y <= bounds.minimum.y)
+ particles[i].invWeight = 0.0f;
+ }
+ if (borderFlag & BORDER_TOP)
+ {
+ for (PxU32 i = 0; i < numParticles; i++)
+ if (particles[i].pos.y >= bounds.maximum.y)
+ particles[i].invWeight = 0.0f;
+ }
+ if (borderFlag & BORDER_NEAR)
+ {
+ for (PxU32 i = 0; i < numParticles; i++)
+ if (particles[i].pos.z <= bounds.minimum.z)
+ particles[i].invWeight = 0.0f;
+ }
+ if (borderFlag & BORDER_FAR)
+ {
+ for (PxU32 i = 0; i < numParticles; i++)
+ if (particles[i].pos.z >= bounds.maximum.z)
+ particles[i].invWeight = 0.0f;
+ }
+
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool Test::ClothHelpers::attachBorder(PxCloth& cloth, PxBorderFlags borderFlag)
+{
+ PxClothParticleData* particleData = cloth.lockParticleData(PxDataAccessFlag::eWRITABLE);
+ if (!particleData)
+ return false;
+
+ PxU32 numParticles = cloth.getNbParticles();
+ PxClothParticle* particles = particleData->previousParticles;
+
+ attachBorder(particles, numParticles, borderFlag);
+
+ particleData->particles = 0;
+ particleData->unlock();
+
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool Test::ClothHelpers::attachClothOverlapToShape(PxCloth& cloth, PxShape& shape,PxReal radius)
+{
+ PxClothParticleData* particleData = cloth.lockParticleData(PxDataAccessFlag::eWRITABLE);
+ if (!particleData)
+ return false;
+
+ PxU32 numParticles = cloth.getNbParticles();
+ PxClothParticle* particles = particleData->previousParticles;
+
+ PxSphereGeometry sphere(radius);
+ PxTransform position = PxTransform(PxIdentity);
+ PxTransform pose = cloth.getGlobalPose();
+ for (PxU32 i = 0; i < numParticles; i++)
+ {
+ // check if particle overlaps shape volume
+ position.p = pose.transform(particles[i].pos);
+ if (PxGeometryQuery::overlap(shape.getGeometry().any(), PxShapeExt::getGlobalPose(shape, *shape.getActor()), sphere, position))
+ particles[i].invWeight = 0.0f;
+ }
+
+ particleData->particles = 0;
+ particleData->unlock();
+
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool Test::ClothHelpers::createCollisionCapsule(
+ const PxTransform &pose,
+ const PxVec3 &center0, PxReal r0, const PxVec3 &center1, PxReal r1,
+ SampleArray<PxClothCollisionSphere> &spheres, SampleArray<PxU32> &indexPairs)
+{
+ PxTransform invPose = pose.getInverse();
+
+ spheres.resize(2);
+
+ spheres[0].pos = invPose.transform(center0);
+ spheres[0].radius = r0;
+ spheres[1].pos = invPose.transform(center1);
+ spheres[1].radius = r1;
+
+ indexPairs.resize(2);
+ indexPairs[0] = 0;
+ indexPairs[1] = 1;
+
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+PxClothMeshDesc Test::ClothHelpers::createMeshGrid(PxVec3 dirU, PxVec3 dirV, PxU32 numU, PxU32 numV,
+ SampleArray<PxVec4>& vertices, SampleArray<PxU32>& indices, SampleArray<PxVec2>& texcoords)
+{
+ int numVertices = numU * numV;
+ int numQuads = (numU-1) * (numV-1);
+
+ vertices.resize(numVertices);
+ indices.resize(numQuads * 4);
+ texcoords.resize(numVertices);
+
+ // fill in point data
+ PxReal scaleU = 1 / PxReal(numU-1);
+ PxReal scaleV = 1 / PxReal(numV-1);
+
+ PxVec4* posIt = vertices.begin();
+ PxVec2* texIt = texcoords.begin();
+ for (PxU32 i = 0; i < numV; i++)
+ {
+ PxReal texV = i * scaleV;
+ PxVec3 posV = (texV - 0.5f) * dirV;
+ for (PxU32 j = 0; j < numU; j++)
+ {
+ PxReal texU = j * scaleU;
+ PxVec3 posU = (texU - 0.5f) * dirU;
+ *posIt++ = PxVec4(posU + posV, 1.0f);
+ *texIt++ = PxVec2(texU, 1.0f - texV);
+ }
+ }
+
+ // fill in quad index data
+ PxU32 *idxIt = indices.begin();
+ for (PxU32 i = 0; i < numV-1; i++)
+ {
+ for (PxU32 j = 0; j < numU-1; j++)
+ {
+ PxU32 i0 = i * numU + j;
+ *idxIt++ = i0;
+ *idxIt++ = i0 + 1;
+ *idxIt++ = i0 + numU + 1;
+ *idxIt++ = i0 + numU;
+ }
+ }
+
+ PxClothMeshDesc meshDesc;
+
+ // convert vertex array to PxBoundedData (desc.points)
+ meshDesc.points.data = vertices.begin();
+ meshDesc.points.count = static_cast<PxU32>(numVertices);
+ meshDesc.points.stride = sizeof(PxVec4);
+
+ meshDesc.invMasses.data = &vertices.begin()->w;
+ meshDesc.invMasses.count = static_cast<PxU32>(numVertices);
+ meshDesc.invMasses.stride = sizeof(PxVec4);
+
+ // convert index array to PxBoundedData (desc.quads)
+ meshDesc.quads.data = indices.begin();
+ meshDesc.quads.count = static_cast<PxU32>(numQuads);
+ meshDesc.quads.stride = sizeof(PxU32) * 4; // <- stride per quad
+
+ return meshDesc;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// merge two meshes into a single mesh, works only for 4 stride vertex data
+PxClothMeshDesc Test::ClothHelpers::mergeMeshDesc(PxClothMeshDesc &desc1, PxClothMeshDesc &desc2,
+ SampleArray<PxVec4>& vertices, SampleArray<PxU32>& indices,
+ SampleArray<PxVec2>& texcoords1, SampleArray<PxVec2>& texcoords2, SampleArray<PxVec2>& texcoords)
+{
+ PxClothMeshDesc meshDesc;
+
+ PxU32 numVertices = desc1.points.count + desc2.points.count;
+ vertices.resize(numVertices);
+ memcpy(vertices.begin(), desc1.points.data, sizeof(PxVec4) * desc1.points.count);
+ memcpy(vertices.begin()+desc1.points.count, desc2.points.data, sizeof(PxVec4) * desc2.points.count);
+
+ indices.resize(desc1.quads.count * 4 + desc2.quads.count * 4 + desc1.triangles.count * 3 + desc2.triangles.count * 3);
+
+ PxU32* indexBase = indices.begin();
+ memcpy(indexBase, desc1.quads.data, sizeof(PxU32) * desc1.quads.count * 4);
+ indexBase += desc1.quads.count * 4;
+
+ memcpy(indexBase, desc2.quads.data, sizeof(PxU32) * desc2.quads.count * 4);
+ for (PxU32 i = 0; i < desc2.quads.count * 4; i++)
+ indexBase[i] += desc1.points.count;
+ indexBase += desc2.quads.count * 4;
+
+ memcpy(indexBase, desc1.triangles.data, sizeof(PxU32) * desc1.triangles.count * 3);
+ indexBase += desc1.triangles.count * 3;
+
+ memcpy(indexBase, desc2.triangles.data, sizeof(PxU32) * desc2.triangles.count * 3);
+ for (PxU32 i = 0; i < desc2.triangles.count * 3; i++)
+ indexBase[i] += desc1.points.count;
+
+ texcoords.resize(desc1.points.count + desc2.points.count);
+ memcpy(texcoords.begin(), texcoords1.begin(), sizeof(PxVec2) * desc1.points.count);
+ memcpy(texcoords.begin()+desc1.points.count, texcoords2.begin(), sizeof(PxVec2) * desc2.points.count);
+
+ meshDesc.points.count = numVertices;
+ meshDesc.points.data = vertices.begin();
+ meshDesc.points.stride = sizeof(PxVec4);
+
+ meshDesc.invMasses.data = &vertices.begin()->w;
+ meshDesc.invMasses.count = static_cast<PxU32>(numVertices);
+ meshDesc.invMasses.stride = sizeof(PxVec4);
+
+ // convert index array to PxBoundedData (desc.quads)
+ PxU32 numQuads = desc1.quads.count + desc2.quads.count;
+ meshDesc.quads.data = indices.begin();
+ meshDesc.quads.count = static_cast<PxU32>(numQuads);
+ meshDesc.quads.stride = sizeof(PxU32) * 4; // <- stride per quad
+
+ PxU32 numTriangles = desc1.triangles.count + desc2.triangles.count;
+ meshDesc.triangles.data = indices.begin() + numQuads;
+ meshDesc.triangles.count = static_cast<PxU32>(numTriangles);
+ meshDesc.triangles.stride = sizeof(PxU32) * 3; // <- stride per triangle
+
+ return meshDesc;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// remove duplicate vertices
+PxClothMeshDesc Test::ClothHelpers::removeDuplicateVertices(PxClothMeshDesc &inMesh, SampleArray<PxVec2> &inTexcoords,
+ SampleArray<PxVec4>& vertices, SampleArray<PxU32>& indices, SampleArray<PxVec2>& texcoords)
+{
+ PxU32 numVertices = inMesh.points.count;
+ SampleArray<PxU32> inputToOutput, outputToInput;
+
+ inputToOutput.resize(inMesh.points.count, PxU32(-1));
+ outputToInput.reserve(inMesh.points.count);
+
+ const float eps = 0.00001f;
+ const PxVec4* ptr = static_cast<const PxVec4*>(inMesh.points.data);
+ for (PxU32 i = 0; i < numVertices; ++i)
+ {
+ if (inputToOutput[i] != PxU32(-1))
+ continue; // already visited
+
+ inputToOutput[i] = outputToInput.size();
+ outputToInput.pushBack(i);
+
+ for (PxU32 j = i+1; j < numVertices; ++j)
+ {
+ const PxVec3& p0 = (const PxVec3&)ptr[i];
+ const PxVec3& p1 = (const PxVec3&)ptr[j];
+
+ float diff = (p0-p1).magnitudeSquared();
+ if (diff < eps)
+ {
+ inputToOutput[j] = inputToOutput[i];
+ }
+ }
+ }
+
+ // copy vertex data
+ vertices.resize(outputToInput.size());
+ for (PxU32 i = 0; i < outputToInput.size(); ++i)
+ {
+ PxU32 oi = outputToInput[i];
+ vertices[i] = ptr[oi];
+ }
+
+ // handle indices
+ indices.resize(inMesh.quads.count*4 + inMesh.triangles.count*3);
+
+ PxU32* indexBase = indices.begin();
+ memcpy(indexBase, inMesh.quads.data, sizeof(PxU32) * inMesh.quads.count * 4);
+ indexBase += inMesh.quads.count * 4;
+ memcpy(indexBase, inMesh.triangles.data, sizeof(PxU32) * inMesh.triangles.count * 3);
+
+ for (PxU32 i = 0; i < indices.size(); i++)
+ indices[i] = inputToOutput[indices[i]];
+
+ // fill the mesh descriptor
+ numVertices = vertices.size();
+ PxClothMeshDesc meshDesc;
+ meshDesc.points.data = vertices.begin();
+ meshDesc.points.count = numVertices;
+ meshDesc.points.stride = sizeof(PxVec4);
+
+ meshDesc.invMasses.data = &vertices.begin()->w;
+ meshDesc.invMasses.count = static_cast<PxU32>(numVertices);
+ meshDesc.invMasses.stride = sizeof(PxVec4);
+
+ PxU32 numQuads = inMesh.quads.count;
+ meshDesc.quads.data = indices.begin();
+ meshDesc.quads.count = static_cast<PxU32>(numQuads);
+ meshDesc.quads.stride = sizeof(PxU32) * 4; // <- stride per quad
+
+ PxU32 numTriangles = inMesh.triangles.count;
+ meshDesc.triangles.data = indices.begin() + numQuads;
+ meshDesc.triangles.count = static_cast<PxU32>(numTriangles);
+ meshDesc.triangles.stride = sizeof(PxU32) * 3; // <- stride per triangle
+
+ return meshDesc;
+}
+
+#include "wavefront.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// create cloth mesh from obj file (user must provide vertex, primitive, and optionally texture coord buffer)
+PxClothMeshDesc Test::ClothHelpers::createMeshFromObj(const char* filename, PxReal scale, PxQuat rot, PxVec3 offset,
+ SampleArray<PxVec4>& vertices, SampleArray<PxU32>& indices, SampleArray<PxVec2>& texcoords)
+{
+ WavefrontObj wo;
+ wo.loadObj(filename, true);
+
+ int numVertices = wo.mVertexCount;
+ int numTriangles = wo.mTriCount;
+
+ vertices.resize(numVertices);
+ indices.resize(numTriangles*3);
+ texcoords.resize(numVertices);
+
+ PxVec3 *vSrc = (PxVec3*)wo.mVertices;
+ PxVec4 *vDest = (PxVec4*)vertices.begin();
+ for (int i = 0; i < numVertices; i++, vDest++, vSrc++)
+ *vDest = PxVec4(scale * rot.rotate(*vSrc) + offset, 1.0f);
+
+ memcpy((PxU32*)indices.begin(),
+ wo.mIndices, sizeof(PxU32)*numTriangles*3);
+
+ texcoords.resize(numVertices);
+ memcpy(&texcoords.begin()->x,
+ wo.mTexCoords, sizeof(PxVec2) * numVertices);
+
+ PxClothMeshDesc meshDesc;
+
+ // convert vertex array to PxBoundedData (desc.points)
+ meshDesc.points.data = vertices.begin();
+ meshDesc.points.count = static_cast<PxU32>(numVertices);
+ meshDesc.points.stride = sizeof(PxVec4);
+
+ meshDesc.invMasses.data = &vertices.begin()->w;
+ meshDesc.invMasses.count = static_cast<PxU32>(numVertices);
+ meshDesc.invMasses.stride = sizeof(PxVec4);
+
+ // convert face index array to PxBoundedData (desc.triangles)
+ meshDesc.triangles.data = indices.begin();
+ meshDesc.triangles.count = static_cast<PxU32>(numTriangles);
+ meshDesc.triangles.stride = sizeof(PxU32) * 3; // <- stride per triangle
+
+ return meshDesc;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool Test::ClothHelpers::setMotionConstraints(PxCloth &cloth, PxReal radius)
+{
+ PxU32 numParticles = cloth.getNbParticles();
+
+ PxClothParticleData* readData = cloth.lockParticleData();
+ if (!readData)
+ return false;
+
+ const PxClothParticle* particles = readData->particles;
+
+ SampleArray<PxClothParticleMotionConstraint> constraints(numParticles);
+
+ for (PxU32 i = 0; i < numParticles; i++) {
+ constraints[i].pos = particles[i].pos;
+ constraints[i].radius = radius;
+ }
+
+ readData->unlock();
+
+ cloth.setMotionConstraints(constraints.begin());
+
+ return true;
+}
+
+bool Test::ClothHelpers::setStiffness(PxCloth& cloth, PxReal newStiffness)
+{
+ PxClothStretchConfig stretchConfig;
+ stretchConfig = cloth.getStretchConfig(PxClothFabricPhaseType::eVERTICAL);
+ stretchConfig.stiffness = newStiffness;
+ cloth.setStretchConfig(PxClothFabricPhaseType::eVERTICAL, stretchConfig);
+
+ stretchConfig = cloth.getStretchConfig(PxClothFabricPhaseType::eHORIZONTAL);
+ stretchConfig.stiffness = newStiffness;
+ cloth.setStretchConfig(PxClothFabricPhaseType::eHORIZONTAL, stretchConfig);
+
+ PxClothStretchConfig shearingConfig = cloth.getStretchConfig(PxClothFabricPhaseType::eSHEARING);
+ shearingConfig.stiffness = newStiffness;
+ cloth.setStretchConfig(PxClothFabricPhaseType::eSHEARING, shearingConfig);
+
+ PxClothStretchConfig bendingConfig = cloth.getStretchConfig(PxClothFabricPhaseType::eBENDING);
+ bendingConfig.stiffness = newStiffness;
+ cloth.setStretchConfig(PxClothFabricPhaseType::eBENDING, bendingConfig);
+
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+namespace
+{
+ static PxVec3 gVirtualParticleWeights[] =
+ {
+ // center point
+ PxVec3(1.0f / 3, 1.0f / 3, 1.0f / 3),
+
+ // off-center point
+ PxVec3(4.0f / 6, 1.0f / 6, 1.0f / 6),
+
+ // edge point
+ PxVec3(1.0f / 2, 1.0f / 2, 0.0f),
+ };
+
+ shdfnd::Pair<PxU32, PxU32> makeEdge(PxU32 v0, PxU32 v1)
+ {
+ if(v0 < v1)
+ return shdfnd::Pair<PxU32, PxU32>(v0, v1);
+ else
+ return shdfnd::Pair<PxU32, PxU32>(v1, v0);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool Test::ClothHelpers::createVirtualParticles(PxCloth& cloth, PxClothMeshDesc& meshDesc, int level)
+{
+ if(level < 1 || level > 5)
+ return false;
+
+ PxU32 edgeSampleCount[] = { 0, 0, 1, 1, 0, 1 };
+ PxU32 triSampleCount[] = { 0, 1, 0, 1, 3, 3 };
+ PxU32 quadSampleCount[] = { 0, 1, 0, 1, 4, 4 };
+
+ PxU32 numEdgeSamples = edgeSampleCount[level];
+ PxU32 numTriSamples = triSampleCount[level];
+ PxU32 numQuadSamples = quadSampleCount[level];
+
+ PxU32 numTriangles = meshDesc.triangles.count;
+ PxU8* triangles = (PxU8*)meshDesc.triangles.data;
+
+ PxU32 numQuads = meshDesc.quads.count;
+ PxU8* quads = (PxU8*)meshDesc.quads.data;
+
+ SampleArray<PxU32> indices;
+ indices.reserve(numTriangles * (numTriSamples + 3*numEdgeSamples)
+ + numQuads * (numQuadSamples + 4*numEdgeSamples));
+
+ typedef shdfnd::Pair<PxU32, PxU32> Edge;
+ shdfnd::HashSet<Edge> edges;
+
+ for (PxU32 i = 0; i < numTriangles; i++)
+ {
+ PxU32 v0, v1, v2;
+
+ if (meshDesc.flags & PxMeshFlag::e16_BIT_INDICES)
+ {
+ PxU16* triangle = (PxU16*)triangles;
+ v0 = triangle[0];
+ v1 = triangle[1];
+ v2 = triangle[2];
+ }
+ else
+ {
+ PxU32* triangle = (PxU32*)triangles;
+ v0 = triangle[0];
+ v1 = triangle[1];
+ v2 = triangle[2];
+ }
+
+ if(numTriSamples == 1)
+ {
+ indices.pushBack(v0);
+ indices.pushBack(v1);
+ indices.pushBack(v2);
+ indices.pushBack(0);
+ }
+
+ if(numTriSamples == 3)
+ {
+ indices.pushBack(v0);
+ indices.pushBack(v1);
+ indices.pushBack(v2);
+ indices.pushBack(1);
+
+ indices.pushBack(v1);
+ indices.pushBack(v2);
+ indices.pushBack(v0);
+ indices.pushBack(1);
+
+ indices.pushBack(v2);
+ indices.pushBack(v0);
+ indices.pushBack(v1);
+ indices.pushBack(1);
+ }
+
+ if(numEdgeSamples == 1)
+ {
+ if(edges.insert(makeEdge(v0, v1)))
+ {
+ indices.pushBack(v0);
+ indices.pushBack(v1);
+ indices.pushBack(v2);
+ indices.pushBack(2);
+ }
+
+ if(edges.insert(makeEdge(v1, v2)))
+ {
+ indices.pushBack(v1);
+ indices.pushBack(v2);
+ indices.pushBack(v0);
+ indices.pushBack(2);
+ }
+
+ if(edges.insert(makeEdge(v2, v0)))
+ {
+ indices.pushBack(v2);
+ indices.pushBack(v0);
+ indices.pushBack(v1);
+ indices.pushBack(2);
+ }
+ }
+
+ triangles += meshDesc.triangles.stride;
+ }
+
+ for (PxU32 i = 0; i < numQuads; i++)
+ {
+ PxU32 v0, v1, v2, v3;
+
+ if (meshDesc.flags & PxMeshFlag::e16_BIT_INDICES)
+ {
+ PxU16* quad = (PxU16*)quads;
+ v0 = quad[0];
+ v1 = quad[1];
+ v2 = quad[2];
+ v3 = quad[3];
+ }
+ else
+ {
+ PxU32* quad = (PxU32*)quads;
+ v0 = quad[0];
+ v1 = quad[1];
+ v2 = quad[2];
+ v3 = quad[3];
+ }
+
+ if(numQuadSamples == 1)
+ {
+ indices.pushBack(v0);
+ indices.pushBack(v2);
+ indices.pushBack(v3);
+ indices.pushBack(2);
+ }
+
+ if(numQuadSamples == 4)
+ {
+ indices.pushBack(v0);
+ indices.pushBack(v1);
+ indices.pushBack(v2);
+ indices.pushBack(1);
+
+ indices.pushBack(v1);
+ indices.pushBack(v2);
+ indices.pushBack(v3);
+ indices.pushBack(1);
+
+ indices.pushBack(v2);
+ indices.pushBack(v3);
+ indices.pushBack(v0);
+ indices.pushBack(1);
+
+ indices.pushBack(v3);
+ indices.pushBack(v0);
+ indices.pushBack(v1);
+ indices.pushBack(1);
+ }
+
+ if(numEdgeSamples == 1)
+ {
+ if(edges.insert(makeEdge(v0, v1)))
+ {
+ indices.pushBack(v0);
+ indices.pushBack(v1);
+ indices.pushBack(v2);
+ indices.pushBack(2);
+ }
+
+ if(edges.insert(makeEdge(v1, v2)))
+ {
+ indices.pushBack(v1);
+ indices.pushBack(v2);
+ indices.pushBack(v3);
+ indices.pushBack(2);
+ }
+
+ if(edges.insert(makeEdge(v2, v3)))
+ {
+ indices.pushBack(v2);
+ indices.pushBack(v3);
+ indices.pushBack(v0);
+ indices.pushBack(2);
+ }
+
+ if(edges.insert(makeEdge(v3, v0)))
+ {
+ indices.pushBack(v3);
+ indices.pushBack(v0);
+ indices.pushBack(v1);
+ indices.pushBack(2);
+ }
+ }
+
+ quads += meshDesc.quads.stride;
+ }
+
+ cloth.setVirtualParticles(indices.size()/4,
+ indices.begin(), 3, gVirtualParticleWeights);
+
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+PxBounds3 Test::ClothHelpers::getAllWorldBounds(PxCloth& cloth)
+{
+ PxBounds3 totalBounds = cloth.getWorldBounds();
+
+ PxU32 numSpheres = cloth.getNbCollisionSpheres();
+
+ SampleArray<PxClothCollisionSphere> spheres(numSpheres);
+ /*
+ SampleArray<PxU32> pairs(numCapsules*2);
+ SampleArray<PxClothCollisionPlane> planes(numPlanes);
+ SampleArray<PxU32> convexMasks(numConvexes);
+ SampleArray<PxClothCollisionTriangle> triangles(numTriangles);
+ */
+
+ cloth.getCollisionData(spheres.begin(), 0, 0, 0, 0
+ /*pairs.begin(), planes.begin(), convexMasks.begin(), triangles.begin()*/);
+
+ PxTransform clothPose = cloth.getGlobalPose();
+
+ for (PxU32 i = 0; i < numSpheres; i++)
+ {
+ PxVec3 p = clothPose.transform(spheres[i].pos);
+ PxBounds3 bounds = PxBounds3::centerExtents(p, PxVec3(spheres[i].radius));
+ totalBounds.minimum = totalBounds.minimum.minimum(bounds.minimum);
+ totalBounds.maximum = totalBounds.maximum.maximum(bounds.maximum);
+ }
+
+ return totalBounds;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool Test::ClothHelpers::getParticlePositions(PxCloth &cloth, SampleArray<PxVec3> &positions)
+{
+ PxClothParticleData* readData = cloth.lockParticleData();
+ if (!readData)
+ return false;
+
+ const PxClothParticle* particles = readData->particles;
+ if (!particles)
+ return false;
+
+ PxU32 nbParticles = cloth.getNbParticles();
+ positions.resize(nbParticles);
+ for (PxU32 i = 0; i < nbParticles; i++)
+ positions[i] = particles[i].pos;
+
+ readData->unlock();
+
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool Test::ClothHelpers::setParticlePositions(PxCloth &cloth, const SampleArray<PxVec3> &positions, bool useConstrainedOnly, bool useCurrentOnly)
+{
+ PxU32 nbParticles = cloth.getNbParticles();
+ if (nbParticles != positions.size())
+ return false;
+
+ PxClothParticleData* particleData = cloth.lockParticleData(PxDataAccessFlag::eWRITABLE);
+ if (!particleData)
+ return false;
+
+ PxClothParticle* particles = particleData->particles;
+ for (PxU32 i = 0; i < nbParticles; i++)
+ {
+ bool constrained = particles[i].invWeight == 0.0f;
+ if (!useConstrainedOnly || constrained)
+ particles[i].pos = positions[i];
+ }
+
+ if(!useCurrentOnly)
+ particleData->previousParticles = particleData->particles;
+
+ particleData->unlock();
+
+ return true;
+}
+
+#endif // PX_USE_CLOTH_API
diff --git a/PhysX_3.4/Samples/SampleBase/TestClothHelpers.h b/PhysX_3.4/Samples/SampleBase/TestClothHelpers.h
new file mode 100644
index 00000000..a583bdb5
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/TestClothHelpers.h
@@ -0,0 +1,115 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef TEST_CLOTH_HELPERS_H
+#define TEST_CLOTH_HELPERS_H
+
+#include "PxShape.h"
+#include "PsArray.h"
+#include "cloth/PxCloth.h"
+#include "cloth/PxClothTypes.h"
+#include "cloth/PxClothCollisionData.h"
+#include "extensions/PxClothMeshDesc.h"
+#include "cooking/PxCooking.h"
+#include "foundation/PxVec2.h"
+#include "foundation/PxVec4.h"
+#include "Test.h"
+
+
+template<typename T> class SampleArray;
+
+namespace Test
+{
+ /// simple utility functions for PxCloth
+ class ClothHelpers
+ {
+ public:
+
+ // border flags
+ enum BorderFlags
+ {
+ NONE = 0,
+ BORDER_LEFT = (1 << 0),
+ BORDER_RIGHT = (1 << 1),
+ BORDER_BOTTOM = (1 << 2),
+ BORDER_TOP = (1 << 3),
+ BORDER_NEAR = (1 << 4),
+ BORDER_FAR = (1 << 5)
+ };
+ typedef PxFlags<BorderFlags, PxU16> PxBorderFlags;
+ // attach cloth border
+ static bool attachBorder(PxClothParticle* particles, PxU32 numParticles, PxBorderFlags borderFlag);
+ static bool attachBorder(PxCloth& cloth, PxBorderFlags borderFlag);
+
+ // constrain cloth particles that overlap the given shape
+ static bool attachClothOverlapToShape(PxCloth& cloth, PxShape& shape, PxReal radius = 0.1f);
+
+ // create cloth mesh descriptor for a grid mesh defined along two (u,v) axis.
+ static PxClothMeshDesc createMeshGrid(PxVec3 dirU, PxVec3 dirV, PxU32 numU, PxU32 numV,
+ SampleArray<PxVec4>& vertices, SampleArray<PxU32>& indices, SampleArray<PxVec2>& texcoords);
+
+ // create cloth mesh from obj file
+ static PxClothMeshDesc createMeshFromObj(const char* filename, PxReal scale, PxQuat rot, PxVec3 offset,
+ SampleArray<PxVec4>& vertices, SampleArray<PxU32>& indices, SampleArray<PxVec2>& texcoords);
+
+ // create capsule data in local space of pose
+ static bool createCollisionCapsule(const PxTransform &pose, const PxVec3 &center0, PxReal r0, const PxVec3 &center1, PxReal r1,
+ SampleArray<PxClothCollisionSphere> &spheres, SampleArray<PxU32> &indexPairs);
+
+ // create virtual particle samples
+ static bool createVirtualParticles(PxCloth& cloth, PxClothMeshDesc& meshDesc, int numSamples);
+
+ // get world bounds containing all the colliders and the cloth
+ static PxBounds3 getAllWorldBounds(PxCloth& cloth);
+
+ // get particle location from the cloth
+ static bool getParticlePositions(PxCloth&cloth, SampleArray<PxVec3> &positions);
+
+ // remove duplicate vertices
+ static PxClothMeshDesc removeDuplicateVertices(PxClothMeshDesc &inMesh, SampleArray<PxVec2> &inTexcoords,
+ SampleArray<PxVec4>& vertices, SampleArray<PxU32>& indices, SampleArray<PxVec2>& texcoords);
+
+ // merge two mesh descriptor and uvs into a single one
+ static PxClothMeshDesc mergeMeshDesc(PxClothMeshDesc &desc1, PxClothMeshDesc &desc2,
+ SampleArray<PxVec4>& vertices, SampleArray<PxU32>& indices,
+ SampleArray<PxVec2>& texcoords1, SampleArray<PxVec2>& texcoords2, SampleArray<PxVec2>& texcoords);
+
+ // set motion constraint radius
+ static bool setMotionConstraints(PxCloth &cloth, PxReal radius);
+
+ // set particle location from the cloth
+ static bool setParticlePositions(PxCloth&cloth, const SampleArray<PxVec3> &positions, bool useConstrainedOnly = true, bool useCurrentOnly = true);
+
+ // set stiffness for all the phases
+ static bool setStiffness(PxCloth& cloth, PxReal stiffness);
+ };
+}
+
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/TestClothReadDataLock.h b/PhysX_3.4/Samples/SampleBase/TestClothReadDataLock.h
new file mode 100644
index 00000000..db583950
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/TestClothReadDataLock.h
@@ -0,0 +1,51 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef TEST_CLOTH_READ_DATA_LOCK
+#define TEST_CLOTH_READ_DATA_LOCK
+
+#include "foundation/PxStrideIterator.h"
+
+#include "cloth/PxCloth.h"
+#include "cloth/PxClothReadData.h"
+
+namespace Test
+{
+ class ClothReadDataLock
+ {
+ public:
+ ClothReadDataLock(PxCloth& cloth) { mReadData = cloth.lockClothReadData(); }
+ ~ClothReadDataLock() { mReadData->unlock(); }
+ PxClothReadData* get() { return mReadData; }
+ private:
+ PxClothReadData* mReadData;
+ };
+};
+
+#endif // TEST_CLOTH_READ_DATA_LOCK
diff --git a/PhysX_3.4/Samples/SampleBase/TestGeometryHelpers.cpp b/PhysX_3.4/Samples/SampleBase/TestGeometryHelpers.cpp
new file mode 100644
index 00000000..e156108d
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/TestGeometryHelpers.cpp
@@ -0,0 +1,43 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "TestGeometryHelpers.h"
+
+#include "geometry/PxBoxGeometry.h"
+#include "geometry/PxSphereGeometry.h"
+#include "geometry/PxCapsuleGeometry.h"
+#include "geometry/PxPlaneGeometry.h"
+#include "geometry/PxConvexMeshGeometry.h"
+#include "geometry/PxTriangleMeshGeometry.h"
+#include "geometry/PxHeightFieldGeometry.h"
+
+bool Test::GeometryHelpers::testForOverlap(const PxShape& s0, const PxGeometry& g1, const PxTransform& globalPose1)
+{
+ return PxGeometryQuery::overlap(g1, globalPose1, s0.getGeometry().any(), PxShapeExt::getGlobalPose(s0, *s0.getActor()));
+}
diff --git a/PhysX_3.4/Samples/SampleBase/TestGeometryHelpers.h b/PhysX_3.4/Samples/SampleBase/TestGeometryHelpers.h
new file mode 100644
index 00000000..f772464a
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/TestGeometryHelpers.h
@@ -0,0 +1,49 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef TEST_GEOMETRY_HELPERS_H
+#define TEST_GEOMETRY_HELPERS_H
+
+#include "PxShape.h"
+#include "extensions/PxShapeExt.h"
+#include "geometry/PxGeometryQuery.h"
+#include "Test.h"
+
+namespace Test
+{
+ class GeometryHelpers
+ {
+ public:
+ static bool testForOverlap(const PxShape& s0, const PxShape& s1);
+ static bool testForOverlap(const PxShape& s0, const PxGeometry& g1, const PxTransform& globalPose1);
+ };
+}
+
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleBase/TestGroup.cpp b/PhysX_3.4/Samples/SampleBase/TestGroup.cpp
new file mode 100644
index 00000000..4c233904
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/TestGroup.cpp
@@ -0,0 +1,315 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+
+#include "TestGroup.h"
+
+#include <stdio.h>
+#include <string.h>
+
+Test::TestGroup::TestGroup(const char* name, size_t count)
+ : mTest(NULL)
+ , mParent(NULL)
+{
+ if (MAX_COUNT == count)
+ count = strlen(name);
+ mName = new char[count + 1];
+ strncpy(mName, name, count);
+ mName[count] = '\0';
+}
+
+Test::TestGroup::TestGroup(TestGroup* group)
+ : mTest(group->mTest)
+ , mParent(NULL)
+{
+ mName = new char[strlen(group->getName()) + 1];
+ strcpy(mName, group->getName());
+}
+
+Test::TestGroup::TestGroup(SampleCreator test, const char* name, size_t count)
+ : mTest(test)
+ , mParent(NULL)
+{
+ PX_ASSERT(test);
+
+ if (MAX_COUNT == count)
+ count = strlen(name);
+ mName = new char[count + 1];
+ strncpy(mName, name, count);
+ mName[count] = '\0';
+}
+
+Test::TestGroup::~TestGroup()
+{
+ if (!isTest())
+ {
+ for (PxU32 i = 0; i < mChildren.size(); i++)
+ delete mChildren[i];
+
+ delete[] mName;
+ }
+}
+
+void Test::TestGroup::getPath(SampleArray<TestGroup*>& path)
+{
+ if (getParent())
+ getParent()->getPath(path);
+
+ path.pushBack(this);
+}
+
+void Test::TestGroup::getPathName(char* strBuffer, unsigned strBufferMaxLength, bool omitRoot)
+{
+ SampleArray<TestGroup*> path;
+ getPath(path);
+
+ unsigned charCount = 1; //\0
+ for (unsigned i = omitRoot ? 1 : 0; i < path.size(); ++i)
+ {
+ const TestGroup& node = *path[i];
+
+ unsigned nodeNameLength = unsigned(strlen(node.getName()));
+ if (node.getFirstChild())
+ nodeNameLength += 1;
+
+ if (charCount + nodeNameLength < strBufferMaxLength)
+ {
+ sprintf(strBuffer + (charCount - 1), "%s%s", node.getName(), node.getFirstChild() ? "/" : "");
+ charCount += nodeNameLength;
+ }
+ }
+}
+
+Test::TestGroup* Test::TestGroup::getGroupFromPathName(const char* pathName, bool omitRoot)
+{
+ if (!omitRoot || getParent())
+ {
+ if (strstr(pathName, getName()) != pathName)
+ return NULL;
+
+ pathName += strlen(getName());
+
+ if (getFirstChild())
+ {
+ if (strstr(pathName, "/") != pathName)
+ return NULL;
+
+ pathName += strlen("/");
+ }
+ else
+ {
+ if (pathName[0] == '\0')
+ return this;
+ else
+ return NULL;
+ }
+ }
+
+ for (unsigned i = 0; i < mChildren.size(); ++i)
+ {
+ TestGroup* group = mChildren[i]->getGroupFromPathName(pathName, omitRoot);
+ if (group)
+ return group;
+ }
+ return NULL;
+}
+
+void Test::TestGroup::addTest(SampleCreator test, const char* name, size_t count)
+{
+ PX_ASSERT(!isTest() && test);
+ TestGroup* testGroup = new TestGroup(test, name, count);
+ addGroup(testGroup);
+}
+
+void Test::TestGroup::addGroup(TestGroup* group)
+{
+ PX_ASSERT(group && !group->getParent());
+ mChildren.pushBack(group);
+ group->mParent = this;
+}
+
+Test::TestGroup* Test::TestGroup::deepCopy()
+{
+ TestGroup* groupCopy = new TestGroup(this);
+
+ for (unsigned i = 0; i < mChildren.size(); i++)
+ {
+ TestGroup* childCopy = mChildren[i]->deepCopy();
+ groupCopy->addGroup(childCopy);
+ }
+
+ return groupCopy;
+}
+
+Test::TestGroup* Test::TestGroup::addPath(SampleArray<TestGroup*>& path)
+{
+ if (path.size() == 0)
+ return NULL;
+
+ TestGroup* current = this;
+ for (unsigned i = 0; i < path.size(); i++)
+ {
+ TestGroup* pathGroup = path[i];
+ TestGroup* child = current->getChildByName(pathGroup->getName());
+ if (!child)
+ {
+ child = new TestGroup(pathGroup);
+ current->addGroup(child);
+ }
+ current = child;
+ }
+
+ return current;
+}
+
+Test::TestGroup* Test::TestGroup::getNextChild(TestGroup& current)
+{
+ int nextIndex = getChildIndex(current) + 1;
+ if (nextIndex >= int(mChildren.size()))
+ return NULL;
+
+ return mChildren[nextIndex];
+}
+
+Test::TestGroup* Test::TestGroup::getPreviousChild(TestGroup& current)
+{
+ int prevIndex = getChildIndex(current) - 1;
+ if (prevIndex < 0)
+ return NULL;
+
+ return mChildren[prevIndex];
+}
+
+Test::TestGroup* Test::TestGroup::getChildByName(const char* name, size_t count)
+{
+ if (MAX_COUNT == count)
+ count = strlen(name) + 1;
+ for (unsigned i = 0; i < mChildren.size(); i++)
+ {
+ if (strncmp(mChildren[i]->getName(), name, count) == 0)
+ return mChildren[i];
+ }
+ return NULL;
+}
+
+Test::TestGroup* Test::TestGroup::getFirstTest()
+{
+ TestGroup* current = getFirstLeaf();
+ if (!current || current->isTest())
+ return current;
+
+ return getNextTest(current);
+}
+
+Test::TestGroup* Test::TestGroup::getLastTest()
+{
+ TestGroup* current = getLastLeaf();
+ if (!current || current->isTest())
+ return current;
+
+ return getPreviousTest(current);
+}
+
+Test::TestGroup* Test::TestGroup::getNextTest(TestGroup* current)
+{
+ current = getNextLeaf(current);
+ while (current && !current->isTest())
+ current = getNextLeaf(current);
+
+ return current;
+}
+
+Test::TestGroup* Test::TestGroup::getPreviousTest(TestGroup* current)
+{
+ current = getPreviousLeaf(current);
+ while (current && !current->isTest())
+ current = getPreviousLeaf(current);
+
+ return current;
+}
+
+unsigned Test::TestGroup::getChildIndex(TestGroup& child)
+{
+ PX_ASSERT(!isTest());
+ TestGroup** p = mChildren.find(&child);
+ PX_ASSERT(p != mChildren.end());
+ return unsigned(p - mChildren.begin());
+}
+
+Test::TestGroup* Test::TestGroup::getFirstLeaf()
+{
+ TestGroup* firstChild = getFirstChild();
+ if (!firstChild)
+ return this;
+
+ return firstChild->getFirstLeaf();
+}
+
+Test::TestGroup* Test::TestGroup::getLastLeaf()
+{
+ TestGroup* lastChild = getLastChild();
+ if (!lastChild)
+ return this;
+
+ return lastChild->getLastLeaf();
+}
+
+Test::TestGroup* Test::TestGroup::getNextLeaf(TestGroup* current)
+{
+ PX_ASSERT(current);
+
+ if (current == this)
+ return NULL;
+
+ TestGroup* parent = current->getParent();
+ if (!parent)
+ return NULL;
+
+ TestGroup* nextSibling = parent->getNextChild(*current);
+ if (nextSibling)
+ return nextSibling->getFirstLeaf();
+ else
+ return getNextLeaf(parent);
+}
+
+Test::TestGroup* Test::TestGroup::getPreviousLeaf(TestGroup* current)
+{
+ PX_ASSERT(current);
+
+ if (current == this)
+ return NULL;
+
+ TestGroup* parent = current->getParent();
+ if (!parent)
+ return NULL;
+
+ TestGroup* prevSibling = parent->getPreviousChild(*current);
+ if (prevSibling)
+ return prevSibling->getLastLeaf();
+ else
+ return getPreviousLeaf(parent);
+}
+
diff --git a/PhysX_3.4/Samples/SampleBase/TestGroup.h b/PhysX_3.4/Samples/SampleBase/TestGroup.h
new file mode 100644
index 00000000..81620179
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/TestGroup.h
@@ -0,0 +1,201 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+
+#ifndef TEST_CATEGORY
+#define TEST_CATEGORY
+
+#include "PhysXSampleApplication.h"
+#include "SampleArray.h"
+
+namespace Test
+{
+ /**
+ Group of tests. The groups can be linked to a tree.
+ If a test is added to a group, a leaf group is automatically created, that
+ contains the test.
+ */
+ class TestGroup
+ {
+ static const size_t MAX_COUNT = ~0;
+ public:
+ explicit TestGroup(const char* name, size_t count = MAX_COUNT);
+ explicit TestGroup(TestGroup* group);
+ TestGroup(SampleCreator test, const char* name, size_t count = MAX_COUNT);
+ ~TestGroup();
+
+ /**
+ Releases all tests from this node and its descendants.
+ Destructing a Test groups just releases the groups and not the tests themselves!
+ */
+// void releaseTests();
+
+ /**
+ Returns the name of the TestGroup. If the test group represents a single
+ test, the name of the test is returned instead.
+ */
+ const char* getName() const { return mName; }
+
+ /**
+ Prints all the TestGroup names to strBuffer in this format:
+ "RootName/Name1/Name2/.../ThisName"
+ With omitRoot the root TestGroup is omitted.
+ */
+ void getPathName(char* strBuffer, unsigned strBufferMaxLength, bool omitRoot);
+
+ /**
+ Adds a child TestGroup to this TestGroup. After this call the group is owned by this.
+ A TestGroup can't be added multiple times.
+ */
+ void addGroup(TestGroup* group);
+
+ /**
+ Deep copy of all the group data, except the tests themselves. The copy is returned as a root.
+ */
+ TestGroup* deepCopy();
+
+ /**
+ Adds a copy of path to this group avoiding duplicates. Returns the copy of the last element in path.
+ */
+ TestGroup* addPath(SampleArray<TestGroup*>& path);
+
+ /**
+ Fills all TestGroup instances into path starting with this->getRoot() and ending with this.
+ */
+ void getPath(SampleArray<TestGroup*>& path);
+
+ /**
+ Reads a path from pathName and returns the corresponding TestGroup.
+ The format of the path has to be the same as the one used by getPathName().
+ If the TestGroup doesn't exist, NULL is returned.
+ */
+ TestGroup* getGroupFromPathName(const char* pathName, bool omitRoot);
+
+ /**
+ Returns whether this TestGroup corresponds to a single test.
+ */
+ bool isTest() const { return mTest != NULL; }
+
+ /**
+ Automatically creates a child TestGroup representing the test passed. A TestInterface instance
+ shouldn't be added multiple times, since it is owned by this TestGroup after the call.
+ */
+ void addTest(SampleCreator test, const char* name, size_t count = MAX_COUNT);
+
+ /**
+ Returns the TestInterface for a TestGroup corresponding to a single test.
+ */
+// TestInterface& getTestInterface() { PX_ASSERT(isTest()); return *mTest; }
+ SampleCreator getCreator() { PX_ASSERT(isTest()); return mTest; }
+
+ /**
+ Returns the parent TestGroup, if this isn't a root.
+ */
+ TestGroup* getParent() const { return mParent; }
+
+ /**
+ Returns the root of this TestGroup.
+ */
+ TestGroup* getRoot() { return mParent ? mParent->getRoot() : this; }
+
+ /**
+ Returns the first direct child of this TestGroup. If this TestGroup doesn't has
+ any children, NULL is returned.
+ */
+ TestGroup* getFirstChild() const { return mChildren.empty() ? NULL : mChildren.front(); }
+
+ /**
+ Returns the last direct child of this TestGroup. If this TestGroup doesn't has
+ any children, NULL is returned.
+ */
+ TestGroup* getLastChild() const { return mChildren.empty() ? NULL : mChildren.back(); }
+
+ /**
+ Returns the next direct child of this TestGroup after current. If there is no next child, NULL is returned.
+ The TestGroup current has to be itself a direct child of this Testgroup.
+ */
+ TestGroup* getNextChild(TestGroup& current);
+
+ /**
+ Returns the previous direct child of this TestGroup after current. If there is no previous child, NULL is returned.
+ The TestGroup current has to be itself a direct child of this Testgroup.
+ */
+ TestGroup* getPreviousChild(TestGroup& current);
+
+ /**
+ Returns the child with the given name, if exists.
+ */
+ TestGroup* getChildByName(const char* name, size_t count = MAX_COUNT);
+
+ /**
+ Returns the first TestGroup representing a single test (isTest() == true) within
+ the whole test group tree rooted at this TestGroup. Returns NULL if there isn't such
+ a TestGroup.
+ */
+ TestGroup* getFirstTest();
+
+ /**
+ Returns the last TestGroup representing a single test (isTest() == true) within
+ the whole test group tree rooted at this TestGroup. Returns NULL if there isn't such
+ a TestGroup.
+ */
+ TestGroup* getLastTest();
+
+ /**
+ Returns the next TestGroup representing a single test (isTest() == true) within
+ the whole test group tree rooted at this TestGroup. The current TestGroup has to be
+ a descendant of this TestGroup.
+ */
+ TestGroup* getNextTest(TestGroup* current);
+
+ /**
+ Returns the previous TestGroup representing a single test (isTest() == true) within
+ the whole test group tree rooted at this TestGroup. The current TestGroup has to be
+ a descendant of this TestGroup.
+ */
+ TestGroup* getPreviousTest(TestGroup* current);
+
+ /**
+ Returns the number of children
+ */
+ PxU32 numChildren() const { return mChildren.size(); }
+
+ private:
+ unsigned getChildIndex(TestGroup& child);
+ TestGroup* getFirstLeaf();
+ TestGroup* getLastLeaf();
+ TestGroup* getNextLeaf(TestGroup* current);
+ TestGroup* getPreviousLeaf(TestGroup* current);
+
+ private:
+ SampleCreator mTest;
+ char* mName;
+ SampleArray<TestGroup*> mChildren;
+ TestGroup* mParent;
+ };
+};
+
+#endif // TEST_CATEGORY
diff --git a/PhysX_3.4/Samples/SampleBase/TestMotionGenerator.cpp b/PhysX_3.4/Samples/SampleBase/TestMotionGenerator.cpp
new file mode 100644
index 00000000..bc5ef9b2
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/TestMotionGenerator.cpp
@@ -0,0 +1,108 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "TestMotionGenerator.h"
+
+//----------------------------------------------------------------------------//
+MotionGenerator::MotionGenerator()
+: mLinear(0.0f),
+ mAngular(0.0f),
+ mTransform(PxTransform(PxIdentity))
+{
+}
+
+//----------------------------------------------------------------------------//
+MotionGenerator::MotionGenerator(const PxTransform &pose, const PxVec3& linear, const PxVec3& angular)
+: mLinear(linear),
+ mAngular(angular),
+ mTransform(pose)
+{
+}
+
+//----------------------------------------------------------------------------//
+PxVec3 MotionGenerator::getLinearVelocity( float time )
+{
+ float t = time - (int(time) & ~0xf);
+ const float scale = 0.25f * PxPi;
+
+ if(t > 0 && t < 2)
+ return -scale * sinf(t * 0.5f * PxPi) * mLinear;
+
+ if(t > 8 && t < 10)
+ return +scale * sinf(t * 0.5f * PxPi) * mLinear;
+
+ return PxVec3(0.0f);
+}
+
+//----------------------------------------------------------------------------//
+PxVec3 MotionGenerator::getAngularVelocity( float time )
+{
+ float t = time - (int(time) & ~0xf);
+
+ if(t > 4 && t < 6)
+ return +PxPi * mAngular;
+
+ if(t > 12 && t < 14)
+ return -PxPi * mAngular;
+
+ return PxVec3(0.0f);
+}
+
+static PxQuat computeQuatFromAngularVelocity(const PxVec3 &omega)
+{
+ PxReal angle = omega.magnitude();
+
+ if (angle < 1e-5f)
+ {
+ return PxQuat(PxIdentity);
+ } else {
+ PxReal s = sin( 0.5f * angle ) / angle;
+ PxReal x = omega[0] * s;
+ PxReal y = omega[1] * s;
+ PxReal z = omega[2] * s;
+ PxReal w = cos( 0.5f * angle );
+ return PxQuat(x,y,z,w);
+ }
+}
+//----------------------------------------------------------------------------//
+const PxTransform& MotionGenerator::update(float time, float dt)
+{
+ PxVec3 dw = dt * getAngularVelocity(time);
+ PxQuat dq = computeQuatFromAngularVelocity(dw);
+
+ mTransform.q = (dq * mTransform.q).getNormalized();
+ mTransform.p += dt * getLinearVelocity(time);
+
+ return mTransform;
+}
+
+
+
+
+
diff --git a/PhysX_3.4/Samples/SampleBase/TestMotionGenerator.h b/PhysX_3.4/Samples/SampleBase/TestMotionGenerator.h
new file mode 100644
index 00000000..d1bd7e8a
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/TestMotionGenerator.h
@@ -0,0 +1,53 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef TEST_MOTION_GENERATOR
+#define TEST_MOTION_GENERATOR
+
+#include "PxPhysicsAPI.h"
+#include "Test.h"
+
+
+struct MotionGenerator
+{
+public:
+ MotionGenerator();
+ MotionGenerator(const PxTransform &pose, const PxVec3& linear, const PxVec3& angular);
+
+public:
+ const PxTransform& update(float time, float dt);
+
+ PxVec3 getLinearVelocity(float time);
+ PxVec3 getAngularVelocity(float time);
+
+ PxVec3 mLinear, mAngular;
+ PxTransform mTransform;
+};
+
+#endif // TEST_MOTION_GENERATOR
diff --git a/PhysX_3.4/Samples/SampleBase/wavefront.cpp b/PhysX_3.4/Samples/SampleBase/wavefront.cpp
new file mode 100644
index 00000000..b6d712e6
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/wavefront.cpp
@@ -0,0 +1,946 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+
+#include "wavefront.h"
+#include "FrameworkFoundation.h"
+#include "PxTkFile.h"
+
+namespace WAVEFRONT
+{
+
+ /*******************************************************************/
+ /******************** InParser.h ********************************/
+ /*******************************************************************/
+ class InPlaceParserInterface
+ {
+ public:
+ virtual int ParseLine(int lineno,int argc,const char **argv) =0; // return TRUE to continue parsing, return FALSE to abort parsing process
+ virtual ~InPlaceParserInterface() {}
+ };
+
+ enum SeparatorType
+ {
+ ST_DATA, // is data
+ ST_HARD, // is a hard separator
+ ST_SOFT, // is a soft separator
+ ST_EOS // is a comment symbol, and everything past this character should be ignored
+ };
+
+ class InPlaceParser
+ {
+ public:
+ InPlaceParser(void)
+ {
+ Init();
+ }
+
+ InPlaceParser(char *data,int len)
+ {
+ Init();
+ SetSourceData(data,len);
+ }
+
+ InPlaceParser(const char *fname)
+ {
+ Init();
+ SetFile(fname);
+ }
+
+ ~InPlaceParser(void);
+
+ void Init(void)
+ {
+ mQuoteChar = 34;
+ mData = 0;
+ mLen = 0;
+ mMyAlloc = false;
+ for (int i=0; i<256; i++)
+ {
+ mHard[i] = ST_DATA;
+ mHardString[i*2] = i;
+ mHardString[i*2+1] = 0;
+ }
+ mHard[0] = ST_EOS;
+ mHard[32] = ST_SOFT;
+ mHard[9] = ST_SOFT;
+ mHard[13] = ST_SOFT;
+ mHard[10] = ST_SOFT;
+ }
+
+ void SetFile(const char *fname); // use this file as source data to parse.
+
+ void SetSourceData(char *data,int len)
+ {
+ mData = data;
+ mLen = len;
+ mMyAlloc = false;
+ }
+
+ int Parse(InPlaceParserInterface *callback); // returns true if entire file was parsed, false if it aborted for some reason
+
+ int ProcessLine(int lineno,char *line,InPlaceParserInterface *callback);
+
+ const char ** GetArglist(char *source,int &count); // convert source string into an arg list, this is a destructive parse.
+
+ void SetHardSeparator(char c) // add a hard separator
+ {
+ mHard[(unsigned int)c] = ST_HARD;
+ }
+
+ void SetHard(char c) // add a hard separator
+ {
+ mHard[(unsigned int)c] = ST_HARD;
+ }
+
+
+ void SetCommentSymbol(char c) // comment character, treated as 'end of string'
+ {
+ mHard[(unsigned int)c] = ST_EOS;
+ }
+
+ void ClearHardSeparator(char c)
+ {
+ mHard[(unsigned int)c] = ST_DATA;
+ }
+
+
+ void DefaultSymbols(void); // set up default symbols for hard seperator and comment symbol of the '#' character.
+
+ bool EOS(char c)
+ {
+ if ( mHard[(unsigned int)c] == ST_EOS )
+ {
+ return true;
+ }
+ return false;
+ }
+
+ void SetQuoteChar(char c)
+ {
+ mQuoteChar = c;
+ }
+
+ private:
+
+
+ inline char * AddHard(int &argc,const char **argv,char *foo);
+ inline bool IsHard(char c);
+ inline char * SkipSpaces(char *foo);
+ inline bool IsWhiteSpace(char c);
+ inline bool IsNonSeparator(char c); // non seperator,neither hard nor soft
+
+ bool mMyAlloc; // whether or not *I* allocated the buffer and am responsible for deleting it.
+ char *mData; // ascii data to parse.
+ int mLen; // length of data
+ SeparatorType mHard[256];
+ char mHardString[256*2];
+ char mQuoteChar;
+ };
+
+ /*******************************************************************/
+ /******************** InParser.cpp ********************************/
+ /*******************************************************************/
+ void InPlaceParser::SetFile(const char* fname)
+ {
+ if ( mMyAlloc )
+ free(mData);
+
+ mData = 0;
+ mLen = 0;
+ mMyAlloc = false;
+
+ SampleFramework::File* fph = NULL;
+ PxToolkit::fopen_s(&fph, fname, "rb");
+ if ( fph )
+ {
+ fseek(fph,0L,SEEK_END);
+ mLen = (int)ftell(fph);
+ fseek(fph,0L,SEEK_SET);
+ if ( mLen )
+ {
+ mData = (char *) malloc(sizeof(char)*(mLen+1));
+ int ok = int(fread(mData, 1, mLen, fph));
+ if ( !ok )
+ {
+ free(mData);
+ mData = 0;
+ }
+ else
+ {
+ mData[mLen] = 0; // zero byte terminate end of file marker.
+ mMyAlloc = true;
+ }
+ }
+ fclose(fph);
+ }
+ }
+
+ InPlaceParser::~InPlaceParser(void)
+ {
+ if ( mMyAlloc )
+ free(mData);
+ }
+
+#define MAXARGS 512
+
+ bool InPlaceParser::IsHard(char c)
+ {
+ return mHard[(unsigned int)c] == ST_HARD;
+ }
+
+ char * InPlaceParser::AddHard(int &argc,const char **argv,char *foo)
+ {
+ while ( IsHard(*foo) )
+ {
+ const char *hard = &mHardString[*foo*2];
+ if ( argc < MAXARGS )
+ {
+ argv[argc++] = hard;
+ }
+ foo++;
+ }
+ return foo;
+ }
+
+ bool InPlaceParser::IsWhiteSpace(char c)
+ {
+ return mHard[(unsigned int)c] == ST_SOFT;
+ }
+
+ char * InPlaceParser::SkipSpaces(char *foo)
+ {
+ while ( !EOS(*foo) && IsWhiteSpace(*foo) ) foo++;
+ return foo;
+ }
+
+ bool InPlaceParser::IsNonSeparator(char c)
+ {
+ if ( !IsHard(c) && !IsWhiteSpace(c) && c != 0 ) return true;
+ return false;
+ }
+
+
+ int InPlaceParser::ProcessLine(int lineno,char *line,InPlaceParserInterface *callback)
+ {
+ int ret = 0;
+
+ const char *argv[MAXARGS];
+ int argc = 0;
+
+ char *foo = line;
+
+ while ( !EOS(*foo) && argc < MAXARGS )
+ {
+
+ foo = SkipSpaces(foo); // skip any leading spaces
+
+ if ( EOS(*foo) ) break;
+
+ if ( *foo == mQuoteChar ) // if it is an open quote
+ {
+ foo++;
+ if ( argc < MAXARGS )
+ {
+ argv[argc++] = foo;
+ }
+ while ( !EOS(*foo) && *foo != mQuoteChar ) foo++;
+ if ( !EOS(*foo) )
+ {
+ *foo = 0; // replace close quote with zero byte EOS
+ foo++;
+ }
+ }
+ else
+ {
+
+ foo = AddHard(argc,argv,foo); // add any hard separators, skip any spaces
+
+ if ( IsNonSeparator(*foo) ) // add non-hard argument.
+ {
+ bool quote = false;
+ if ( *foo == mQuoteChar )
+ {
+ foo++;
+ quote = true;
+ }
+
+ if ( argc < MAXARGS )
+ {
+ argv[argc++] = foo;
+ }
+
+ if ( quote )
+ {
+ while (*foo && *foo != mQuoteChar ) foo++;
+ if ( *foo ) *foo = 32;
+ }
+
+ // continue..until we hit an eos ..
+ while ( !EOS(*foo) ) // until we hit EOS
+ {
+ if ( IsWhiteSpace(*foo) ) // if we hit a space, stomp a zero byte, and exit
+ {
+ *foo = 0;
+ foo++;
+ break;
+ }
+ else if ( IsHard(*foo) ) // if we hit a hard separator, stomp a zero byte and store the hard separator argument
+ {
+ const char *hard = &mHardString[*foo*2];
+ *foo = 0;
+ if ( argc < MAXARGS )
+ {
+ argv[argc++] = hard;
+ }
+ foo++;
+ break;
+ }
+ foo++;
+ } // end of while loop...
+ }
+ }
+ }
+
+ if ( argc )
+ {
+ ret = callback->ParseLine(lineno, argc, argv );
+ }
+
+ return ret;
+ }
+
+ int InPlaceParser::Parse(InPlaceParserInterface *callback) // returns true if entire file was parsed, false if it aborted for some reason
+ {
+ assert( callback );
+ if ( !mData ) return 0;
+
+ int ret = 0;
+
+ int lineno = 0;
+
+ char *foo = mData;
+ char *begin = foo;
+
+
+ while ( *foo )
+ {
+ if ( *foo == 10 || *foo == 13 )
+ {
+ lineno++;
+ *foo = 0;
+
+ if ( *begin ) // if there is any data to parse at all...
+ {
+ int v = ProcessLine(lineno,begin,callback);
+ if ( v ) ret = v;
+ }
+
+ foo++;
+ if ( *foo == 10 ) foo++; // skip line feed, if it is in the carraige-return line-feed format...
+ begin = foo;
+ }
+ else
+ {
+ foo++;
+ }
+ }
+
+ lineno++; // last line.
+
+ int v = ProcessLine(lineno,begin,callback);
+ if ( v ) ret = v;
+ return ret;
+ }
+
+
+ void InPlaceParser::DefaultSymbols(void)
+ {
+ SetHardSeparator(',');
+ SetHardSeparator('(');
+ SetHardSeparator(')');
+ SetHardSeparator('=');
+ SetHardSeparator('[');
+ SetHardSeparator(']');
+ SetHardSeparator('{');
+ SetHardSeparator('}');
+ SetCommentSymbol('#');
+ }
+
+
+ const char ** InPlaceParser::GetArglist(char *line,int &count) // convert source string into an arg list, this is a destructive parse.
+ {
+ const char **ret = 0;
+
+ static const char *argv[MAXARGS];
+ int argc = 0;
+
+ char *foo = line;
+
+ while ( !EOS(*foo) && argc < MAXARGS )
+ {
+
+ foo = SkipSpaces(foo); // skip any leading spaces
+
+ if ( EOS(*foo) ) break;
+
+ if ( *foo == mQuoteChar ) // if it is an open quote
+ {
+ foo++;
+ if ( argc < MAXARGS )
+ {
+ argv[argc++] = foo;
+ }
+ while ( !EOS(*foo) && *foo != mQuoteChar ) foo++;
+ if ( !EOS(*foo) )
+ {
+ *foo = 0; // replace close quote with zero byte EOS
+ foo++;
+ }
+ }
+ else
+ {
+
+ foo = AddHard(argc,argv,foo); // add any hard separators, skip any spaces
+
+ if ( IsNonSeparator(*foo) ) // add non-hard argument.
+ {
+ bool quote = false;
+ if ( *foo == mQuoteChar )
+ {
+ foo++;
+ quote = true;
+ }
+
+ if ( argc < MAXARGS )
+ {
+ argv[argc++] = foo;
+ }
+
+ if ( quote )
+ {
+ while (*foo && *foo != mQuoteChar ) foo++;
+ if ( *foo ) *foo = 32;
+ }
+
+ // continue..until we hit an eos ..
+ while ( !EOS(*foo) ) // until we hit EOS
+ {
+ if ( IsWhiteSpace(*foo) ) // if we hit a space, stomp a zero byte, and exit
+ {
+ *foo = 0;
+ foo++;
+ break;
+ }
+ else if ( IsHard(*foo) ) // if we hit a hard separator, stomp a zero byte and store the hard separator argument
+ {
+ const char *hard = &mHardString[*foo*2];
+ *foo = 0;
+ if ( argc < MAXARGS )
+ {
+ argv[argc++] = hard;
+ }
+ foo++;
+ break;
+ }
+ foo++;
+ } // end of while loop...
+ }
+ }
+ }
+
+ count = argc;
+ if ( argc )
+ {
+ ret = argv;
+ }
+
+ return ret;
+ }
+
+ /*******************************************************************/
+ /******************** Geometry.h ********************************/
+ /*******************************************************************/
+
+ class GeometryVertex
+ {
+ public:
+ float mPos[3];
+ float mNormal[3];
+ float mTexel[2];
+ };
+
+
+ class GeometryInterface
+ {
+ public:
+
+ virtual void NodeTriangle(const GeometryVertex *v1,const GeometryVertex *v2,const GeometryVertex *v3, bool textured)
+ {
+ }
+
+ virtual ~GeometryInterface() {}
+
+ };
+
+
+ /*******************************************************************/
+ /******************** Obj.h ********************************/
+ /*******************************************************************/
+
+
+ class OBJ : public InPlaceParserInterface
+ {
+ public:
+ int LoadMesh(const char *fname,GeometryInterface *callback, bool textured);
+ int ParseLine(int lineno,int argc,const char **argv); // return TRUE to continue parsing, return FALSE to abort parsing process
+
+ OBJ() : mVerts(NULL), mTexels(NULL), mNormals(NULL), mTextured(false), mCallback(NULL) { Clear(); }
+ ~OBJ() { Clear(); }
+
+ private:
+
+ void Clear();
+ void GetVertex(GeometryVertex &v,const char *face) const;
+
+ float* mVerts;
+ unsigned mNumVerts; // this is the tripled number of verts
+ unsigned mMaxVerts;
+
+ float* mTexels; // doubled number of texcoords
+ unsigned mNumTexels;
+ unsigned mMaxTexels;
+
+ float* mNormals; // tripled number of normals
+ unsigned mNumNormals;
+ unsigned mMaxNormals;
+
+ bool mTextured;
+ GeometryInterface* mCallback;
+ };
+
+
+ /*******************************************************************/
+ /******************** Obj.cpp ********************************/
+ /*******************************************************************/
+
+ int OBJ::LoadMesh(const char *fname, GeometryInterface *iface, bool textured)
+ {
+ Clear();
+
+ mTextured = textured;
+ int ret = 0;
+ mCallback = iface;
+
+ InPlaceParser ipp(fname);
+
+ ipp.Parse(this);
+
+ return ret;
+ }
+
+ void OBJ::Clear()
+ {
+ if (mVerts)
+ delete[] mVerts;
+ mMaxVerts = 0;
+ mNumVerts = 0;
+
+ if (mTexels)
+ delete[] mTexels;
+ mMaxTexels = 0;
+ mNumTexels = 0;
+
+ if (mNormals)
+ delete[] mNormals;
+ mMaxNormals = 0;
+ mNumNormals = 0;
+ }
+
+ void OBJ::GetVertex(GeometryVertex &v,const char *face) const
+ {
+ v.mPos[0] = 0;
+ v.mPos[1] = 0;
+ v.mPos[2] = 0;
+
+ v.mTexel[0] = 0;
+ v.mTexel[1] = 0;
+
+ v.mNormal[0] = 0;
+ v.mNormal[1] = 1;
+ v.mNormal[2] = 0;
+
+ int index = atoi( face )-1;
+
+ const char *texel = strstr(face,"/");
+
+ if ( texel )
+ {
+ int tindex = atoi( texel+1) - 1;
+
+ if ( tindex >=0 && tindex < (int)(mNumTexels/2) )
+ {
+ const float *t = &mTexels[tindex*2];
+
+ v.mTexel[0] = t[0];
+ v.mTexel[1] = t[1];
+
+ }
+
+ const char *normal = strstr(texel+1,"/");
+ if ( normal )
+ {
+ int nindex = atoi( normal+1 ) - 1;
+
+ if (nindex >= 0 && nindex < (int)(mNumNormals/3) )
+ {
+ const float *n = &mNormals[nindex*3];
+
+ v.mNormal[0] = n[0];
+ v.mNormal[1] = n[1];
+ v.mNormal[2] = n[2];
+ }
+ }
+ }
+
+ if ( index >= 0 && index < (int)(mNumVerts/3) )
+ {
+
+ const float *p = &mVerts[index*3];
+
+ v.mPos[0] = p[0];
+ v.mPos[1] = p[1];
+ v.mPos[2] = p[2];
+ } else
+ assert(0 == "Negative face vertex indices are not supported in wavefront loader.");
+ }
+
+ template<typename T>
+ void Resize(T*& data, unsigned& capacity, unsigned count, unsigned new_count)
+ {
+ if (new_count >= capacity)
+ {
+ capacity = new_count*2;
+ T* tmp = new T[capacity];
+ memcpy(tmp, data, count*sizeof(T));
+ delete[] data;
+ data = tmp;
+ }
+ }
+
+ int OBJ::ParseLine(int lineno,int argc,const char **argv) // return TRUE to continue parsing, return FALSE to abort parsing process
+ {
+ int ret = 0;
+
+ if ( argc >= 1 )
+ {
+ const char *foo = argv[0];
+ if ( *foo != '#' )
+ {
+ if (strcmp(argv[0], "v") == 0 && argc == 4 )
+ {
+ float vx = (float) atof( argv[1] );
+ float vy = (float) atof( argv[2] );
+ float vz = (float) atof( argv[3] );
+ Resize(mVerts, mMaxVerts, mNumVerts, mNumVerts + 3);
+ mVerts[mNumVerts++] = vx;
+ mVerts[mNumVerts++] = vy;
+ mVerts[mNumVerts++] = vz;
+ }
+ else if (strcmp(argv[0],"vt") == 0 && (argc == 3 || argc == 4))
+ {
+ // ignore 4rd component if present
+ float tx = (float) atof( argv[1] );
+ float ty = (float) atof( argv[2] );
+ Resize(mTexels, mMaxTexels, mNumTexels, mNumTexels + 2);
+ mTexels[mNumTexels++] = tx;
+ mTexels[mNumTexels++] = ty;
+ }
+ else if (strcmp(argv[0],"vn") == 0 && argc == 4 )
+ {
+ float normalx = (float) atof(argv[1]);
+ float normaly = (float) atof(argv[2]);
+ float normalz = (float) atof(argv[3]);
+ Resize(mNormals, mMaxNormals, mNumNormals, mNumNormals + 3);
+ mNormals[mNumNormals++] = normalx;
+ mNormals[mNumNormals++] = normaly;
+ mNormals[mNumNormals++] = normalz;
+
+ }
+ else if (strcmp(argv[0],"f") == 0 && argc >= 4 )
+ {
+ GeometryVertex v[32];
+
+ int vcount = argc-1;
+
+ for (int i=1; i<argc; i++)
+ {
+ GetVertex(v[i-1],argv[i] );
+ }
+
+ // need to generate a normal!
+#if 0 // not currently implemented
+ if ( mNormals.empty() )
+ {
+ Vector3d<float> p1( v[0].mPos );
+ Vector3d<float> p2( v[1].mPos );
+ Vector3d<float> p3( v[2].mPos );
+
+ Vector3d<float> n;
+ n.ComputeNormal(p3,p2,p1);
+
+ for (int i=0; i<vcount; i++)
+ {
+ v[i].mNormal[0] = n.x;
+ v[i].mNormal[1] = n.y;
+ v[i].mNormal[2] = n.z;
+ }
+
+ }
+#endif
+
+ mCallback->NodeTriangle(&v[0],&v[1],&v[2], mTextured);
+
+ if ( vcount >=3 ) // do the fan
+ {
+ for (int i=2; i<(vcount-1); i++)
+ {
+ mCallback->NodeTriangle(&v[0],&v[i],&v[i+1], mTextured);
+ }
+ }
+
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ class BuildMesh : public GeometryInterface
+ {
+ public:
+ BuildMesh() : mVertices(NULL), mTexCoords(NULL), mIndices(NULL) { Clear(); }
+ ~BuildMesh() { Clear(); }
+
+ void Clear()
+ {
+ if (mVertices)
+ delete[] mVertices;
+ mMaxVertices = 0;
+ mNumVertices = 0;
+
+ if (mTexCoords)
+ delete[] mTexCoords;
+ mMaxTexCoords = 0;
+ mNumTexCoords = 0;
+
+ if (mIndices)
+ delete[] mIndices;
+ mMaxIndices = 0;
+ mNumIndices = 0;
+ }
+
+ int GetIndex(const float *p, const float *texCoord)
+ {
+
+ int vcount = mNumVertices/3;
+
+ if(vcount>0)
+ {
+ //New MS STL library checks indices in debug build, so zero causes an assert if it is empty.
+ const float *v = &mVertices[0];
+ const float *t = texCoord != NULL ? &mTexCoords[0] : NULL;
+
+ for (int i=0; i<vcount; i++)
+ {
+ if ( v[0] == p[0] && v[1] == p[1] && v[2] == p[2] )
+ {
+ if (texCoord == NULL || (t[0] == texCoord[0] && t[1] == texCoord[1]))
+ {
+ return i;
+ }
+ }
+ v+=3;
+ if (t != NULL)
+ t += 2;
+ }
+ }
+
+ Resize(mVertices, mMaxVertices, mNumVertices, mNumVertices + 3);
+ mVertices[mNumVertices++] = p[0];
+ mVertices[mNumVertices++] = p[1];
+ mVertices[mNumVertices++] = p[2];
+
+ if (texCoord != NULL)
+ {
+ Resize(mTexCoords, mMaxTexCoords, mNumTexCoords, mNumTexCoords + 2);
+ mTexCoords[mNumTexCoords++] = texCoord[0];
+ mTexCoords[mNumTexCoords++] = texCoord[1];
+ }
+
+ return vcount;
+ }
+
+ virtual void NodeTriangle(const GeometryVertex *v1,const GeometryVertex *v2,const GeometryVertex *v3, bool textured)
+ {
+ Resize(mIndices, mMaxIndices, mNumIndices, mNumIndices + 3);
+
+ mIndices[mNumIndices++] = GetIndex(v1->mPos, textured ? v1->mTexel : NULL);
+ mIndices[mNumIndices++] = GetIndex(v2->mPos, textured ? v2->mTexel : NULL);
+ mIndices[mNumIndices++] = GetIndex(v3->mPos, textured ? v3->mTexel : NULL);
+ }
+
+
+ const float* GetVertices() const { return mVertices; }
+ unsigned GetNumVertices() const { return mNumVertices; }
+
+ const float* GetTexCoords(void) const { return mTexCoords; }
+ unsigned GetNumTexCoords(void) const { return mNumTexCoords; }
+
+ const int* GetIndices() const { return mIndices; }
+ unsigned GetNumIndices() const {return mNumIndices; }
+
+
+ private:
+ float* mVertices;
+ unsigned mMaxVertices;
+ unsigned mNumVertices;
+
+ float* mTexCoords;
+ unsigned mMaxTexCoords;
+ unsigned mNumTexCoords;
+
+ int* mIndices;
+ unsigned mMaxIndices;
+ unsigned mNumIndices;
+ };
+
+};
+
+using namespace WAVEFRONT;
+
+WavefrontObj::WavefrontObj(void)
+{
+ mVertexCount = 0;
+ mTriCount = 0;
+ mIndices = 0;
+ mVertices = NULL;
+ mTexCoords = NULL;
+}
+
+WavefrontObj::~WavefrontObj(void)
+{
+ delete []mIndices;
+ delete []mVertices;
+ if (mTexCoords)
+ delete[] mTexCoords;
+}
+
+unsigned int WavefrontObj::loadObj(const char *fname, bool textured) // load a wavefront obj returns number of triangles that were loaded. Data is persists until the class is destructed.
+{
+ unsigned int ret = 0;
+ delete []mVertices;
+ mVertices = 0;
+ delete []mIndices;
+ mIndices = 0;
+ mVertexCount = 0;
+ mTriCount = 0;
+
+ BuildMesh bm;
+ OBJ obj;
+ obj.LoadMesh(fname, &bm, textured);
+
+ if (bm.GetNumVertices())
+ {
+ mVertexCount = bm.GetNumVertices()/3;
+ mVertices = new float[mVertexCount*3];
+ memcpy(mVertices, bm.GetVertices(), sizeof(float)*mVertexCount*3);
+
+ if (textured)
+ {
+ mTexCoords = new float[mVertexCount * 2];
+ memcpy(mTexCoords, bm.GetTexCoords(), sizeof(float) * mVertexCount * 2);
+ }
+
+ mTriCount = bm.GetNumIndices()/3;
+ mIndices = new int[mTriCount*3];
+ memcpy(mIndices, bm.GetIndices(), sizeof(int)*mTriCount*3);
+ ret = mTriCount;
+ }
+
+ return ret;
+}
+
+
+
+bool LoadWavefrontBinary(const char* filename, WavefrontObj& wfo)
+{
+ SampleFramework::File* fp = NULL;
+ PxToolkit::fopen_s(&fp, filename, "rb");
+ if(!fp) return false;
+
+ size_t numRead = fread(&wfo.mVertexCount, 1, sizeof(int), fp);
+ if(numRead != sizeof(int)) { fclose(fp); return false; }
+
+ wfo.mVertices = new float[wfo.mVertexCount*3];
+ numRead = fread(wfo.mVertices, 1, sizeof(float)*wfo.mVertexCount*3, fp);
+ if(numRead != sizeof(float)*wfo.mVertexCount*3) { fclose(fp); return false; }
+
+ numRead = fread(&wfo.mTriCount, 1, sizeof(int), fp);
+ if(numRead != sizeof(int)) { fclose(fp); return false; }
+
+ wfo.mIndices = new int[wfo.mTriCount*3];
+ numRead = fread(wfo.mIndices, 1, sizeof(int)*wfo.mTriCount*3, fp);
+ if(numRead != sizeof(int)*wfo.mTriCount*3) { fclose(fp); return false; }
+
+ // NB: mTexCoords not supported
+
+ fclose(fp);
+ return true;
+}
+
+bool SaveWavefrontBinary(const char* filename, const WavefrontObj& wfo)
+{
+ SampleFramework::File* fp = NULL;
+ PxToolkit::fopen_s(&fp, filename, "wb");
+ if(!fp) return false;
+
+ fwrite(&wfo.mVertexCount, 1, sizeof(int), fp);
+ fwrite(wfo.mVertices, 1, wfo.mVertexCount*3*sizeof(float), fp);
+
+ fwrite(&wfo.mTriCount, 1, sizeof(int), fp);
+ fwrite(wfo.mIndices, 1, wfo.mTriCount*3*sizeof(int), fp);
+
+ // NB: mTexCoords not supported
+
+ fclose(fp);
+ return true;
+}
diff --git a/PhysX_3.4/Samples/SampleBase/wavefront.h b/PhysX_3.4/Samples/SampleBase/wavefront.h
new file mode 100644
index 00000000..34240ebd
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleBase/wavefront.h
@@ -0,0 +1,52 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef WAVEFRONT_OBJ_H
+#define WAVEFRONT_OBJ_H
+
+class WavefrontObj
+{
+public:
+
+ WavefrontObj(void);
+ ~WavefrontObj(void);
+
+ unsigned int loadObj(const char *fname, bool textured); // load a wavefront obj returns number of triangles that were loaded. Data is persists until the class is destructed.
+
+ int mVertexCount;
+ int mTriCount;
+ int* mIndices;
+ float* mVertices;
+ float* mTexCoords;
+};
+
+ bool LoadWavefrontBinary(const char* filename, WavefrontObj& wfo);
+ bool SaveWavefrontBinary(const char* filename, const WavefrontObj& wfo);
+
+#endif