#include "platform/platform.h" #include "T3D/physics/jolt/joltPlugin.h" #include "T3D/physics/jolt/joltWorld.h" #include "T3D/physics/jolt/joltCollision.h" #include "T3D/physics/jolt/joltBody.h" #include "T3D/physics/jolt/joltPlayer.h" #include "T3D/gameBase/gameProcess.h" #include "core/util/tNamedFactory.h" #include "gfx/sim/debugDraw.h" AFTER_MODULE_INIT(Sim) { NamedFactory::add("JoltPhysics", &JoltPlugin::create); } JoltPlugin::JoltPlugin() { JPH::RegisterDefaultAllocator(); JPH::Factory::sInstance = new JPH::Factory(); JPH::RegisterTypes(); #ifdef JPH_DEBUG_RENDERER JPH::DebugRenderer::sInstance = new JoltDebugRenderer(); #endif // TORQUE_TOOLS } JoltPlugin::~JoltPlugin() { delete JPH::Factory::sInstance; #ifdef JPH_DEBUG_RENDERER delete JPH::DebugRenderer::sInstance; JPH::DebugRenderer::sInstance = nullptr; #endif } void JoltPlugin::reset() { // First delete all the cleanup objects. if (getPhysicsCleanup()) getPhysicsCleanup()->deleteAllObjects(); getPhysicsResetSignal().trigger(PhysicsResetEvent_Restore); // Now let each world reset itself. Map::Iterator iter = mPhysicsWorldLookup.begin(); for (; iter != mPhysicsWorldLookup.end(); iter++) iter->value->reset(); } PhysicsPlugin* JoltPlugin::create() { return new JoltPlugin(); } void JoltPlugin::destroyPlugin() { // Cleanup any worlds that are still kicking. Map::Iterator iter = mPhysicsWorldLookup.begin(); for (; iter != mPhysicsWorldLookup.end(); iter++) { iter->value->destroyWorld(); delete iter->value; } mPhysicsWorldLookup.clear(); delete this; } PhysicsCollision* JoltPlugin::createCollision() { return new JoltCollision(); } PhysicsBody* JoltPlugin::createBody() { return new JoltBody(); } PhysicsPlayer* JoltPlugin::createPlayer() { return new JoltPlayer(); } bool JoltPlugin::isSimulationEnabled() const { bool ret = false; JoltWorld* world = static_cast(getWorld(smClientWorldName)); if (world) { ret = world->getEnabled(); return ret; } world = static_cast(getWorld(smServerWorldName)); if (world) { ret = world->getEnabled(); return ret; } return ret; } void JoltPlugin::enableSimulation(const String& worldName, bool enable) { JoltWorld* world = static_cast(getWorld(worldName)); if (world) world->setEnabled(enable); } void JoltPlugin::setTimeScale(const F32 timeScale) { // Grab both the client and // server worlds and set their time // scales to the passed value. JoltWorld* world = static_cast(getWorld(smClientWorldName)); if (world) world->setEditorTimeScale(timeScale); world = static_cast(getWorld(smServerWorldName)); if (world) world->setEditorTimeScale(timeScale); } const F32 JoltPlugin::getTimeScale() const { // Grab both the client and // server worlds and call // setEnabled( true ) on them. JoltWorld* world = static_cast(getWorld(smClientWorldName)); if (!world) { world = static_cast(getWorld(smServerWorldName)); if (!world) return 0.0f; } return world->getEditorTimeScale(); } bool JoltPlugin::createWorld(const String& worldName) { Map::Iterator iter = mPhysicsWorldLookup.find(worldName); PhysicsWorld* world = NULL; iter != mPhysicsWorldLookup.end() ? world = (*iter).value : world = NULL; if (world) { Con::errorf("BtPlugin::createWorld - %s world already exists!", worldName.c_str()); return false; } world = new JoltWorld(); if (worldName.equal(smClientWorldName, String::NoCase)) world->initWorld(false, ClientProcessList::get()); else world->initWorld(true, ServerProcessList::get()); mPhysicsWorldLookup.insert(worldName, world); return world != NULL; } void JoltPlugin::destroyWorld(const String& worldName) { Map::Iterator iter = mPhysicsWorldLookup.find(worldName); if (iter == mPhysicsWorldLookup.end()) return; PhysicsWorld* world = (*iter).value; world->destroyWorld(); mPhysicsWorldLookup.erase(iter); } PhysicsWorld* JoltPlugin::getWorld(const String& worldName) const { if (mPhysicsWorldLookup.isEmpty()) return NULL; Map::ConstIterator iter = mPhysicsWorldLookup.find(worldName); return iter != mPhysicsWorldLookup.end() ? (*iter).value : NULL; } PhysicsWorld* JoltPlugin::getWorld() const { if (mPhysicsWorldLookup.size() == 0) return NULL; Map::ConstIterator iter = mPhysicsWorldLookup.begin(); return iter->value; } U32 JoltPlugin::getWorldCount() const { return mPhysicsWorldLookup.size(); } #ifdef JPH_DEBUG_RENDERER JoltDebugRenderer::JoltDebugRenderer() { JPH::DebugRenderer::Initialize(); } void JoltDebugRenderer::DrawLine(JPH::RVec3Arg inFrom, JPH::RVec3Arg inTo, JPH::ColorArg inColor) { DebugDrawer::get()->drawLine(joltCast(inFrom), joltCast(inTo), fromJolt(inColor)); } void JoltDebugRenderer::DrawTriangle(JPH::RVec3Arg inV1, JPH::RVec3Arg inV2, JPH::RVec3Arg inV3, JPH::ColorArg inColor, ECastShadow inCastShadow) { DebugDrawer::get()->drawTri(joltCast(inV1), joltCast(inV2), joltCast(inV3), fromJolt(inColor)); } JPH::DebugRenderer::Batch JoltDebugRenderer::CreateTriangleBatch(const Triangle* inTriangles, int inTriangleCount) { BatchImpl* batch = new BatchImpl; if (inTriangles && inTriangleCount) batch->mTriangles.assign(inTriangles, inTriangles + inTriangleCount); return batch; } JPH::DebugRenderer::Batch JoltDebugRenderer::CreateTriangleBatch(const Vertex* inVertices, int inVertexCount, const JPH::uint32* inIndices, int inIndexCount) { BatchImpl* batch = new BatchImpl; if (inVertices == nullptr || inVertexCount == 0 || inIndices == nullptr || inIndexCount == 0) return batch; // Convert indexed triangle list to triangle list batch->mTriangles.resize(inIndexCount / 3); for (size_t t = 0; t < batch->mTriangles.size(); ++t) { JPH::DebugRenderer::Triangle& triangle = batch->mTriangles[t]; triangle.mV[0] = inVertices[inIndices[t * 3 + 0]]; triangle.mV[1] = inVertices[inIndices[t * 3 + 1]]; triangle.mV[2] = inVertices[inIndices[t * 3 + 2]]; } return batch; } void JoltDebugRenderer::DrawGeometry(JPH::RMat44Arg inModelMatrix, const JPH::AABox& inWorldSpaceBounds, float inLODScaleSq, JPH::ColorArg inModelColor, const GeometryRef& inGeometry, ECullMode inCullMode, ECastShadow inCastShadow, EDrawMode inDrawMode) { const auto& lod = inGeometry->GetLOD( mFrameState.cameraPos, inWorldSpaceBounds, inLODScaleSq ); const BatchImpl* batch = static_cast(lod.mTriangleBatch.GetPtr()); if (!batch) return; const U32 triCount = batch->mTriangles.size(); if (triCount == 0) return; if (!mFrameState.frustum.getBounds().isOverlapped(fromJolt(inWorldSpaceBounds))) return; // Start one batched primitive build GFX->setupGenericShaders(); GFXStateBlockDesc desc; desc.setZReadWrite(false); GFX->setStateBlockByDesc(desc); PrimBuild::begin(GFXLineList, triCount * 6); for (const auto& tri : batch->mTriangles) { JPH::Vec3 v0 = inModelMatrix * JPH::Vec3(tri.mV[0].mPosition); JPH::Vec3 v1 = inModelMatrix * JPH::Vec3(tri.mV[1].mPosition); JPH::Vec3 v2 = inModelMatrix * JPH::Vec3(tri.mV[2].mPosition); JPH::Color color = inModelColor * tri.mV[0].mColor; PrimBuild::color(fromJolt(color)); // Edge 1 PrimBuild::vertex3f(v0.GetX(), v0.GetY(), v0.GetZ()); PrimBuild::vertex3f(v1.GetX(), v1.GetY(), v1.GetZ()); // Edge 2 PrimBuild::vertex3f(v1.GetX(), v1.GetY(), v1.GetZ()); PrimBuild::vertex3f(v2.GetX(), v2.GetY(), v2.GetZ()); // Edge 3 PrimBuild::vertex3f(v2.GetX(), v2.GetY(), v2.GetZ()); PrimBuild::vertex3f(v0.GetX(), v0.GetY(), v0.GetZ()); } PrimBuild::end(true); } #endif