aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Samples/SampleBase/PhysXSample.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'PhysX_3.4/Samples/SampleBase/PhysXSample.cpp')
-rw-r--r--PhysX_3.4/Samples/SampleBase/PhysXSample.cpp2901
1 files changed, 2901 insertions, 0 deletions
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
+