diff options
| author | git perforce import user <a@b> | 2016-10-25 12:29:14 -0600 |
|---|---|---|
| committer | Sheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees> | 2016-10-25 18:56:37 -0500 |
| commit | 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch) | |
| tree | fa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Samples/SampleBase | |
| download | physx-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')
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 ¢er0, PxReal r0, const PxVec3 ¢er1, 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 ¢er0, PxReal r0, const PxVec3 ¢er1, 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 |