#include "PxPhysicsAPI.h" #include "physxABIStruct.hpp" // // extern "C" { struct FilterShaderCallbackInfo { physx::PxFilterObjectAttributes attributes0; physx::PxFilterObjectAttributes attributes1; physx::PxFilterData filterData0; physx::PxFilterData filterData1; physx::PxPairFlags* pairFlags; const void* constantBlock; physx::PxU32 constantBlockSize; }; typedef void (*CollisionCallback)(void*, physx::PxContactPairHeader const*, physx::PxContactPair const*, physx::PxU32); typedef physx::PxU16(*SimulationShaderFilter)(FilterShaderCallbackInfo*); struct FilterCallbackData { SimulationShaderFilter filter; bool call_default_filter_shader_first; }; physx::PxFilterFlags FilterShaderTrampoline(physx::PxFilterObjectAttributes attributes0, physx::PxFilterData filterData0, physx::PxFilterObjectAttributes attributes1, physx::PxFilterData filterData1, physx::PxPairFlags& pairFlags, const void* constantBlock, physx::PxU32 constantBlockSize) { const FilterCallbackData* data = static_cast(constantBlock); if (data->call_default_filter_shader_first) { // Let the default handler set the pair flags, but ignore the collision filtering PxDefaultSimulationFilterShader(attributes0, filterData0, attributes1, filterData1, pairFlags, constantBlock, constantBlockSize); } // Get the filter shader from the constant block SimulationShaderFilter shaderfilter = data->filter; // This is a bit expensive since we're putting things on the stack but with LTO this should optimize OK, // and I was having issues with corrupted values when passing by value FilterShaderCallbackInfo info{ attributes0, attributes1, filterData0, filterData1, &pairFlags, nullptr, 0 }; // We return a u16 since PxFilterFlags is a complex type and C++ wants it to be returned on the stack, // but Rust thinks it's simple due to the codegen and wants to return it in EAX. return physx::PxFilterFlags{ shaderfilter(&info) }; } using PairFoundCallback = physx::PxFilterFlags(*)(physx::PxU64, physx::PxFilterObjectAttributes, physx::PxFilterData, const physx::PxActor*, const physx::PxShape*, physx::PxFilterObjectAttributes, physx::PxFilterData, const physx::PxActor*, const physx::PxShape*, physx::PxPairFlags&); using PairLostCallback = void (*)(physx::PxU64, physx::PxFilterObjectAttributes, physx::PxFilterData, physx::PxFilterObjectAttributes, physx::PxFilterData, bool); using StatusChangeCallback = bool (*)(physx::PxU64&, physx::PxPairFlags&, physx::PxFilterFlags&); struct SimuliationFilterCallBackInfo { // Callback for pairFound PairFoundCallback pairFoundCallback = nullptr; PairLostCallback pairLostCallback = nullptr; StatusChangeCallback statusChangeCallback = nullptr; }; // // class SimulationFilterCallBackTrampoline : public physx::PxSimulationFilterCallback { public: SimulationFilterCallBackTrampoline(const SimuliationFilterCallBackInfo* callbacks) : mCallbacks(*callbacks) {} // Collisions //二级传递引用需要传递万能引用 可能存在bug physx::PxFilterFlags pairFound(physx::PxU64 pairID, physx::PxFilterObjectAttributes attributes0, physx::PxFilterData filterData0, const physx::PxActor* a0, const physx::PxShape* s0, physx::PxFilterObjectAttributes attributes1, physx::PxFilterData filterData1, const physx::PxActor* a1, const physx::PxShape* s1, physx::PxPairFlags& pairFlags) override { if (mCallbacks.pairFoundCallback) { return mCallbacks.pairFoundCallback(pairID, attributes0, filterData0, a0, s0, attributes1, filterData1, a1, s1, pairFlags); } } // Triggers void pairLost(physx::PxU64 pairID, physx::PxFilterObjectAttributes attributes0, physx::PxFilterData filterData0, physx::PxFilterObjectAttributes attributes1, physx::PxFilterData filterData1, bool objectRemoved) override { if (mCallbacks.pairLostCallback) { mCallbacks.pairLostCallback(pairID, attributes0, filterData0, attributes1, filterData1, objectRemoved); } } // Constraint breaks bool statusChange(physx::PxU64& pairID, physx::PxPairFlags& pairFlags, physx::PxFilterFlags& filterFlags) override { if (mCallbacks.statusChangeCallback) { return mCallbacks.statusChangeCallback(pairID, pairFlags, filterFlags); } } SimuliationFilterCallBackInfo mCallbacks; }; // // // using CollisionCallback = void (*)(void*, physx::PxContactPairHeader const*, physx::PxContactPair const*, physx::PxU32); using TriggerCallback = void (*)(void*, physx::PxTriggerPair const*, physx::PxU32); using ConstraintBreakCallback = void (*)(void*, physx::PxConstraintInfo const*, physx::PxU32); using WakeSleepCallback = void (*)(void*, physx::PxActor** const, physx::PxU32, bool); using AdvanceCallback = void (*)(void*, const physx::PxRigidBody* const*, const physx::PxTransform* const, physx::PxU32); // // struct SimulationEventCallbackInfo { // Callback for collision events. CollisionCallback collisionCallback = nullptr; void* collisionUserData = nullptr; // Callback for trigger shape events (an object entered or left a trigger shape). TriggerCallback triggerCallback = nullptr; void* triggerUserData = nullptr; // Callback for when a constraint breaks (such as a joint with a force limit) ConstraintBreakCallback constraintBreakCallback = nullptr; void* constraintBreakUserData = nullptr; // Callback for when an object falls asleep or is awoken. WakeSleepCallback wakeSleepCallback = nullptr; void* wakeSleepUserData = nullptr; // Callback to get the next pose early for objects (if flagged with eENABLE_POSE_INTEGRATION_PREVIEW). AdvanceCallback advanceCallback = nullptr; void* advanceUserData = nullptr; }; // // // class SimulationEventTrampoline : public physx::PxSimulationEventCallback { public: SimulationEventTrampoline(const SimulationEventCallbackInfo* callbacks) : mCallbacks(*callbacks) {} // Collisions void onContact(const physx::PxContactPairHeader& pairHeader, const physx::PxContactPair* pairs, physx::PxU32 nbPairs) override { if (mCallbacks.collisionCallback) { mCallbacks.collisionCallback(mCallbacks.collisionUserData, &pairHeader, pairs, nbPairs); } } // Triggers void onTrigger(physx::PxTriggerPair* pairs, physx::PxU32 count) override { if (mCallbacks.triggerCallback) { mCallbacks.triggerCallback(mCallbacks.triggerUserData, pairs, count); } } // Constraint breaks void onConstraintBreak(physx::PxConstraintInfo* constraints, physx::PxU32 count) override { if (mCallbacks.constraintBreakCallback) { mCallbacks.constraintBreakCallback(mCallbacks.constraintBreakUserData, constraints, count); } } // Wake/Sleep (combined for convenience) void onWake(physx::PxActor** actors, physx::PxU32 count) override { if (mCallbacks.wakeSleepCallback) { mCallbacks.wakeSleepCallback(mCallbacks.wakeSleepUserData, actors, count, true); } } void onSleep(physx::PxActor** actors, physx::PxU32 count) override { if (mCallbacks.wakeSleepCallback) { mCallbacks.wakeSleepCallback(mCallbacks.wakeSleepUserData, actors, count, false); } } // Advance void onAdvance(const physx::PxRigidBody* const* bodyBuffer, const physx::PxTransform* poseBuffer, const physx::PxU32 count) override { if (mCallbacks.advanceCallback) { mCallbacks.advanceCallback(mCallbacks.advanceUserData, bodyBuffer, poseBuffer, count); } } SimulationEventCallbackInfo mCallbacks; }; // class RaycastFilterCallback : public physx::PxQueryFilterCallback { public: explicit RaycastFilterCallback(physx::PxRigidActor* actor) : mActor(actor) {} physx::PxRigidActor* mActor; virtual physx::PxQueryHitType::Enum preFilter(const physx::PxFilterData&, const physx::PxShape* shape, const physx::PxRigidActor* actor, physx::PxHitFlags&) { if (mActor == actor) { return physx::PxQueryHitType::eNONE; } else { return physx::PxQueryHitType::eBLOCK; } } virtual physx::PxQueryHitType::Enum postFilter(const physx::PxFilterData& filterData, const physx::PxQueryHit& hit, const physx::PxShape* shape, const physx::PxRigidActor* actor) { return physx::PxQueryHitType::eNONE; } }; // TODO: Shouldn't we rename this to PreFilterCallback? typedef uint32_t(*RaycastHitCallback)(const physx::PxRigidActor* actor, const physx::PxFilterData* filterData, const physx::PxShape* shape, uint32_t hitFlags, const void* userData); typedef uint32_t(*PostFilterCallback)(const physx::PxFilterData* filterData, const physx::PxQueryHit* hit, const void* userData); physx::PxQueryHitType::Enum sanitize_hit_type(uint32_t hit_type) { switch (hit_type) { case physx::PxQueryHitType::eNONE: case physx::PxQueryHitType::eTOUCH: case physx::PxQueryHitType::eBLOCK: return (physx::PxQueryHitType::Enum)hit_type; default: return physx::PxQueryHitType::eNONE; } } // class RaycastFilterTrampoline : public physx::PxQueryFilterCallback { public: RaycastFilterTrampoline(RaycastHitCallback callback, const void* userdata) : mCallback(callback), mUserData(userdata) {} RaycastHitCallback mCallback; const void* mUserData; virtual physx::PxQueryHitType::Enum preFilter(const physx::PxFilterData& filterData, const physx::PxShape* shape, const physx::PxRigidActor* actor, physx::PxHitFlags& hitFlags) { return sanitize_hit_type(mCallback(actor, &filterData, shape, (uint32_t)hitFlags, mUserData)); } virtual physx::PxQueryHitType::Enum postFilter(const physx::PxFilterData& filterData, const physx::PxQueryHit& hit, const physx::PxShape* shape, const physx::PxRigidActor* actor) { return physx::PxQueryHitType::eNONE; } //virtual physx::PxQueryHitType::Enum postFilter(const physx::PxFilterData&, const physx::PxQueryHit&) //{ // return physx::PxQueryHitType::eNONE; //} }; // // class RaycastFilterPrePostTrampoline : public physx::PxQueryFilterCallback { public: RaycastFilterPrePostTrampoline(RaycastHitCallback preFilter, PostFilterCallback postFilter, const void* userdata) : mPreFilter(preFilter), mPostFilter(postFilter), mUserData(userdata) {} RaycastHitCallback mPreFilter; PostFilterCallback mPostFilter; const void* mUserData; virtual physx::PxQueryHitType::Enum preFilter(const physx::PxFilterData& filterData, const physx::PxShape* shape, const physx::PxRigidActor* actor, physx::PxHitFlags& hitFlags) { return sanitize_hit_type(mPreFilter(actor, &filterData, shape, (uint32_t)hitFlags, mUserData)); } //需要重新关注下 virtual physx::PxQueryHitType::Enum postFilter(const physx::PxFilterData& filterData, const physx::PxQueryHit& hit, const physx::PxShape* shape, const physx::PxRigidActor* actor) { return sanitize_hit_type(mPostFilter(&filterData, &hit, mUserData)); } //virtual physx::PxQueryHitType::Enum postFilter(const physx::PxFilterData& filterData, const physx::PxQueryHit& hit) //{ // return sanitize_hit_type(mPostFilter(&filterData, &hit, mUserData)); //} }; // typedef physx::PxAgain(*RaycastHitProcessTouchesCallback)(const physx::PxRaycastHit* buffer, physx::PxU32 nbHits, void* userdata); typedef physx::PxAgain(*SweepHitProcessTouchesCallback)(const physx::PxSweepHit* buffer, physx::PxU32 nbHits, void* userdata); typedef physx::PxAgain(*OverlapHitProcessTouchesCallback)(const physx::PxOverlapHit* buffer, physx::PxU32 nbHits, void* userdata); typedef void (*HitFinalizeQueryCallback)(void* userdata); // class RaycastHitCallbackTrampoline : public physx::PxRaycastCallback { public: RaycastHitCallbackTrampoline( RaycastHitProcessTouchesCallback processTouchesCallback, HitFinalizeQueryCallback finalizeQueryCallback, physx::PxRaycastHit* touchesBuffer, physx::PxU32 numTouches, void* userdata) : physx::PxRaycastCallback(touchesBuffer, numTouches), mProcessTouchesCallback(processTouchesCallback), mFinalizeQueryCallback(finalizeQueryCallback), mUserData(userdata) {} RaycastHitProcessTouchesCallback mProcessTouchesCallback; HitFinalizeQueryCallback mFinalizeQueryCallback; void* mUserData; physx::PxAgain processTouches(const physx::PxRaycastHit* buffer, physx::PxU32 nbHits) override { return mProcessTouchesCallback(buffer, nbHits, mUserData); } void finalizeQuery() override { mFinalizeQueryCallback(mUserData); } }; // class SweepHitCallbackTrampoline : public physx::PxSweepCallback { public: SweepHitCallbackTrampoline( SweepHitProcessTouchesCallback processTouchesCallback, HitFinalizeQueryCallback finalizeQueryCallback, physx::PxSweepHit* touchesBuffer, physx::PxU32 numTouches, void* userdata) : physx::PxSweepCallback(touchesBuffer, numTouches), mProcessTouchesCallback(processTouchesCallback), mFinalizeQueryCallback(finalizeQueryCallback), mUserData(userdata) {} SweepHitProcessTouchesCallback mProcessTouchesCallback; HitFinalizeQueryCallback mFinalizeQueryCallback; void* mUserData; physx::PxAgain processTouches(const physx::PxSweepHit* buffer, physx::PxU32 nbHits) override { return mProcessTouchesCallback(buffer, nbHits, mUserData); } void finalizeQuery() override { mFinalizeQueryCallback(mUserData); } }; // class OverlapHitCallbackTrampoline : public physx::PxOverlapCallback { public: OverlapHitCallbackTrampoline( OverlapHitProcessTouchesCallback processTouchesCallback, HitFinalizeQueryCallback finalizeQueryCallback, physx::PxOverlapHit* touchesBuffer, physx::PxU32 numTouches, void* userdata) : physx::PxOverlapCallback(touchesBuffer, numTouches), mProcessTouchesCallback(processTouchesCallback), mFinalizeQueryCallback(finalizeQueryCallback), mUserData(userdata) {} OverlapHitProcessTouchesCallback mProcessTouchesCallback; HitFinalizeQueryCallback mFinalizeQueryCallback; void* mUserData; physx::PxAgain processTouches(const physx::PxOverlapHit* buffer, physx::PxU32 nbHits) override { return mProcessTouchesCallback(buffer, nbHits, mUserData); } void finalizeQuery() override { mFinalizeQueryCallback(mUserData); } }; typedef void* (*AllocCallback)(uint64_t size, const char* typeName, const char* filename, int line, void* userdata); typedef void (*DeallocCallback)(void* ptr, void* userdata); class CustomAllocatorTrampoline : public physx::PxAllocatorCallback { public: CustomAllocatorTrampoline(AllocCallback allocCb, DeallocCallback deallocCb, void* userdata) : mAllocCallback(allocCb), mDeallocCallback(deallocCb), mUserData(userdata) {} void* allocate(size_t size, const char* typeName, const char* filename, int line) { return mAllocCallback((uint64_t)size, typeName, filename, line, mUserData); } virtual void deallocate(void* ptr) { mDeallocCallback(ptr, mUserData); } private: AllocCallback mAllocCallback; DeallocCallback mDeallocCallback; public: void* mUserData; }; typedef void* (*ZoneStartCallback)(const char* typeName, bool detached, uint64_t context, void* userdata); typedef void (*ZoneEndCallback)(void* profilerData, const char* typeName, bool detached, uint64_t context, void* userdata); class CustomProfilerTrampoline : public physx::PxProfilerCallback { public: CustomProfilerTrampoline(ZoneStartCallback startCb, ZoneEndCallback endCb, void* userdata) : mStartCallback(startCb), mEndCallback(endCb), mUserData(userdata) { } virtual void* zoneStart(const char* eventName, bool detached, uint64_t contextId) override { return mStartCallback(eventName, detached, contextId, mUserData); } virtual void zoneEnd(void* profilerData, const char* eventName, bool detached, uint64_t contextId) override { return mEndCallback(profilerData, eventName, detached, contextId, mUserData); } private: ZoneStartCallback mStartCallback; ZoneEndCallback mEndCallback; public: void* mUserData; }; using ErrorCallback = void (*)(int code, const char* message, const char* file, int line, void* userdata); class ErrorTrampoline : public physx::PxErrorCallback { public: ErrorTrampoline(ErrorCallback errorCb, void* userdata) : mErrorCallback(errorCb), mUserdata(userdata) {} void reportError(physx::PxErrorCode::Enum code, const char* message, const char* file, int line) override { mErrorCallback(code, message, file, line, mUserdata); } private: ErrorCallback mErrorCallback = nullptr; void* mUserdata = nullptr; }; //using AssertHandler = void (*)(const char* expr, const char* file, int line, bool* should_ignore, void* userdata); //class AssertTrampoline : public physx::PxAssertHandler { //public: // AssertTrampoline(AssertHandler onAssert, void* userdata) // : mAssertHandler(onAssert), mUserdata(userdata) // {} // // virtual void operator()(const char* exp, const char* file, int line, bool& ignore) override final { // mAssertHandler(exp, file, line, &ignore, mUserdata); // } // //private: // AssertHandler mAssertHandler = nullptr; // void* mUserdata = nullptr; //}; // fixme[tolsson]: this might be iffy on Windows with DLLs if we have multiple packages // linking against the raw interface //physx::PxErrorCallback* get_default_error_callback() //{ // return &gErrorCallback; //} physx::PxPhysics* physx_create_physics(physx::PxFoundation* foundation) { return PxCreatePhysics(PX_PHYSICS_VERSION, *foundation, physx::PxTolerancesScale(), true, nullptr, nullptr); } physx::PxQueryFilterCallback* create_raycast_filter_callback(physx::PxRigidActor* actor_to_ignore) { return new RaycastFilterCallback(actor_to_ignore); } physx::PxQueryFilterCallback* create_raycast_filter_callback_func(RaycastHitCallback callback, void* userData) { return new RaycastFilterTrampoline(callback, userData); } physx::PxQueryFilterCallback* create_pre_and_post_raycast_filter_callback_func(RaycastHitCallback preFilter, PostFilterCallback postFilter, void* userData) { return new RaycastFilterPrePostTrampoline(preFilter, postFilter, userData); } physx::PxRaycastCallback* create_raycast_callback( RaycastHitProcessTouchesCallback process_touches_callback, HitFinalizeQueryCallback finalize_query_callback, physx::PxRaycastHit* touchesBuffer, physx::PxU32 numTouches, void* userdata ) { return new RaycastHitCallbackTrampoline( process_touches_callback, finalize_query_callback, touchesBuffer, numTouches, userdata); } void delete_raycast_callback(physx::PxRaycastCallback* callback) { delete callback; } void delete_sweep_callback(physx::PxSweepCallback* callback) { delete callback; } void delete_overlap_callback(physx::PxOverlapCallback* callback) { delete callback; } physx::PxSweepCallback* create_sweep_callback( SweepHitProcessTouchesCallback process_touches_callback, HitFinalizeQueryCallback finalize_query_callback, physx::PxSweepHit* touchesBuffer, physx::PxU32 numTouches, void* userdata ) { return new SweepHitCallbackTrampoline( process_touches_callback, finalize_query_callback, touchesBuffer, numTouches, userdata ); } physx::PxOverlapCallback* create_overlap_callback( OverlapHitProcessTouchesCallback process_touches_callback, HitFinalizeQueryCallback finalize_query_callback, physx::PxOverlapHit* touchesBuffer, physx::PxU32 numTouches, void* userdata ) { return new OverlapHitCallbackTrampoline( process_touches_callback, finalize_query_callback, touchesBuffer, numTouches, userdata ); } physx::PxAllocatorCallback* create_alloc_callback( AllocCallback alloc_callback, DeallocCallback dealloc_callback, void* userdata ) { return new CustomAllocatorTrampoline(alloc_callback, dealloc_callback, userdata); } void* get_alloc_callback_user_data(physx::PxAllocatorCallback* allocator) { CustomAllocatorTrampoline* trampoline = static_cast(allocator); return trampoline->mUserData; } physx::PxProfilerCallback* create_profiler_callback( ZoneStartCallback zone_start_callback, ZoneEndCallback zone_end_callback, void* userdata ) { return new CustomProfilerTrampoline(zone_start_callback, zone_end_callback, userdata); } physx::PxErrorCallback* create_error_callback( ErrorCallback error_callback, void* userdata ) { return new ErrorTrampoline(error_callback, userdata); } //physx::PxAssertHandler* create_assert_handler( AssertHandler on_assert,void* userdata ) //{ // return new AssertTrampoline(on_assert, userdata); //} void* get_default_simulation_filter_shader() { return (void*)physx::PxDefaultSimulationFilterShader; } physx::PxSimulationFilterCallback* create_simulation_filter_callbacks(const SimuliationFilterCallBackInfo* callbacks) { SimulationFilterCallBackTrampoline* trampoline = new SimulationFilterCallBackTrampoline(callbacks); return static_cast(trampoline); } void destroy_simulation_filter_callbacks(physx::PxSimulationFilterCallback* callback) { SimulationFilterCallBackTrampoline* trampoline = static_cast(callback); delete trampoline; } physx::PxSimulationEventCallback* create_simulation_event_callbacks(const SimulationEventCallbackInfo* callbacks) { SimulationEventTrampoline* trampoline = new SimulationEventTrampoline(callbacks); return static_cast(trampoline); } SimulationEventCallbackInfo* get_simulation_event_info(physx::PxSimulationEventCallback* callback) { SimulationEventTrampoline* trampoline = static_cast(callback); return &trampoline->mCallbacks; } void destroy_simulation_event_callbacks(physx::PxSimulationEventCallback* callback) { SimulationEventTrampoline* trampoline = static_cast(callback); delete trampoline; } void enable_custom_filter_shader(physx::PxSceneDesc* desc, SimulationShaderFilter filter, uint32_t call_default_filter_shader_first) { /* Note: This is a workaround to PhysX copying the filter data */ static FilterCallbackData filterShaderData = { filter, call_default_filter_shader_first != 0 }; desc->filterShader = FilterShaderTrampoline; // printf("Setting pointer to %p\n", filter); desc->filterShaderData = (void*)&filterShaderData; desc->filterShaderDataSize = sizeof(FilterCallbackData); } //// Not generated, used only for testing and examples! //void PxAssertHandler_opCall_mut(physx_PxErrorCallback_Pod* self__pod, char const* expr, char const* file, int32_t line, bool* ignore) { // physx::PxAssertHandler* self_ = reinterpret_cast(self__pod); // (*self_)(expr, file, line, *ignore); //}; }