// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of NVIDIA CORPORATION nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Copyright (c) 2008-2021 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" 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 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); 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); 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& localPoses, const std::vector& 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); void createRenderObjectsFromScene(); 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& 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(PxArticulationBase& 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 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& ); 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 mPhysicsActors; std::vector mDeletedRenderActors; std::vector mRenderActors; std::vector mRenderTextures; std::vector mManagedAssets; std::vector mRenderMaterials; RenderMaterial* (&mManagedMaterials)[MATERIAL_COUNT]; SampleFramework::SampleInputAsset* mSampleInputAsset; PxActor** mBufferedActiveActors; std::vector 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