diff --git a/.gitmodules b/.gitmodules index f98028e..8433ebe 100644 --- a/.gitmodules +++ b/.gitmodules @@ -26,3 +26,6 @@ [submodule "Prism/vendor/Box2D"] path = Prism/vendor/Box2D url = https://github.com/erincatto/box2d.git +[submodule "Prism/vendor/PhysX"] + path = Prism/vendor/PhysX + url = https://github.com/NVIDIA-Omniverse/PhysX.git diff --git a/Editor/Editor/EditorLayer.cpp b/Editor/Editor/EditorLayer.cpp index 86fc256..0b32dea 100644 --- a/Editor/Editor/EditorLayer.cpp +++ b/Editor/Editor/EditorLayer.cpp @@ -182,6 +182,7 @@ namespace Prism void EditorLayer::OnDetach() { + m_EditorScene->OnShutdown(); } void EditorLayer::OnUpdate(const TimeStep deltaTime) @@ -953,7 +954,12 @@ namespace Prism SelectedSubmesh selection; if (entity.HasComponent()) { - selection.Mesh = &entity.GetComponent().Mesh->GetSubmeshes()[0]; + auto& meshComp = entity.GetComponent(); + + if (meshComp.Mesh) + { + selection.Mesh = &meshComp.Mesh->GetSubmeshes()[0]; + } } selection.Entity = entity; m_SelectionContext.clear(); diff --git a/Editor/assets/scenes/Physics3DTest.scene b/Editor/assets/scenes/Physics3DTest.scene new file mode 100644 index 0000000..5172996 --- /dev/null +++ b/Editor/assets/scenes/Physics3DTest.scene @@ -0,0 +1,95 @@ +Scene: Scene Name +Environment: + AssetPath: assets/env/pink_sunrise_4k.hdr + Light: + Direction: [-0.787, -0.73299998, 1] + Radiance: [1, 1, 1] + Multiplier: 0.514999986 +Entities: + - Entity: 10169503531257462571 + TagComponent: + Tag: Box + TransformComponent: + Position: [0, 1.5, 0] + Rotation: [1, 0, 0, 0] + Scale: [2, 2, 2] + MeshComponent: + AssetPath: assets/meshes/Cube1m.fbx + RigidBodyComponent: + BodyType: 1 + Mass: 0.5 + PhysicsMaterialComponent: + StaticFriction: 1 + DynamicFriction: 1 + Bounciness: 0 + BoxColliderComponent: + Offset: [0, 0, 0] + Size: [2, 2, 2] + - Entity: 14057422478420564497 + TagComponent: + Tag: Player + TransformComponent: + Position: [-19.43363, 4.50874043, -1.96695328e-06] + Rotation: [1, 0, 0, 0] + Scale: [1, 1, 1] + ScriptComponent: + ModuleName: Example.PlayerSphere + StoredFields: + - Name: HorizontalForce + Type: 1 + Data: 10 + - Name: MaxSpeed + Type: 6 + Data: [10, 10, 10] + - Name: JumpForce + Type: 1 + Data: 200 + MeshComponent: + AssetPath: assets/meshes/Sphere1m.fbx + RigidBodyComponent: + BodyType: 1 + Mass: 1 + PhysicsMaterialComponent: + StaticFriction: 1 + DynamicFriction: 1 + Bounciness: 0 + SphereColliderComponent: + Radius: 0.5 + - Entity: 5178862374589434728 + TagComponent: + Tag: Camera + TransformComponent: + Position: [-21.7406311, 9.70659542, 15] + Rotation: [0.999910355, -0.0133911213, 0, 0] + Scale: [1, 1, 1] + ScriptComponent: + ModuleName: Example.BasicController + StoredFields: + - Name: Speed + Type: 1 + Data: 12 + - Name: DistanceFromPlayer + Type: 1 + Data: 15 + CameraComponent: + Camera: some camera data... + Primary: true + - Entity: 18306113171518048249 + TagComponent: + Tag: Box + TransformComponent: + Position: [0, 0, 0] + Rotation: [1, 0, 0, 0] + Scale: [50, 1, 50] + MeshComponent: + AssetPath: assets/meshes/Cube1m.fbx + RigidBodyComponent: + BodyType: 0 + Mass: 1 + PhysicsMaterialComponent: + StaticFriction: 1 + DynamicFriction: 1 + Bounciness: 0 + BoxColliderComponent: + Offset: [0, 0, 0] + Size: [50, 1, 50] diff --git a/ExampleApp/Src/BasicContorller.cs b/ExampleApp/Src/BasicContorller.cs index b9180e5..f15ca02 100644 --- a/ExampleApp/Src/BasicContorller.cs +++ b/ExampleApp/Src/BasicContorller.cs @@ -5,6 +5,7 @@ namespace Example public class BasicController : Entity { public float Speed; + public float DistanceFromPlayer = 20.0F; private Entity m_PlayerEntity; @@ -17,8 +18,10 @@ namespace Example { Mat4 transform = GetTransform(); + Vec3 playerTranstation = m_PlayerEntity.GetTransform().Translation; Vec3 translation = transform.Translation; - translation.XY = m_PlayerEntity.GetTransform().Translation.XY; + translation.XY = playerTranstation.XY; + translation.Z = playerTranstation.Z + DistanceFromPlayer; translation.Y = Math.Max(translation.Y, 4.5f); transform.Translation = translation; SetTransform(transform); diff --git a/ExampleApp/Src/PlayerSphere.cs b/ExampleApp/Src/PlayerSphere.cs new file mode 100644 index 0000000..06c28ca --- /dev/null +++ b/ExampleApp/Src/PlayerSphere.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Prism; + +namespace Example +{ + class PlayerSphere : Entity + { + public float HorizontalForce = 10.0f; + public float JumpForce = 10.0f; + + private RigidBodyComponent m_PhysicsBody; + private MaterialInstance m_MeshMaterial; + + public int m_CollisionCounter = 0; + + public Vec3 MaxSpeed = new Vec3(); + + private bool Colliding => m_CollisionCounter > 0; + + void OnCreate() + { + m_PhysicsBody = GetComponent(); + + MeshComponent meshComponent = GetComponent(); + m_MeshMaterial = meshComponent.Mesh.GetMaterial(0); + m_MeshMaterial.Set("u_Metalness", 0.0f); + + AddCollisionBeginCallback(OnPlayerCollisionBegin); + AddCollisionEndCallback(OnPlayerCollisionEnd); + } + + void OnPlayerCollisionBegin(float value) + { + m_CollisionCounter++; + } + + void OnPlayerCollisionEnd(float value) + { + m_CollisionCounter--; + } + + void OnUpdate(float ts) + { + float movementForce = HorizontalForce; + + if (!Colliding) + { + movementForce *= 0.4f; + } + + Vec3 forward = GetForwardDirection(); + Vec3 right = GetRightDirection(); + Vec3 up = GetUpDirection(); + + if (Input.IsKeyPressed(KeyCode.W)) + m_PhysicsBody.AddForce(forward * movementForce); + else if (Input.IsKeyPressed(KeyCode.S)) + m_PhysicsBody.AddForce(forward * -movementForce); + + if (Input.IsKeyPressed(KeyCode.D)) + m_PhysicsBody.AddForce(right * movementForce); + else if (Input.IsKeyPressed(KeyCode.A)) + m_PhysicsBody.AddForce(right * -movementForce); + + if (Colliding && Input.IsKeyPressed(KeyCode.Space)) + m_PhysicsBody.AddForce(up * JumpForce); + + if (Colliding) + m_MeshMaterial.Set("u_AlbedoColor", new Vec3(1.0f, 0.0f, 0.0f)); + else + m_MeshMaterial.Set("u_AlbedoColor", new Vec3(0.8f, 0.8f, 0.8f)); + + Vec3 linearVelocity = m_PhysicsBody.GetLinearVelocity(); + linearVelocity.Clamp(new Vec3(-MaxSpeed.X, -1000, -MaxSpeed.Z), MaxSpeed); + m_PhysicsBody.SetLinearVelocity(linearVelocity); + + if (Input.IsKeyPressed(KeyCode.R)) + { + Mat4 transform = GetTransform(); + transform.Translation = new Vec3(0.0f); + SetTransform(transform); + } + + } + + } +} diff --git a/Prism-ScriptCore/Src/Prism/Entity.cs b/Prism-ScriptCore/Src/Prism/Entity.cs index bb1dba9..3044e35 100644 --- a/Prism-ScriptCore/Src/Prism/Entity.cs +++ b/Prism-ScriptCore/Src/Prism/Entity.cs @@ -13,6 +13,8 @@ namespace Prism private List> m_Collision2DBeginCallbacks = new List>(); private List> m_Collision2DEndCallbacks = new List>(); + private Action m_CollisionBeginCallbacks; + private Action m_CollisionEndCallbacks; protected Entity() { ID = 0; } @@ -63,6 +65,24 @@ namespace Prism SetTransform_Native(ID, ref transform); } + public Vec3 GetForwardDirection() + { + GetForwardDirection_Native(ID, out Vec3 forward); + return forward; + } + + public Vec3 GetRightDirection() + { + GetRightDirection_Native(ID, out Vec3 right); + return right; + } + + public Vec3 GetUpDirection() + { + GetUpDirection_Native(ID, out Vec3 up); + return up; + } + public void AddCollision2DBeginCallback(Action callback) { m_Collision2DBeginCallbacks.Add(callback); @@ -73,6 +93,28 @@ namespace Prism m_Collision2DEndCallbacks.Add(callback); } + public void AddCollisionBeginCallback(Action callback) + { + m_CollisionBeginCallbacks += callback; + } + + public void AddCollisionEndCallback(Action callback) + { + m_CollisionEndCallbacks += callback; + } + + private void OnCollisionBegin(float data) + { + if (m_CollisionBeginCallbacks != null) + m_CollisionBeginCallbacks.Invoke(data); + } + + private void OnCollisionEnd(float data) + { + if (m_CollisionEndCallbacks != null) + m_CollisionEndCallbacks.Invoke(data); + } + private void OnCollision2DBegin(float data) { foreach (var callback in m_Collision2DBeginCallbacks) @@ -96,5 +138,11 @@ namespace Prism [MethodImpl(MethodImplOptions.InternalCall)] private static extern ulong FindEntityByTag_Native(string tag); + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern void GetForwardDirection_Native(ulong entityID, out Vec3 forward); + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern void GetRightDirection_Native(ulong entityID, out Vec3 right); + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern void GetUpDirection_Native(ulong entityID, out Vec3 up); } } diff --git a/Prism-ScriptCore/Src/Prism/Math/Mathf.cs b/Prism-ScriptCore/Src/Prism/Math/Mathf.cs new file mode 100644 index 0000000..5062a03 --- /dev/null +++ b/Prism-ScriptCore/Src/Prism/Math/Mathf.cs @@ -0,0 +1,15 @@ + +namespace Prism +{ + public static class Mathf + { + public static float Clamp(float value, float min, float max) + { + if (value < min) + return min; + if (value > max) + return max; + return value; + } + } +} diff --git a/Prism-ScriptCore/Src/Prism/Math/Vec3.cs b/Prism-ScriptCore/Src/Prism/Math/Vec3.cs index 6c94863..6ff2443 100644 --- a/Prism-ScriptCore/Src/Prism/Math/Vec3.cs +++ b/Prism-ScriptCore/Src/Prism/Math/Vec3.cs @@ -33,6 +33,23 @@ namespace Prism Z = vec.Z; } + public void Clamp(Vec3 min, Vec3 max) + { + X = Mathf.Clamp(X, min.X, max.X); + Y = Mathf.Clamp(Y, min.Y, max.Y); + Z = Mathf.Clamp(Z, min.Z, max.Z); + } + + public static Vec3 operator *(Vec3 left, float scalar) + { + return new Vec3(left.X * scalar, left.Y * scalar, left.Z * scalar); + } + + public static Vec3 operator *(float scalar, Vec3 right) + { + return new Vec3(scalar * right.X, scalar * right.Y, scalar * right.Z); + } + public Vec2 XY { get { return new Vec2(X, Y); } set { X = value.X; Y = value.Y; } diff --git a/Prism-ScriptCore/Src/Prism/Scene/Component.cs b/Prism-ScriptCore/Src/Prism/Scene/Component.cs index f965c74..a2e1611 100644 --- a/Prism-ScriptCore/Src/Prism/Scene/Component.cs +++ b/Prism-ScriptCore/Src/Prism/Scene/Component.cs @@ -123,4 +123,56 @@ namespace Prism public class BoxCollider2DComponent : Component { } + + public class BoxColliderComponent : Component + { + } + + public class SphereColliderComponent : Component + { + } + + public class RigidBodyComponent : Component + { + public enum ForceMode + { + Force = 0, + Impulse, + VelocityChange, + Acceleration + } + + public void AddForce(Vec3 force, ForceMode forceMode = ForceMode.Force) + { + AddForce_Native(Entity.ID, ref force, forceMode); + } + + public void AddTorque(Vec3 torque, ForceMode forceMode = ForceMode.Force) + { + AddTorque_Native(Entity.ID, ref torque, forceMode); + } + + public Vec3 GetLinearVelocity() + { + GetLinearVelocity_Native(Entity.ID, out Vec3 velocity); + return velocity; + } + + public void SetLinearVelocity(Vec3 velocity) + { + SetLinearVelocity_Native(Entity.ID, ref velocity); + } + + // TODO: Add SetMaxLinearVelocity() as well + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern void AddForce_Native(ulong entityID, ref Vec3 force, ForceMode forceMode); + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern void AddTorque_Native(ulong entityID, ref Vec3 torque, ForceMode forceMode); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern void GetLinearVelocity_Native(ulong entityID, out Vec3 velocity); + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern void SetLinearVelocity_Native(ulong entityID, ref Vec3 velocity); + } } diff --git a/Prism/CMakeLists.txt b/Prism/CMakeLists.txt index e5940fc..d4d05d2 100644 --- a/Prism/CMakeLists.txt +++ b/Prism/CMakeLists.txt @@ -45,6 +45,36 @@ file(GLOB IMGUIZMO_SOURCE ${IMGUIZMO_DIR}/*.cpp) list(APPEND SRC_SOURCE ${IMGUIZMO_SOURCE}) +# ------------- NVIDIA PhysX ------------- +# PhysX/physx/buildtools/presets/*.xml +# PX_GENERATE_STATIC_LIBRARIES=True +# NV_USE_STATIC_WINCRT=False + +set(PHYSX_BUILD_TYPE "checked" CACHE STRING "The build type of PhysX") +set_property(CACHE PHYSX_BUILD_TYPE PROPERTY STRINGS debug checked profile release) + +if(NOT CMAKE_BUILD_TYPE) + if(PHYSX_BUILD_TYPE STREQUAL "debug" OR PHYSX_BUILD_TYPE STREQUAL "checked") + set(CMAKE_BUILD_TYPE "Debug") + endif() +endif() + +if(CMAKE_BUILD_TYPE STREQUAL "Release") + set(PHYSX_BUILD_TYPE "release") +elseif (CMAKE_BUILD_TYPE STREQUAL "Debug") + set(PHYSX_BUILD_TYPE "debug") +endif () + +include_directories(vendor/PhysX/physx/include) +link_directories("vendor/PhysX/physx/bin/win.x86_64.vc143.md/${PHYSX_BUILD_TYPE}") # This is the path where PhysX libraries are installed + +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + message("Building snippet in debug with PhysX ${PHYSX_BUILD_TYPE} configuration") + add_compile_definitions(_DEBUG) +else() + message("Building snippet in release configuration with PhysX ${PHYSX_BUILD_TYPE} configuration") + add_compile_definitions(NDEBUG) +endif() # ------------- link libraries ------------- set(LINK_LIBRARIES_PRIVATE @@ -55,6 +85,13 @@ set(LINK_LIBRARIES_PRIVATE tinyFileDialogs FastNoise yaml-cpp + + PhysXExtensions_static_64 + PhysX_static_64 + PhysXPvdSDK_static_64 + PhysXCommon_static_64 + PhysXFoundation_static_64 + PhysXCooking_static_64 ) set(LINK_LIBRARIES_PUBLIC @@ -84,10 +121,11 @@ set(TARGET_INCLUDE_DIR # ------------- debug Defines ------------- set(DEBUG_DEFINITIONS $<$:PM_ENABLE_ASSERTS> + $<$:PM_ENABLE_ASSERTS> ) - # static library +# static library set(STATIC_LIBRARY ${PROJECT_NAME}-static) add_library(${STATIC_LIBRARY} STATIC ${SRC_SOURCE}) diff --git a/Prism/src/Prism/Core/Application.cpp b/Prism/src/Prism/Core/Application.cpp index 286a87b..64a3d6d 100644 --- a/Prism/src/Prism/Core/Application.cpp +++ b/Prism/src/Prism/Core/Application.cpp @@ -11,6 +11,7 @@ #include "Prism/Renderer/FrameBuffer.h" #include "tinyfiledialogs.h" +#include "Prism/Physics/Physics3D.h" #include "Prism/Script/ScriptEngine.h" namespace Prism @@ -35,6 +36,7 @@ namespace Prism PushOverlay(m_ImGuiLayer); ScriptEngine::Init("assets/scripts/ExampleApp.dll"); + Physics3D::Init(); Renderer::Init(); Renderer::WaitAndRender(); @@ -42,6 +44,10 @@ namespace Prism Application::~Application() { + for (Layer* layer : m_LayerStack) + layer->OnDetach(); + + Physics3D::Shutdown(); ScriptEngine::Shutdown(); } diff --git a/Prism/src/Prism/Core/Math/Noise.cpp b/Prism/src/Prism/Core/Math/Noise.cpp index 661c8ec..9e7f03b 100644 --- a/Prism/src/Prism/Core/Math/Noise.cpp +++ b/Prism/src/Prism/Core/Math/Noise.cpp @@ -14,7 +14,7 @@ namespace Prism float Noise::PerlinNoise(float x, float y) { s_FastNoise.SetNoiseType(FastNoise::Perlin); - float result = s_FastNoise.GetNoise(x, y); // This returns a value between -1 and 1 + const float result = s_FastNoise.GetNoise(x, y); // This returns a value between -1 and 1 return result; } } \ No newline at end of file diff --git a/Prism/src/Prism/Editor/SceneHierachyPanel.cpp b/Prism/src/Prism/Editor/SceneHierachyPanel.cpp index 6e50655..b5d2a40 100644 --- a/Prism/src/Prism/Editor/SceneHierachyPanel.cpp +++ b/Prism/src/Prism/Editor/SceneHierachyPanel.cpp @@ -135,6 +135,48 @@ namespace Prism ImGui::CloseCurrentPopup(); } } + if (!m_SelectionContext.HasComponent()) + { + if (ImGui::Button("Rigidbody")) + { + m_SelectionContext.AddComponent(); + ImGui::CloseCurrentPopup(); + } + } + if (!m_SelectionContext.HasComponent()) + { + if (ImGui::Button("Physics Material")) + { + m_SelectionContext.AddComponent(); + ImGui::CloseCurrentPopup(); + } + } + if (!m_SelectionContext.HasComponent()) + { + if (ImGui::Button("Box Collider")) + { + m_SelectionContext.AddComponent(); + ImGui::CloseCurrentPopup(); + } + } + if (!m_SelectionContext.HasComponent()) + { + if (ImGui::Button("Sphere Collider")) + { + m_SelectionContext.AddComponent(); + ImGui::CloseCurrentPopup(); + } + } + + if (!m_SelectionContext.HasComponent()) + { + if (ImGui::Button("Mesh Collider")) + { + m_SelectionContext.AddComponent(); + ImGui::CloseCurrentPopup(); + } + } + ImGui::EndPopup(); } } @@ -858,6 +900,101 @@ namespace Prism EndPropertyGrid(); }); + DrawComponent("Rigidbody", entity, [](RigidBodyComponent& rbc) + { + // Rigidbody Type + const char* rbTypeStrings[] = { "Static", "Dynamic", "Kinematic" }; + const char* currentType = rbTypeStrings[(int)rbc.BodyType]; + if (ImGui::BeginCombo("Type", currentType)) + { + for (int type = 0; type < 3; type++) + { + bool is_selected = (currentType == rbTypeStrings[type]); + if (ImGui::Selectable(rbTypeStrings[type], is_selected)) + { + currentType = rbTypeStrings[type]; + rbc.BodyType = (RigidBodyComponent::Type)type; + } + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } + + if (rbc.BodyType == RigidBodyComponent::Type::Dynamic) + { + BeginPropertyGrid(); + Property("Mass", rbc.Mass); + + if (ImGui::TreeNode("RigidBodyConstraints", "Constraints")) + { + Property("Position: X", rbc.LockPositionX); + Property("Position: Y", rbc.LockPositionY); + Property("Position: Z", rbc.LockPositionZ); + Property("Rotation: X", rbc.LockRotationX); + Property("Rotation: Y", rbc.LockRotationY); + Property("Rotation: Z", rbc.LockRotationZ); + + ImGui::TreePop(); + } + + EndPropertyGrid(); + } + }); + + DrawComponent("Physics Material", entity, [](PhysicsMaterialComponent& pmc) + { + BeginPropertyGrid(); + + Property("Static Friction", pmc.StaticFriction); + Property("Dynamic Friction", pmc.DynamicFriction); + Property("Bounciness", pmc.Bounciness); + + EndPropertyGrid(); + }); + + DrawComponent("Box Collider", entity, [](BoxColliderComponent& bcc) + { + BeginPropertyGrid(); + + Property("Size", bcc.Size); + //Property("Offset", bcc.Offset); + + EndPropertyGrid(); + }); + + DrawComponent("Sphere Collider", entity, [](SphereColliderComponent& scc) + { + BeginPropertyGrid(); + + Property("Radius", scc.Radius); + + EndPropertyGrid(); + }); + + DrawComponent("Mesh Collider", entity, [](MeshColliderComponent& mc) + { + ImGui::Columns(3); + ImGui::SetColumnWidth(0, 100); + ImGui::SetColumnWidth(1, 300); + ImGui::SetColumnWidth(2, 40); + ImGui::Text("File Path"); + ImGui::NextColumn(); + ImGui::PushItemWidth(-1); + if (mc.CollisionMesh) + ImGui::InputText("##meshfilepath", (char*)mc.CollisionMesh->GetFilePath().c_str(), 256, ImGuiInputTextFlags_ReadOnly); + else + ImGui::InputText("##meshfilepath", (char*)"Null", 256, ImGuiInputTextFlags_ReadOnly); + ImGui::PopItemWidth(); + ImGui::NextColumn(); + if (ImGui::Button("...##openmesh")) + { + std::string file = Application::Get().OpenFile(); + if (!file.empty()) + mc.CollisionMesh = Ref::Create(file); + } + }); + } diff --git a/Prism/src/Prism/Physics/Physics3D.cpp b/Prism/src/Prism/Physics/Physics3D.cpp new file mode 100644 index 0000000..63d3f46 --- /dev/null +++ b/Prism/src/Prism/Physics/Physics3D.cpp @@ -0,0 +1,203 @@ +// +// Created by sfd on 25-12-16. +// + +#include "Physics3D.h" + +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include +#include + +namespace Prism +{ + // TODO: Kinematic Actors + // TODO: Rotation/Position Locking + // TODO: Collision "layers" + // TODO: Expose more of the API to scripts + // TODO: Connect/Disconnect PVD + // TODO: Collider Shape Rendering + // TODO: Relative Transformations for scripts + + static physx::PxSimulationFilterShader s_DefaultFilterShader = physx::PxDefaultSimulationFilterShader; + + static std::tuple GetTransformDecomposition(const glm::mat4& transform) + { + glm::vec3 scale, translation, skew; + glm::vec4 perspective; + glm::quat orientation; + glm::decompose(transform, scale, orientation, translation, skew, perspective); + + return { translation, orientation, scale }; + } + + static physx::PxFilterFlags PrismFilterShader(physx::PxFilterObjectAttributes attributes0, physx::PxFilterData filterData0, physx::PxFilterObjectAttributes attributes1, physx::PxFilterData filterData1, physx::PxPairFlags& pairFlags, const void* constantBlock, physx::PxU32 constantBlockSize) + { + if (physx::PxFilterObjectIsTrigger(attributes0) || physx::PxFilterObjectIsTrigger(attributes1)) + { + pairFlags = physx::PxPairFlag::eTRIGGER_DEFAULT; + return physx::PxFilterFlag::eDEFAULT; + } + + pairFlags = physx::PxPairFlag::eCONTACT_DEFAULT; + + if ((filterData0.word0 & filterData1.word1) || (filterData1.word0 & filterData0.word1)) + { + pairFlags |= physx::PxPairFlag::eNOTIFY_TOUCH_FOUND; + pairFlags |= physx::PxPairFlag::eNOTIFY_TOUCH_LOST; + } + + return physx::PxFilterFlag::eDEFAULT; + } + + + void Physics3D::Init() + { + PM_CORE_ASSERT(!s_PXFoundation, "PhysXManager::Init shouldn't be called more than once!"); + + s_PXFoundation = PxCreateFoundation(PX_PHYSICS_VERSION, s_PXAllocator, s_PXErrorCallback); + PM_CORE_ASSERT(s_PXFoundation, "PxCreateFoundation Failed!"); + + PM_CORE_INFO("Try to connect PVD..."); + s_PXPvd = PxCreatePvd(*s_PXFoundation); + physx::PxPvdTransport* transport = physx::PxDefaultPvdSocketTransportCreate("localhost", 5425, 100000000); + const bool isConnect = s_PXPvd->connect(*transport, physx::PxPvdInstrumentationFlag::eALL); + if (isConnect) + { + PM_CORE_INFO("PVD connect success"); + }else + { + PM_CORE_ERROR("PVD connect failed"); + } + + s_PXPhysicsFactory = PxCreatePhysics(PX_PHYSICS_VERSION, *s_PXFoundation, physx::PxTolerancesScale(), true, isConnect ? s_PXPvd : nullptr); + PM_CORE_ASSERT(s_PXPhysicsFactory, "PxCreatePhysics Failed!"); + } + + void Physics3D::Shutdown() + { + s_PXPhysicsFactory->release(); + s_PXFoundation->release(); + } + + physx::PxSceneDesc Physics3D::CreateSceneDesc() + { + physx::PxSceneDesc sceneDesc(s_PXPhysicsFactory->getTolerancesScale()); + if (!sceneDesc.cpuDispatcher) + { + physx::PxDefaultCpuDispatcher* mCpuDispatcher = physx::PxDefaultCpuDispatcherCreate(4); + PM_CORE_ASSERT(mCpuDispatcher); + sceneDesc.cpuDispatcher = mCpuDispatcher; + } + + if (!sceneDesc.filterShader) + sceneDesc.filterShader = PrismFilterShader; + + return sceneDesc; + } + + physx::PxScene* Physics3D::CreateScene(const physx::PxSceneDesc& sceneDesc) + { + return s_PXPhysicsFactory->createScene(sceneDesc); + } + + physx::PxRigidActor* Physics3D::CreateAndAddActor(physx::PxScene* scene, const RigidBodyComponent& rigidbody, const glm::mat4& transform) + { + physx::PxRigidActor* actor = nullptr; + + if (rigidbody.BodyType == RigidBodyComponent::Type::Static) + { + actor = s_PXPhysicsFactory->createRigidStatic(CreatePose(transform)); + } + else if (rigidbody.BodyType == RigidBodyComponent::Type::Dynamic) + { + physx::PxRigidDynamic* dynamicActor = s_PXPhysicsFactory->createRigidDynamic(CreatePose(transform)); + physx::PxRigidBodyExt::updateMassAndInertia(*dynamicActor, rigidbody.Mass); + + dynamicActor->setRigidDynamicLockFlag(physx::PxRigidDynamicLockFlag::eLOCK_LINEAR_X, rigidbody.LockPositionX); + dynamicActor->setRigidDynamicLockFlag(physx::PxRigidDynamicLockFlag::eLOCK_LINEAR_Y, rigidbody.LockPositionY); + dynamicActor->setRigidDynamicLockFlag(physx::PxRigidDynamicLockFlag::eLOCK_LINEAR_Z, rigidbody.LockPositionZ); + dynamicActor->setRigidDynamicLockFlag(physx::PxRigidDynamicLockFlag::eLOCK_ANGULAR_X, rigidbody.LockRotationX); + dynamicActor->setRigidDynamicLockFlag(physx::PxRigidDynamicLockFlag::eLOCK_ANGULAR_Y, rigidbody.LockRotationY); + dynamicActor->setRigidDynamicLockFlag(physx::PxRigidDynamicLockFlag::eLOCK_ANGULAR_Z, rigidbody.LockRotationZ); + + actor = dynamicActor; + } + + actor->setActorFlag(physx::PxActorFlag::eVISUALIZATION, true); + + scene->addActor(*actor); + + return actor; + } + + physx::PxMaterial* Physics3D::CreateMaterial(float staticFriction, float dynamicFriction, float restitution) + { + return s_PXPhysicsFactory->createMaterial(staticFriction, dynamicFriction, restitution); + } + + physx::PxConvexMesh* Physics3D::CreateMeshCollider(const Ref& mesh) + { + const auto& vertices = mesh->GetStaticVertices(); + const auto& indices = mesh->GetIndices(); + const physx::PxCookingParams cookingParams(s_PXPhysicsFactory->getTolerancesScale()); + + physx::PxConvexMeshDesc convexDesc; + convexDesc.points.count = (physx::PxU32)vertices.size(); + convexDesc.points.stride = sizeof(Vertex); + convexDesc.points.data = vertices.data(); + convexDesc.flags = physx::PxConvexFlag::eCOMPUTE_CONVEX; + + const physx::PxDefaultMemoryOutputStream buf; + physx::PxConvexMeshCookingResult::Enum result; + + physx::PxConvexMesh* convexMesh = PxCreateConvexMesh( + cookingParams, // 第一步准备的烹饪参数 + convexDesc, // 第二步准备的网格描述 + *PxGetStandaloneInsertionCallback(), // 便捷的回调函数,用于将资源插入物理SDK + &result // [可选] 获取烹饪结果详情 + ); + if (!convexMesh) { + PM_CORE_ERROR("Failed to create convex mesh. Cooking result code: {}", static_cast(result)); + return nullptr; + } + + return convexMesh; + } + + physx::PxTransform Physics3D::CreatePose(const glm::mat4& transform) + { + auto [translation, rotationQuat, scale] = GetTransformDecomposition(transform); + const glm::vec3 rotation = glm::eulerAngles(rotationQuat); + + physx::PxTransform physxTransform(physx::PxVec3(translation.x, translation.y, translation.z)); + physxTransform.rotate(physx::PxVec3(rotation.x, rotation.y, rotation.z)); + return physxTransform; + } + + void Physics3D::SetCollisionFilters(physx::PxRigidActor* actor, uint32_t filterGroup, uint32_t filterMask) + { + physx::PxFilterData filterData; + filterData.word0 = filterGroup; // word0 = own ID + filterData.word1 = filterMask; // word1 = ID mask to filter pairs that trigger a + // contact callback; + const physx::PxU32 numShapes = actor->getNbShapes(); + physx::PxShape** shapes = (physx::PxShape**)s_PXAllocator.allocate(sizeof(physx::PxShape*) * numShapes, "", "", 0); + actor->getShapes(shapes, numShapes); + for (physx::PxU32 i = 0; i < numShapes; i++) + { + physx::PxShape* shape = shapes[i]; + shape->setFlag(physx::PxShapeFlag::eVISUALIZATION, true); + shape->setSimulationFilterData(filterData); + } + + s_PXAllocator.deallocate(shapes); + } + + physx::PxDefaultErrorCallback Physics3D::s_PXErrorCallback; + physx::PxDefaultAllocator Physics3D::s_PXAllocator; + physx::PxFoundation* Physics3D::s_PXFoundation; + physx::PxPhysics* Physics3D::s_PXPhysicsFactory; + physx::PxPvd* Physics3D::s_PXPvd; +} \ No newline at end of file diff --git a/Prism/src/Prism/Physics/Physics3D.h b/Prism/src/Prism/Physics/Physics3D.h new file mode 100644 index 0000000..59deea3 --- /dev/null +++ b/Prism/src/Prism/Physics/Physics3D.h @@ -0,0 +1,56 @@ +// +// Created by sfd on 25-12-16. +// + +#ifndef PHYSXMANAGER_H +#define PHYSXMANAGER_H +#define PX_PHYSX_STATIC_LIB +#include +#include "glm/glm.hpp" +#include "Prism/Scene/Components.h" + +namespace Prism +{ + enum class ForceMode : uint16_t + { + Force = 0, + Impulse, + VelocityChange, + Acceleration + }; + + enum class FilterGroup : uint32_t + { + Static = BIT(0), + Dynamic = BIT(1), + Kinematic = BIT(2), + All = Static | Dynamic | Kinematic + }; + + class PRISM_API Physics3D + { + public: + static void Init(); + static void Shutdown(); + + static physx::PxSceneDesc CreateSceneDesc(); + static physx::PxScene* CreateScene(const physx::PxSceneDesc& sceneDesc); + static physx::PxRigidActor* CreateAndAddActor(physx::PxScene* scene, const RigidBodyComponent& rigidbody, const glm::mat4& transform); + static physx::PxMaterial* CreateMaterial(float staticFriction, float dynamicFriction, float restitution); + static physx::PxConvexMesh* CreateMeshCollider(const Ref& mesh); + + static physx::PxTransform CreatePose(const glm::mat4& transform); + + static void SetCollisionFilters(physx::PxRigidActor* actor, uint32_t filterGroup, uint32_t filterMask); + + // private: + static physx::PxDefaultErrorCallback s_PXErrorCallback; + static physx::PxDefaultAllocator s_PXAllocator; + static physx::PxFoundation* s_PXFoundation; + static physx::PxPhysics* s_PXPhysicsFactory; + static physx::PxPvd* s_PXPvd; + }; +} + + +#endif //PHYSXMANAGER_H diff --git a/Prism/src/Prism/Renderer/Mesh.h b/Prism/src/Prism/Renderer/Mesh.h index aee4a26..d986578 100644 --- a/Prism/src/Prism/Renderer/Mesh.h +++ b/Prism/src/Prism/Renderer/Mesh.h @@ -115,6 +115,9 @@ namespace Prism std::vector& GetSubmeshes() { return m_Submeshes; } const std::vector& GetSubmeshes() const { return m_Submeshes; } + const std::vector& GetStaticVertices() const { return m_StaticVertices; } + const std::vector& GetIndices() const { return m_Indices; } + inline Ref GetMeshShader() { return m_MeshShader; } inline Ref GetMaterial() { return m_BaseMaterial; } std::vector>& GetMaterials() { return m_Materials; } diff --git a/Prism/src/Prism/Scene/Components.h b/Prism/src/Prism/Scene/Components.h index f08a2ef..2ff10d7 100644 --- a/Prism/src/Prism/Scene/Components.h +++ b/Prism/src/Prism/Scene/Components.h @@ -137,6 +137,81 @@ namespace Prism CircleCollider2DComponent() = default; CircleCollider2DComponent(const CircleCollider2DComponent& other) = default; }; + + + struct SphereColliderComponent + { + float Radius = 1.0f; + + // TODO: Physics Material + + SphereColliderComponent() = default; + SphereColliderComponent(const SphereColliderComponent& other) = default; + }; + + struct RigidBodyComponent + { + enum class Type { Static, Dynamic, Kinematic }; + Type BodyType; + float Mass = 1.0f; + + bool LockPositionX = false; + bool LockPositionY = false; + bool LockPositionZ = false; + bool LockRotationX = false; + bool LockRotationY = false; + bool LockRotationZ = false; + + void* RuntimeActor = nullptr; + + RigidBodyComponent() = default; + RigidBodyComponent(const RigidBodyComponent& other) = default; + }; + + // TODO: This will eventually be a resource, but that requires object referencing through the editor + struct PhysicsMaterialComponent + { + float StaticFriction = 1.0f; + float DynamicFriction = 1.0f; + float Bounciness = 1.0f; + + PhysicsMaterialComponent() = default; + PhysicsMaterialComponent(const PhysicsMaterialComponent& other) = default; + }; + + struct BoxColliderComponent + { + glm::vec3 Size = { 1.0f, 1.0f, 1.0f }; + glm::vec3 Offset = { 0.0f, 0.0f, 0.0f }; + + BoxColliderComponent() = default; + BoxColliderComponent(const BoxColliderComponent& other) = default; + }; + + struct CapsuleColliderComponent + { + float Radius = 0.5f; + float Height = 1.0f; + + CapsuleColliderComponent() = default; + CapsuleColliderComponent(const CapsuleColliderComponent& other) = default; + }; + + struct MeshColliderComponent + { + Ref CollisionMesh; + + MeshColliderComponent() = default; + MeshColliderComponent(const MeshColliderComponent& other) = default; + MeshColliderComponent(const Ref& mesh) + : CollisionMesh(mesh) + { + } + + operator Ref() { return CollisionMesh; } + }; + + } diff --git a/Prism/src/Prism/Scene/Scene.cpp b/Prism/src/Prism/Scene/Scene.cpp index 191e258..3f9c42a 100644 --- a/Prism/src/Prism/Scene/Scene.cpp +++ b/Prism/src/Prism/Scene/Scene.cpp @@ -14,15 +14,18 @@ #include #include +#include "Prism/Physics/Physics3D.h" + namespace Prism { // TODO: THIS SHOULD MOVE TO PHYSICS FILE! - - - std::unordered_map s_ActiveScenes; + static physx::PxDefaultErrorCallback s_PXErrorCallback; + static physx::PxDefaultAllocator s_PXAllocator; + static physx::PxFoundation* s_PXFoundation; + static uint32_t s_SceneIDCounter = 0; struct SceneComponent @@ -42,6 +45,13 @@ namespace Prism } }; + struct PhysXSceneComponent + { + // NOTE: PhysX does some internal ref counting, and thus doesn't allow unique_ptr + physx::PxScene* World; + }; + + void ProcessContactEvents(const b2WorldId worldId) { const b2ContactEvents contactEvents = b2World_GetContactEvents(worldId); @@ -75,6 +85,65 @@ namespace Prism } } + class PhysXContactListener : public physx::PxSimulationEventCallback + { + public: + virtual void onConstraintBreak(physx::PxConstraintInfo* constraints, physx::PxU32 count) override + { + PX_UNUSED(constraints); + PX_UNUSED(count); + } + + virtual void onWake(physx::PxActor** actors, physx::PxU32 count) override + { + PX_UNUSED(actors); + PX_UNUSED(count); + } + + virtual void onSleep(physx::PxActor** actors, physx::PxU32 count) override + { + PX_UNUSED(actors); + PX_UNUSED(count); + } + + virtual void onContact(const physx::PxContactPairHeader& pairHeader, const physx::PxContactPair* pairs, physx::PxU32 nbPairs) override + { + Entity& a = *(Entity*)pairHeader.actors[0]->userData; + Entity& b = *(Entity*)pairHeader.actors[1]->userData; + + if (pairs->flags == physx::PxContactPairFlag::eACTOR_PAIR_HAS_FIRST_TOUCH) + { + if (a.HasComponent() && ScriptEngine::ModuleExists(a.GetComponent().ModuleName)) + ScriptEngine::OnCollisionBegin(a); + + if (b.HasComponent() && ScriptEngine::ModuleExists(b.GetComponent().ModuleName)) + ScriptEngine::OnCollisionBegin(b); + } + else if (pairs->flags == physx::PxContactPairFlag::eACTOR_PAIR_LOST_TOUCH) + { + if (a.HasComponent() && ScriptEngine::ModuleExists(a.GetComponent().ModuleName)) + ScriptEngine::OnCollisionEnd(a); + + if (b.HasComponent() && ScriptEngine::ModuleExists(b.GetComponent().ModuleName)) + ScriptEngine::OnCollisionEnd(b); + } + } + + virtual void onTrigger(physx::PxTriggerPair* pairs, physx::PxU32 count) override + { + PX_UNUSED(pairs); + PX_UNUSED(count); + } + + virtual void onAdvance(const physx::PxRigidBody* const* bodyBuffer, const physx::PxTransform* poseBuffer, const physx::PxU32 count) override + { + PX_UNUSED(bodyBuffer); + PX_UNUSED(poseBuffer); + PX_UNUSED(count); + } + }; + + static PhysXContactListener s_PhysXContactListener; void OnTransformConstruct(entt::registry& registry, entt::entity entity) @@ -134,6 +203,26 @@ namespace Prism s_ActiveScenes[m_SceneID] = this; + + physx::PxSceneDesc sceneDesc = Physics3D::CreateSceneDesc(); + sceneDesc.gravity = physx::PxVec3(0.0f, -9.8f, 0.0f); + sceneDesc.simulationEventCallback = &s_PhysXContactListener; + + const PhysXSceneComponent& physxWorld = m_Registry.emplace(m_SceneEntity, Physics3D::CreateScene(sceneDesc)); + physx::PxPvdSceneClient* pvdClient = physxWorld.World->getScenePvdClient(); + if(pvdClient) + { + pvdClient->setScenePvdFlag(physx::PxPvdSceneFlag::eTRANSMIT_CONSTRAINTS, true); + pvdClient->setScenePvdFlag(physx::PxPvdSceneFlag::eTRANSMIT_CONTACTS, true); + pvdClient->setScenePvdFlag(physx::PxPvdSceneFlag::eTRANSMIT_SCENEQUERIES, true); + }else + { + PM_CORE_WARN("you are using pvd to debug: "); + PM_CORE_WARN("PvdSceneClient is null is pvd running or you are using release/profile PhysX?"); + PM_CORE_WARN("to using Pvd, should using debug/checked version to build!"); + } + PM_CORE_ASSERT(physxWorld.World); + Init(); } @@ -147,11 +236,20 @@ namespace Prism void Scene::Init() { - auto skyboxShader = Shader::Create("assets/shaders/Skybox.glsl"); + const auto skyboxShader = Shader::Create("assets/shaders/Skybox.glsl"); m_SkyboxMaterial = MaterialInstance::Create(Material::Create(skyboxShader)); m_SkyboxMaterial->SetFlag(MaterialFlag::DepthTest, false); } + void Scene::OnShutdown() + { + auto b2WorldView = m_Registry.view(); + b2DestroyWorld(m_Registry.get(m_SceneEntity).World); + + auto physxView = m_Registry.view(); + m_Registry.get(m_SceneEntity).World->release(); + } + void Scene::OnUpdate(TimeStep ts) { // Update all entities @@ -175,16 +273,8 @@ namespace Prism // box2DWorld->Step(ts, velocityIterations, positionIterations); b2World_Step(box2DWorld, ts, positionIterations); - { - ProcessContactEvents(box2DWorld); - /* - const b2ContactEvents contactEvents = b2World_GetContactEvents(box2DWorld); - if (contactEvents.beginCount > 0) - PM_CORE_WARN("collision box counts in begin: {}", contactEvents.beginCount); - if (contactEvents.endCount > 0) - PM_CORE_WARN("collision box counts in end: {}", contactEvents.endCount); - */ - } + // Process Contact Envents box2d version 3.0^ should impl contact event after b2World_Step + ProcessContactEvents(box2DWorld); { const auto view = m_Registry.view(); @@ -206,6 +296,65 @@ namespace Prism } } + // PhysX Physics + auto physxView = m_Registry.view(); + physx::PxScene* physxScene = m_Registry.get(physxView.front()).World; + + constexpr float stepSize = 0.016666660f; + physxScene->simulate(stepSize); + physxScene->fetchResults(true); + + { + auto view = m_Registry.view(); + for (auto entity : view) + { + Entity e = { entity, this }; + auto& transform = e.Transform(); + RigidBodyComponent& rb = e.GetComponent(); + physx::PxRigidActor* actor = static_cast(rb.RuntimeActor); + const auto& position = actor->getGlobalPose().p; + const physx::PxQuat& physicsBodyRotation = actor->getGlobalPose().q; + + auto [translation, rotationQuat, scale] = GetTransformDecomposition(transform); + + if (rb.BodyType == RigidBodyComponent::Type::Dynamic) + { + /* + // If the rigidbody is dynamic, the position of the entity is determined by the rigidbody + // TODO: Get rotation from RigidActor + float xAngle, yAngle, zAngle; + physx::PxVec3 axis; + physicsBodyRotation.toRadiansAndUnitAxis(xAngle, axis); + physicsBodyRotation.toRadiansAndUnitAxis(yAngle, axis); + physicsBodyRotation.toRadiansAndUnitAxis(zAngle, axis); + + transform = glm::translate(glm::mat4(1.0f), { position.x, position.y, position.z }) * + glm::toMat4(glm::quat({ xAngle, yAngle, zAngle })) * + glm::scale(glm::mat4(1.0f), scale); + */ + + // 获取物理引擎的位置和旋转 + physx::PxTransform globalPose = actor->getGlobalPose(); + const physx::PxVec3& pos = globalPose.p; + const physx::PxQuat& physicsQuat = globalPose.q; + + glm::quat glmQuat{physicsQuat.w, physicsQuat.x, physicsQuat.y, physicsQuat.z}; + + // 使用转换后的四元数创建变换矩阵 + transform = glm::translate(glm::mat4(1.0f), + glm::vec3(pos.x, pos.y, pos.z)) * + glm::toMat4(glmQuat) * + glm::scale(glm::mat4(1.0f), scale); + + } + else if (rb.BodyType == RigidBodyComponent::Type::Static) + { + // If the rigidbody is static, make sure the actor is at the entitys position + actor->setGlobalPose(Physics3D::CreatePose(transform)); + } + } + } + } void Scene::OnRenderRuntime(TimeStep ts) @@ -328,7 +477,7 @@ namespace Prism auto& world = m_Registry.get(sceneView.front()).World; { auto view = m_Registry.view(); - m_PhysicsBodyEntityBuffer = new Entity[view.size()]; + m_Physics2DBodyEntityBuffer = new Entity[view.size()]; uint32_t physicsBodyEntityBufferIndex = 0; for (auto entity : view) { @@ -353,7 +502,7 @@ namespace Prism // box2D fixRotation renamed to motionlocks bodyDef.motionLocks = b2MotionLocks{false, false, rigidBody2D.FixedRotation}; - Entity* entityStorage = &m_PhysicsBodyEntityBuffer[physicsBodyEntityBufferIndex++]; + Entity* entityStorage = &m_Physics2DBodyEntityBuffer[physicsBodyEntityBufferIndex++]; *entityStorage = e; bodyDef.userData = entityStorage; @@ -420,12 +569,161 @@ namespace Prism } + auto physxView = m_Registry.view(); + physx::PxScene* physxWorld = m_Registry.get(physxView.front()).World; + + { + auto view = m_Registry.view(); + m_Physics3DBodyEntityBuffer = new Entity[view.size()]; + uint32_t physicsBodyEntityBufferIndex = 0; + + for (auto entity : view) + { + Entity e = { entity, this }; + UUID entityID = e.GetComponent().ID; + auto& transform = e.Transform(); + auto& rigidbody = m_Registry.get(entity); + + physx::PxRigidActor* actor = Physics3D::CreateAndAddActor(physxWorld, rigidbody, transform); + PM_CORE_ASSERT(actor); + + Entity* entityStorage = &m_Physics3DBodyEntityBuffer[physicsBodyEntityBufferIndex++]; + *entityStorage = e; + actor->userData = (void*)entityStorage; + + rigidbody.RuntimeActor = actor; + } + } + + { + auto view = m_Registry.view(); + for (auto entity : view) + { + Entity e = { entity, this }; + auto& transform = e.Transform(); + + auto& boxCollider = m_Registry.get(entity); + if (e.HasComponent()) + { + auto& rigidBody = e.GetComponent(); + auto& physicsMaterial = e.GetComponent(); + PM_CORE_ASSERT(rigidBody.RuntimeActor); + physx::PxRigidActor* actor = static_cast(rigidBody.RuntimeActor); + + physx::PxBoxGeometry boxGeometry = physx::PxBoxGeometry(boxCollider.Size.x / 2.0F, boxCollider.Size.y / 2.0F, boxCollider.Size.z / 2.0F); + physx::PxMaterial* material = Physics3D::CreateMaterial(physicsMaterial.StaticFriction, physicsMaterial.DynamicFriction, physicsMaterial.Bounciness); + physx::PxShape* shape = physx::PxRigidActorExt::createExclusiveShape(*actor, boxGeometry, *material); + shape->setLocalPose(Physics3D::CreatePose(glm::translate(glm::mat4(1.0F), boxCollider.Offset))); + } + } + } + + { + auto view = m_Registry.view(); + for (auto entity : view) + { + Entity e = { entity, this }; + auto& transform = e.Transform(); + + auto& sphereCollider = m_Registry.get(entity); + if (e.HasComponent()) + { + auto& rigidBody = e.GetComponent(); + auto& physicsMaterial = e.GetComponent(); + PM_CORE_ASSERT(rigidBody.RuntimeActor); + physx::PxRigidActor* actor = static_cast(rigidBody.RuntimeActor); + physx::PxSphereGeometry sphereGeometry = physx::PxSphereGeometry(sphereCollider.Radius); + physx::PxMaterial* material = Physics3D::CreateMaterial(physicsMaterial.StaticFriction, physicsMaterial.DynamicFriction, physicsMaterial.Bounciness); + physx::PxRigidActorExt::createExclusiveShape(*actor, sphereGeometry, *material); + + physx::PxRigidDynamic* rigidBodyActor = actor->is(); + + if (rigidBodyActor) + { + rigidBodyActor->setRigidDynamicLockFlag(physx::PxRigidDynamicLockFlag::eLOCK_ANGULAR_X, true); + rigidBodyActor->setRigidDynamicLockFlag(physx::PxRigidDynamicLockFlag::eLOCK_ANGULAR_Y, true); + rigidBodyActor->setRigidDynamicLockFlag(physx::PxRigidDynamicLockFlag::eLOCK_ANGULAR_Z, true); + } + } + } + } + + { + auto view = m_Registry.view(); + for (auto entity : view) + { + Entity e = { entity, this }; + auto& transform = e.Transform(); + + auto& capsuleCollider = m_Registry.get(entity); + if (e.HasComponent()) + { + auto& rigidBody = e.GetComponent(); + auto& physicsMaterial = e.GetComponent(); + PM_CORE_ASSERT(rigidBody.RuntimeActor); + physx::PxRigidActor* actor = static_cast(rigidBody.RuntimeActor); + physx::PxCapsuleGeometry capsuleGeometry = physx::PxCapsuleGeometry(capsuleCollider.Radius, capsuleCollider.Height / 2.0F); + physx::PxMaterial* material = Physics3D::CreateMaterial(physicsMaterial.StaticFriction, physicsMaterial.DynamicFriction, physicsMaterial.Bounciness); + physx::PxShape* shape = physx::PxRigidActorExt::createExclusiveShape(*actor, capsuleGeometry, *material); + + // Make sure that the capsule is facing up (+Y) + shape->setLocalPose(physx::PxTransform(physx::PxQuat(physx::PxHalfPi, physx::PxVec3(0, 0, 1)))); + } + } + } + + { + auto meshView = m_Registry.view(); + for (auto entity : meshView) + { + Entity e = { entity, this }; + auto& transform = e.Transform(); + + auto& meshCollider = m_Registry.get(entity); + if (e.HasComponent()) + { + auto& rigidBody = e.GetComponent(); + auto& physicsMaterial = e.GetComponent(); + PM_CORE_ASSERT(rigidBody.RuntimeActor); + physx::PxRigidActor* actor = static_cast(rigidBody.RuntimeActor); + + physx::PxConvexMesh* triangleMesh = Physics3D::CreateMeshCollider(meshCollider); + PM_CORE_ASSERT(triangleMesh); + + physx::PxConvexMeshGeometry triangleGeometry = physx::PxConvexMeshGeometry(triangleMesh); + physx::PxMaterial* material = Physics3D::CreateMaterial(physicsMaterial.StaticFriction, physicsMaterial.DynamicFriction, physicsMaterial.Bounciness); + physx::PxRigidActorExt::createExclusiveShape(*actor, triangleGeometry, *material); + } + } + + // Setup Collision Filters + auto rbView = m_Registry.view(); + for (auto entity : rbView) + { + Entity e = { entity, this }; + auto& rigidBody = e.GetComponent(); + PM_CORE_ASSERT(rigidBody.RuntimeActor); + physx::PxRigidActor* actor = static_cast(rigidBody.RuntimeActor); + + if (rigidBody.BodyType == RigidBodyComponent::Type::Static) + Physics3D::SetCollisionFilters(actor, (uint32_t)FilterGroup::Static, (uint32_t)FilterGroup::All); + else if (rigidBody.BodyType == RigidBodyComponent::Type::Dynamic) + Physics3D::SetCollisionFilters(actor, (uint32_t)FilterGroup::Dynamic, (uint32_t)FilterGroup::All); + } + } + + m_IsPlaying = true; } void Scene::OnRuntimeStop() { - delete[] m_PhysicsBodyEntityBuffer; + auto physxView = m_Registry.view(); + m_Registry.get(m_SceneEntity).World->release(); + + + delete[] m_Physics3DBodyEntityBuffer; + delete[] m_Physics2DBodyEntityBuffer; m_IsPlaying = false; } @@ -534,6 +832,11 @@ namespace Prism CopyComponentIfExists(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); CopyComponentIfExists(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); CopyComponentIfExists(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); + CopyComponentIfExists(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); + CopyComponentIfExists(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); + CopyComponentIfExists(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); + CopyComponentIfExists(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); + CopyComponentIfExists(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); } Entity Scene::FindEntityByTag(const std::string &tag) { @@ -577,6 +880,11 @@ namespace Prism CopyComponent(target->m_Registry, m_Registry, enttMap); CopyComponent(target->m_Registry, m_Registry, enttMap); CopyComponent(target->m_Registry, m_Registry, enttMap); + CopyComponent(target->m_Registry, m_Registry, enttMap); + CopyComponent(target->m_Registry, m_Registry, enttMap); + CopyComponent(target->m_Registry, m_Registry, enttMap); + CopyComponent(target->m_Registry, m_Registry, enttMap); + CopyComponent(target->m_Registry, m_Registry, enttMap); const auto& entityInstanceMap = ScriptEngine::GetEntityInstanceMap(); if (entityInstanceMap.find(target->GetUUID()) != entityInstanceMap.end()) diff --git a/Prism/src/Prism/Scene/Scene.h b/Prism/src/Prism/Scene/Scene.h index 1069078..8fa00e6 100644 --- a/Prism/src/Prism/Scene/Scene.h +++ b/Prism/src/Prism/Scene/Scene.h @@ -44,6 +44,7 @@ namespace Prism ~Scene(); void Init(); + void OnShutdown(); void OnUpdate(TimeStep ts); void OnRenderRuntime(TimeStep ts); @@ -109,7 +110,8 @@ namespace Prism EntityMap m_EntityIDMap; entt::entity m_SelectedEntity; - Entity* m_PhysicsBodyEntityBuffer = nullptr; + Entity* m_Physics2DBodyEntityBuffer = nullptr; + Entity* m_Physics3DBodyEntityBuffer = nullptr; Light m_Light; float m_LightMultiplier = 0.3f; diff --git a/Prism/src/Prism/Scene/SceneSerializer.cpp b/Prism/src/Prism/Scene/SceneSerializer.cpp index b25f1ac..7a88d2d 100644 --- a/Prism/src/Prism/Scene/SceneSerializer.cpp +++ b/Prism/src/Prism/Scene/SceneSerializer.cpp @@ -329,6 +329,77 @@ namespace Prism out << YAML::EndMap; // CircleCollider2DComponent } + if (entity.HasComponent()) + { + out << YAML::Key << "RigidBodyComponent"; + out << YAML::BeginMap; // RigidBodyComponent + + auto& rigidbodyComponent = entity.GetComponent(); + out << YAML::Key << "BodyType" << YAML::Value << (int)rigidbodyComponent.BodyType; + out << YAML::Key << "Mass" << YAML::Value << rigidbodyComponent.Mass; + + out << YAML::Key << "Constraints"; + out << YAML::BeginMap; // Constraints + + out << YAML::Key << "LockPositionX" << YAML::Value << rigidbodyComponent.LockPositionX; + out << YAML::Key << "LockPositionY" << YAML::Value << rigidbodyComponent.LockPositionY; + out << YAML::Key << "LockPositionZ" << YAML::Value << rigidbodyComponent.LockPositionZ; + out << YAML::Key << "LockRotationX" << YAML::Value << rigidbodyComponent.LockRotationX; + out << YAML::Key << "LockRotationY" << YAML::Value << rigidbodyComponent.LockRotationY; + out << YAML::Key << "LockRotationZ" << YAML::Value << rigidbodyComponent.LockRotationZ; + + out << YAML::EndMap; + + out << YAML::EndMap; // RigidBodyComponent + } + + if (entity.HasComponent()) + { + out << YAML::Key << "PhysicsMaterialComponent"; + out << YAML::BeginMap; // PhysicsMaterialComponent + + auto& physicsMaterial = entity.GetComponent(); + out << YAML::Key << "StaticFriction" << YAML::Value << physicsMaterial.StaticFriction; + out << YAML::Key << "DynamicFriction" << YAML::Value << physicsMaterial.DynamicFriction; + out << YAML::Key << "Bounciness" << YAML::Value << physicsMaterial.Bounciness; + + out << YAML::EndMap; + } + + if (entity.HasComponent()) + { + out << YAML::Key << "BoxColliderComponent"; + out << YAML::BeginMap; // BoxColliderComponent + + auto& boxColliderComponent = entity.GetComponent(); + out << YAML::Key << "Offset" << YAML::Value << boxColliderComponent.Offset; + out << YAML::Key << "Size" << YAML::Value << boxColliderComponent.Size; + + out << YAML::EndMap; // BoxColliderComponent + } + + if (entity.HasComponent()) + { + out << YAML::Key << "SphereColliderComponent"; + out << YAML::BeginMap; // SphereColliderComponent + + auto& sphereColliderComponent = entity.GetComponent(); + out << YAML::Key << "Radius" << YAML::Value << sphereColliderComponent.Radius; + + out << YAML::EndMap; // SphereColliderComponent + } + + if (entity.HasComponent()) + { + out << YAML::Key << "MeshColliderComponent"; + out << YAML::BeginMap; // MeshColliderComponent + + auto mesh = entity.GetComponent().CollisionMesh; + out << YAML::Key << "AssetPath" << YAML::Value << mesh->GetFilePath(); + + out << YAML::EndMap; // MeshColliderComponent + } + out << YAML::EndMap; // Entity } @@ -562,6 +633,49 @@ namespace Prism component.Density = circleCollider2DComponent["Density"] ? circleCollider2DComponent["Density"].as() : 1.0f; component.Friction = circleCollider2DComponent["Friction"] ? circleCollider2DComponent["Friction"].as() : 1.0f; } + + if (auto rigidBodyComponent = entity["RigidBodyComponent"]) + { + auto& component = deserializedEntity.AddComponent(); + component.BodyType = (RigidBodyComponent::Type)rigidBodyComponent["BodyType"].as(); + component.Mass = rigidBodyComponent["Mass"].as(); + + component.LockPositionX = rigidBodyComponent["LockPositionX"] ? rigidBodyComponent["LockPositionX"].as() : false; + component.LockPositionY = rigidBodyComponent["LockPositionY"] ? rigidBodyComponent["LockPositionY"].as() : false; + component.LockPositionZ = rigidBodyComponent["LockPositionZ"] ? rigidBodyComponent["LockPositionZ"].as() : false; + component.LockRotationX = rigidBodyComponent["LockRotationX"] ? rigidBodyComponent["LockRotationX"].as() : false; + component.LockRotationY = rigidBodyComponent["LockRotationY"] ? rigidBodyComponent["LockRotationY"].as() : false; + component.LockRotationZ = rigidBodyComponent["LockRotationZ"] ? rigidBodyComponent["LockRotationZ"].as() : false; + } + + if (auto physicsMaterialComponent = entity["PhysicsMaterialComponent"]) + { + auto& component = deserializedEntity.AddComponent(); + component.StaticFriction = physicsMaterialComponent["StaticFriction"].as(); + component.DynamicFriction = physicsMaterialComponent["DynamicFriction"].as(); + component.Bounciness = physicsMaterialComponent["Bounciness"].as(); + } + + if (auto boxColliderComponent = entity["BoxColliderComponent"]) + { + auto& component = deserializedEntity.AddComponent(); + component.Offset = boxColliderComponent["Offset"].as(); + component.Size = boxColliderComponent["Size"].as(); + } + + if (auto sphereColliderComponent = entity["SphereColliderComponent"]) + { + auto& component = deserializedEntity.AddComponent(); + component.Radius = sphereColliderComponent["Radius"].as(); + } + + if (auto meshColliderComponent = entity["MeshColliderComponent"]) + { + auto meshPath = meshColliderComponent["AssetPath"].as(); + deserializedEntity.AddComponent(Ref::Create(meshPath)); + + PM_CORE_INFO(" Mesh Collider Asset Path: {0}", meshPath); + } } } return true; diff --git a/Prism/src/Prism/Script/ScriptEngine.cpp b/Prism/src/Prism/Script/ScriptEngine.cpp index e019ca5..68b0eac 100644 --- a/Prism/src/Prism/Script/ScriptEngine.cpp +++ b/Prism/src/Prism/Script/ScriptEngine.cpp @@ -20,6 +20,8 @@ #include "imgui.h" +#define ENABLE_MONO_DEBUG + namespace Prism { static MonoDomain* s_MonoDomain = nullptr; @@ -48,6 +50,8 @@ namespace Prism MonoMethod* OnUpdateMethod = nullptr; // Physics + MonoMethod* OnCollisionBeginMethod = nullptr; + MonoMethod* OnCollisionEndMethod = nullptr; MonoMethod* OnCollision2DBeginMethod = nullptr; MonoMethod* OnCollision2DEndMethod = nullptr; @@ -59,6 +63,9 @@ namespace Prism // Physics (Entity class) OnCollision2DBeginMethod = GetMethod(s_CoreAssemblyImage, "Prism.Entity:OnCollision2DBegin(single)"); OnCollision2DEndMethod = GetMethod(s_CoreAssemblyImage, "Prism.Entity:OnCollision2DEnd(single)"); + OnCollisionBeginMethod = GetMethod(s_CoreAssemblyImage, "Prism.Entity:OnCollisionBegin(single)"); + OnCollisionEndMethod = GetMethod(s_CoreAssemblyImage, "Prism.Entity:OnCollisionEnd(single)"); + } }; @@ -423,6 +430,7 @@ namespace Prism auto& dstModuleFieldMap = dstEntityMap[entityID].ModuleFieldMap; for (auto& [fieldName, field] : srcFieldMap) { + volatile auto name = fieldName; PM_CORE_ASSERT(dstModuleFieldMap.find(moduleName) != dstModuleFieldMap.end()); auto& fieldMap = dstModuleFieldMap.at(moduleName); PM_CORE_ASSERT(fieldMap.find(fieldName) != fieldMap.end()); @@ -488,6 +496,38 @@ namespace Prism } + void ScriptEngine::OnCollisionBegin(Entity entity) + { + OnCollisionBegin(entity.m_Scene->GetUUID(), entity.GetComponent().ID); + } + + void ScriptEngine::OnCollisionBegin(const UUID& sceneID, const UUID& entityID) + { + EntityInstance& entityInstance = GetEntityInstanceData(sceneID, entityID).Instance; + if (entityInstance.ScriptClass->OnCollisionBeginMethod) + { + float value = 5.0f; + void* args[] = { &value }; + CallMethod(entityInstance.GetInstance(), entityInstance.ScriptClass->OnCollisionBeginMethod, args); + } + } + + void ScriptEngine::OnCollisionEnd(Entity entity) + { + OnCollisionEnd(entity.m_Scene->GetUUID(), entity.GetComponent().ID); + } + + void ScriptEngine::OnCollisionEnd(const UUID& sceneID, const UUID& entityID) + { + EntityInstance& entityInstance = GetEntityInstanceData(sceneID, entityID).Instance; + if (entityInstance.ScriptClass->OnCollisionEndMethod) + { + float value = 5.0f; + void* args[] = { &value }; + CallMethod(entityInstance.GetInstance(), entityInstance.ScriptClass->OnCollisionEndMethod, args); + } + } + void ScriptEngine::OnScriptComponentDestroyed(const UUID &sceneID, const UUID &entityID) { PM_CORE_ASSERT(s_EntityInstanceMap.find(sceneID) != s_EntityInstanceMap.end()); diff --git a/Prism/src/Prism/Script/ScriptEngine.h b/Prism/src/Prism/Script/ScriptEngine.h index 5cbdf10..64e568d 100644 --- a/Prism/src/Prism/Script/ScriptEngine.h +++ b/Prism/src/Prism/Script/ScriptEngine.h @@ -123,6 +123,11 @@ namespace Prism static void OnCollision2DEnd(Entity entity); static void OnCollision2DEnd(const UUID &sceneID, const UUID &entityID); + static void OnCollisionBegin(Entity entity); + static void OnCollisionBegin(const UUID& sceneID, const UUID& entityID); + static void OnCollisionEnd(Entity entity); + static void OnCollisionEnd(const UUID& sceneID, const UUID& entityID); + static void OnScriptComponentDestroyed(const UUID &sceneID, const UUID &entityID); static bool ModuleExists(const std::string& moduleName); diff --git a/Prism/src/Prism/Script/ScriptEngineRegistry.cpp b/Prism/src/Prism/Script/ScriptEngineRegistry.cpp index bdc955f..0bbd233 100644 --- a/Prism/src/Prism/Script/ScriptEngineRegistry.cpp +++ b/Prism/src/Prism/Script/ScriptEngineRegistry.cpp @@ -26,7 +26,7 @@ namespace Prism s_HasComponentFuncs[type] = [](Entity& entity) { return entity.HasComponent(); };\ s_CreateComponentFuncs[type] = [](Entity& entity) { entity.AddComponent(); };\ } else {\ - PM_CORE_ERROR("No C# component class found for " #Type "!");\ + PM_CORE_ERROR("No C# component class found for {0}", #Type);\ }\ } @@ -40,6 +40,9 @@ namespace Prism Component_RegisterType(SpriteRendererComponent); Component_RegisterType(RigidBody2DComponent); Component_RegisterType(BoxCollider2DComponent); + Component_RegisterType(RigidBodyComponent); + Component_RegisterType(BoxColliderComponent); + Component_RegisterType(SphereColliderComponent); } void ScriptEngineRegistry::RegisterAll() @@ -50,6 +53,10 @@ namespace Prism mono_add_internal_call("Prism.Entity::GetTransform_Native",(const void*)Prism::Script::Prism_Entity_GetTransform); mono_add_internal_call("Prism.Entity::SetTransform_Native",(const void*)Prism::Script::Prism_Entity_SetTransform); + mono_add_internal_call("Prism.Entity::GetForwardDirection_Native", Prism::Script::Prism_Entity_GetForwardDirection); + mono_add_internal_call("Prism.Entity::GetRightDirection_Native", Prism::Script::Prism_Entity_GetRightDirection); + mono_add_internal_call("Prism.Entity::GetUpDirection_Native", Prism::Script::Prism_Entity_GetUpDirection); + mono_add_internal_call("Prism.Entity::CreateComponent_Native",(const void*)Prism::Script::Prism_Entity_CreateComponent); mono_add_internal_call("Prism.Entity::HasComponent_Native",(const void*)Prism::Script::Prism_Entity_HasComponent); mono_add_internal_call("Prism.Entity::FindEntityByTag_Native", (const void*)Prism::Script::Prism_Entity_FindEntityByTag); @@ -67,6 +74,11 @@ namespace Prism mono_add_internal_call("Prism.Texture2D::Destructor_Native", (const void*)Prism::Script::Prism_Texture2D_Destructor); mono_add_internal_call("Prism.Texture2D::SetData_Native", (const void*)Prism::Script::Prism_Texture2D_SetData); + mono_add_internal_call("Prism.RigidBodyComponent::AddForce_Native", Prism::Script::Prism_RigidBodyComponent_AddForce); + mono_add_internal_call("Prism.RigidBodyComponent::AddTorque_Native", Prism::Script::Prism_RigidBodyComponent_AddTorque); + mono_add_internal_call("Prism.RigidBodyComponent::GetLinearVelocity_Native", Prism::Script::Prism_RigidBodyComponent_GetLinearVelocity); + mono_add_internal_call("Prism.RigidBodyComponent::SetLinearVelocity_Native", Prism::Script::Prism_RigidBodyComponent_SetLinearVelocity); + mono_add_internal_call("Prism.Material::Destructor_Native", (const void*)Prism::Script::Prism_Material_Destructor); mono_add_internal_call("Prism.Material::SetFloat_Native", (const void*)Prism::Script::Prism_Material_SetFloat); mono_add_internal_call("Prism.Material::SetTexture_Native", (const void*)Prism::Script::Prism_Material_SetTexture); diff --git a/Prism/src/Prism/Script/ScriptWarppers.cpp b/Prism/src/Prism/Script/ScriptWarppers.cpp index 5605949..f270e80 100644 --- a/Prism/src/Prism/Script/ScriptWarppers.cpp +++ b/Prism/src/Prism/Script/ScriptWarppers.cpp @@ -14,6 +14,13 @@ #include "Prism/Scene/Entity.h" #include "Prism/Scene/Scene.h" +#define GLM_ENABLE_EXPERIMENTAL +#include +#include + +#include "PxRigidActor.h" +#include "PxRigidDynamic.h" +#include "Prism/Physics/Physics3D.h" namespace Prism { extern std::unordered_map> s_HasComponentFuncs; @@ -31,13 +38,23 @@ namespace Prism { namespace Script { SpriteRenderer = 4 }; + static std::tuple GetTransformDecomposition(const glm::mat4& transform) + { + glm::vec3 scale, translation, skew; + glm::vec4 perspective; + glm::quat orientation; + glm::decompose(transform, scale, orientation, translation, skew, perspective); + + return { translation, orientation, scale }; + } + //////////////////////////////////////////////////////////////// // Math //////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////// - float Prism_Noise_PerlinNoise(float x, float y) + float Prism_Noise_PerlinNoise(const float x, const float y) { return Noise::PerlinNoise(x, y); } @@ -48,7 +65,7 @@ namespace Prism { namespace Script { // Input /////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////// - bool Prism_Input_IsKeyPressed(KeyCode key) + bool Prism_Input_IsKeyPressed(const KeyCode key) { return Input::IsKeyPressed(key); } @@ -59,7 +76,7 @@ namespace Prism { namespace Script { // Entity ////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////// - void Prism_Entity_GetTransform(uint64_t entityID, glm::mat4* outTransform) + void Prism_Entity_GetTransform(const uint64_t entityID, glm::mat4* outTransform) { Ref scene = ScriptEngine::GetCurrentSceneContext(); PM_CORE_ASSERT(scene, "No active scene!"); @@ -71,7 +88,7 @@ namespace Prism { namespace Script { memcpy(outTransform, glm::value_ptr(transformComponent.Transform), sizeof(glm::mat4)); } - void Prism_Entity_SetTransform(uint64_t entityID, glm::mat4* inTransform) + void Prism_Entity_SetTransform(const uint64_t entityID, const glm::mat4* inTransform) { Ref scene = ScriptEngine::GetCurrentSceneContext(); PM_CORE_ASSERT(scene, "No active scene!"); @@ -82,8 +99,7 @@ namespace Prism { namespace Script { auto& transformComponent = entity.GetComponent(); memcpy(glm::value_ptr(transformComponent.Transform), inTransform, sizeof(glm::mat4)); } - - void Prism_Entity_CreateComponent(uint64_t entityID, void* type) + void Prism_Entity_GetForwardDirection(const uint64_t entityID, glm::vec3* outForward) { Ref scene = ScriptEngine::GetCurrentSceneContext(); PM_CORE_ASSERT(scene, "No active scene!"); @@ -91,20 +107,65 @@ namespace Prism { namespace Script { PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!"); Entity entity = entityMap.at(entityID); - MonoType* monoType = mono_reflection_type_get_type((MonoReflectionType*)type); + const auto& transformComponent = entity.GetComponent(); + + auto [position, rotation, scale] = GetTransformDecomposition(transformComponent.Transform); + *outForward = glm::rotate(glm::inverse(glm::normalize(rotation)), glm::vec3(0, 0, -1)); + } + + void Prism_Entity_GetRightDirection(const uint64_t entityID, glm::vec3* outRight) + { + Ref scene = ScriptEngine::GetCurrentSceneContext(); + PM_CORE_ASSERT(scene, "No active scene!"); + const auto& entityMap = scene->GetEntityMap(); + PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!"); + + Entity entity = entityMap.at(entityID); + const auto& transformComponent = entity.GetComponent(); + + auto [position, rotation, scale] = GetTransformDecomposition(transformComponent.Transform); + *outRight = glm::rotate(glm::inverse(glm::normalize(rotation)), glm::vec3(1, 0, 0)); + } + + void Prism_Entity_GetUpDirection(const uint64_t entityID, glm::vec3* outUp) + { + Ref scene = ScriptEngine::GetCurrentSceneContext(); + PM_CORE_ASSERT(scene, "No active scene!"); + const auto& entityMap = scene->GetEntityMap(); + PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!"); + + Entity entity = entityMap.at(entityID); + const auto& transformComponent = entity.GetComponent(); + + auto [position, rotation, scale] = GetTransformDecomposition(transformComponent.Transform); + *outUp = glm::rotate(glm::inverse(glm::normalize(rotation)), glm::vec3(0, 1, 0)); + } + + + + + void Prism_Entity_CreateComponent(const uint64_t entityID, void* type) + { + Ref scene = ScriptEngine::GetCurrentSceneContext(); + PM_CORE_ASSERT(scene, "No active scene!"); + const auto& entityMap = scene->GetEntityMap(); + PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!"); + + Entity entity = entityMap.at(entityID); + MonoType* monoType = mono_reflection_type_get_type(static_cast(type)); s_CreateComponentFuncs[monoType](entity); } - bool Prism_Entity_HasComponent(uint64_t entityID, void* type) + bool Prism_Entity_HasComponent(const uint64_t entityID, void* type) { Ref scene = ScriptEngine::GetCurrentSceneContext(); PM_CORE_ASSERT(scene, "No active scene!"); const auto& entityMap = scene->GetEntityMap(); PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!"); - Entity entity = entityMap.at(entityID); - MonoType* monoType = mono_reflection_type_get_type((MonoReflectionType*)type); - bool result = s_HasComponentFuncs[monoType](entity); + Entity entity = entityMap.at(entityID); + MonoType* monoType = mono_reflection_type_get_type(static_cast(type)); + const bool result = s_HasComponentFuncs[monoType](entity); return result; } @@ -120,7 +181,7 @@ namespace Prism { namespace Script { return 0; } - void* Prism_MeshComponent_GetMesh(uint64_t entityID) + void* Prism_MeshComponent_GetMesh(const uint64_t entityID) { Ref scene = ScriptEngine::GetCurrentSceneContext(); PM_CORE_ASSERT(scene, "No active scene!"); @@ -132,7 +193,7 @@ namespace Prism { namespace Script { return new Ref(meshComponent.Mesh); } - void Prism_MeshComponent_SetMesh(uint64_t entityID, Ref* inMesh) + void Prism_MeshComponent_SetMesh(const uint64_t entityID, const Ref* inMesh) { Ref scene = ScriptEngine::GetCurrentSceneContext(); PM_CORE_ASSERT(scene, "No active scene!"); @@ -144,70 +205,7 @@ namespace Prism { namespace Script { meshComponent.Mesh = inMesh ? *inMesh : nullptr; } - void Prism_RigidBody2DComponent_ApplyLinearImpulse(uint64_t entityID, glm::vec2 *impulse, glm::vec2 *offset, bool wake) - { - Ref scene = ScriptEngine::GetCurrentSceneContext(); - PM_CORE_ASSERT(scene, "No active scene!"); - const auto& entityMap = scene->GetEntityMap(); - PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!"); - - Entity entity = entityMap.at(entityID); - PM_CORE_ASSERT(entity.HasComponent()); - auto& component = entity.GetComponent(); - - b2BodyId body = component.RuntimeBodyID; - - b2Body_ApplyLinearImpulse(body, *(const b2Vec2*)impulse, b2Body_GetWorldCenterOfMass(body) + *(const b2Vec2*)offset, wake); - } - - void Prism_RigidBody2DComponent_GetLinearVelocity(uint64_t entityID, glm::vec2 *outVelocity) - { - Ref scene = ScriptEngine::GetCurrentSceneContext(); - PM_CORE_ASSERT(scene, "No active scene!"); - const auto& entityMap = scene->GetEntityMap(); - PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!"); - - Entity entity = entityMap.at(entityID); - PM_CORE_ASSERT(entity.HasComponent()); - auto& component = entity.GetComponent(); - - b2Vec2 velocity = b2Body_GetLinearVelocity(component.RuntimeBodyID); - - PM_CORE_ASSERT(outVelocity); - *outVelocity = { velocity.x, velocity.y }; -} - - void Prism_RigidBody2DComponent_SetLinearVelocity(uint64_t entityID, glm::vec2 *velocity) - { - Ref scene = ScriptEngine::GetCurrentSceneContext(); - PM_CORE_ASSERT(scene, "No active scene!"); - const auto& entityMap = scene->GetEntityMap(); - PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!"); - - Entity entity = entityMap.at(entityID); - PM_CORE_ASSERT(entity.HasComponent()); - auto& component = entity.GetComponent(); - - PM_CORE_ASSERT(velocity); - b2Body_SetLinearVelocity(component.RuntimeBodyID, {velocity->x, velocity->y}); - } - - void Hazel_RigidBody2DComponent_GetLinearVelocity(uint64_t entityID, glm::vec2* outVelocity) - { - Ref scene = ScriptEngine::GetCurrentSceneContext(); - PM_CORE_ASSERT(scene, "No active scene!"); - const auto& entityMap = scene->GetEntityMap(); - PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!"); - - Entity entity = entityMap.at(entityID); - PM_CORE_ASSERT(entity.HasComponent()); - auto& component = entity.GetComponent(); - const auto& velocity = b2Body_GetLinearVelocity(component.RuntimeBodyID); - PM_CORE_ASSERT(outVelocity); - *outVelocity = { velocity.x, velocity.y }; - } - - void Hazel_RigidBody2DComponent_SetLinearVelocity(uint64_t entityID, glm::vec2* velocity) + void Prism_RigidBody2DComponent_ApplyLinearImpulse(const uint64_t entityID, const glm::vec2 *impulse, const glm::vec2 *offset, const bool wake) { Ref scene = ScriptEngine::GetCurrentSceneContext(); PM_CORE_ASSERT(scene, "No active scene!"); @@ -217,10 +215,133 @@ namespace Prism { namespace Script { Entity entity = entityMap.at(entityID); PM_CORE_ASSERT(entity.HasComponent()); const auto& component = entity.GetComponent(); + + const b2BodyId body = component.RuntimeBodyID; + + b2Body_ApplyLinearImpulse(body, *(const b2Vec2*)impulse, b2Body_GetWorldCenterOfMass(body) + *(const b2Vec2*)offset, wake); + } + + void Prism_RigidBody2DComponent_GetLinearVelocity(const uint64_t entityID, glm::vec2 *outVelocity) + { + Ref scene = ScriptEngine::GetCurrentSceneContext(); + PM_CORE_ASSERT(scene, "No active scene!"); + const auto& entityMap = scene->GetEntityMap(); + PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!"); + + Entity entity = entityMap.at(entityID); + PM_CORE_ASSERT(entity.HasComponent()); + const auto& component = entity.GetComponent(); + + b2Vec2 velocity = b2Body_GetLinearVelocity(component.RuntimeBodyID); + + PM_CORE_ASSERT(outVelocity); + *outVelocity = { velocity.x, velocity.y }; + } + + void Prism_RigidBody2DComponent_SetLinearVelocity(const uint64_t entityID, const glm::vec2 *velocity) + { + Ref scene = ScriptEngine::GetCurrentSceneContext(); + PM_CORE_ASSERT(scene, "No active scene!"); + const auto& entityMap = scene->GetEntityMap(); + PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!"); + + Entity entity = entityMap.at(entityID); + PM_CORE_ASSERT(entity.HasComponent()); + const auto& component = entity.GetComponent(); + PM_CORE_ASSERT(velocity); b2Body_SetLinearVelocity(component.RuntimeBodyID, {velocity->x, velocity->y}); } + void Prism_RigidBodyComponent_AddForce(const uint64_t entityID, glm::vec3* force, ForceMode forceMode) + { + Ref scene = ScriptEngine::GetCurrentSceneContext(); + PM_CORE_ASSERT(scene, "No active scene!"); + const auto& entityMap = scene->GetEntityMap(); + PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!"); + + Entity entity = entityMap.at(entityID); + PM_CORE_ASSERT(entity.HasComponent()); + const auto& component = entity.GetComponent(); + physx::PxRigidActor* actor = (physx::PxRigidActor*)component.RuntimeActor; + physx::PxRigidDynamic* dynamicActor = actor->is(); + + // We don't want to assert since scripts might want to be able to switch + // between a static and dynamic actor at runtime + if (!dynamicActor) + return; + + PM_CORE_ASSERT(force); + dynamicActor->addForce({ force->x, force->y, force->z }, (physx::PxForceMode::Enum)forceMode); + } + + void Prism_RigidBodyComponent_AddTorque(const uint64_t entityID, glm::vec3* torque, ForceMode forceMode) + { + Ref scene = ScriptEngine::GetCurrentSceneContext(); + PM_CORE_ASSERT(scene, "No active scene!"); + const auto& entityMap = scene->GetEntityMap(); + PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!"); + + Entity entity = entityMap.at(entityID); + PM_CORE_ASSERT(entity.HasComponent()); + const auto& component = entity.GetComponent(); + physx::PxRigidActor* actor = (physx::PxRigidActor*)component.RuntimeActor; + physx::PxRigidDynamic* dynamicActor = actor->is(); + + // We don't want to assert since scripts might want to be able to switch + // between a static and dynamic actor at runtime + if (!dynamicActor) + return; + + PM_CORE_ASSERT(torque); + dynamicActor->addTorque({ torque->x, torque->y, torque->z }, (physx::PxForceMode::Enum)forceMode); + } + + void Prism_RigidBodyComponent_GetLinearVelocity(const uint64_t entityID, glm::vec3* outVelocity) + { + Ref scene = ScriptEngine::GetCurrentSceneContext(); + PM_CORE_ASSERT(scene, "No active scene!"); + const auto& entityMap = scene->GetEntityMap(); + PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!"); + + Entity entity = entityMap.at(entityID); + PM_CORE_ASSERT(entity.HasComponent()); + const auto& component = entity.GetComponent(); + physx::PxRigidActor* actor = (physx::PxRigidActor*)component.RuntimeActor; + const physx::PxRigidDynamic* dynamicActor = actor->is(); + + // We don't want to assert since scripts might want to be able to switch + // between a static and dynamic actor at runtime + if (!dynamicActor) + return; + + PM_CORE_ASSERT(outVelocity); + physx::PxVec3 velocity = dynamicActor->getLinearVelocity(); + *outVelocity = { velocity.x, velocity.y, velocity.z }; + } + + void Prism_RigidBodyComponent_SetLinearVelocity(const uint64_t entityID, glm::vec3* velocity) + { + Ref scene = ScriptEngine::GetCurrentSceneContext(); + PM_CORE_ASSERT(scene, "No active scene!"); + const auto& entityMap = scene->GetEntityMap(); + PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!"); + + Entity entity = entityMap.at(entityID); + PM_CORE_ASSERT(entity.HasComponent()); + const auto& component = entity.GetComponent(); + physx::PxRigidActor* actor = (physx::PxRigidActor*)component.RuntimeActor; + physx::PxRigidDynamic* dynamicActor = actor->is(); + + // We don't want to assert since scripts might want to be able to switch + // between a static and dynamic actor at runtime + if (!dynamicActor) + return; + + PM_CORE_ASSERT(velocity); + dynamicActor->setLinearVelocity({ velocity->x, velocity->y, velocity->z }); + } + Ref* Prism_Mesh_Constructor(MonoString* filepath) { @@ -239,7 +360,7 @@ namespace Prism { namespace Script { return new Ref(mesh->GetMaterial()); } - Ref* Prism_Mesh_GetMaterialByIndex(Ref* inMesh, int index) + Ref* Prism_Mesh_GetMaterialByIndex(Ref* inMesh, const int index) { Ref& mesh = *(Ref*)inMesh; const auto& materials = mesh->GetMaterials(); @@ -255,13 +376,13 @@ namespace Prism { namespace Script { return (int)materials.size(); } - void* Prism_Texture2D_Constructor(uint32_t width, uint32_t height) + void* Prism_Texture2D_Constructor(const uint32_t width, const uint32_t height) { - auto result = Texture2D::Create(TextureFormat::RGBA, width, height); + const auto result = Texture2D::Create(TextureFormat::RGBA, width, height); return new Ref(result); } - void Prism_Texture2D_Destructor(Ref* _this) + void Prism_Texture2D_Destructor(const Ref* _this) { delete _this; } @@ -270,67 +391,67 @@ namespace Prism { namespace Script { { Ref& instance = *_this; - uint32_t dataSize = count * sizeof(glm::vec4) / 4; + const uint32_t dataSize = count * sizeof(glm::vec4) / 4; instance->Lock(); - Buffer buffer = instance->GetWriteableBuffer(); + const Buffer buffer = instance->GetWriteableBuffer(); PM_CORE_ASSERT(dataSize <= buffer.Size); // Convert RGBA32F color to RGBA8 - uint8_t* pixels = (uint8_t*)buffer.Data; - uint32_t index = 0; + auto pixels = static_cast(buffer.Data); + uint32_t index = 0; for (uint32_t i = 0; i < instance->GetWidth() * instance->GetHeight(); i++) { - glm::vec4& value = mono_array_get(inData, glm::vec4, i); - *pixels++ = (uint32_t)(value.x * 255.0f); - *pixels++ = (uint32_t)(value.y * 255.0f); - *pixels++ = (uint32_t)(value.z * 255.0f); - *pixels++ = (uint32_t)(value.w * 255.0f); + const glm::vec4& value = mono_array_get(inData, glm::vec4, i); + *pixels++ = static_cast(value.x * 255.0f); + *pixels++ = static_cast(value.y * 255.0f); + *pixels++ = static_cast(value.z * 255.0f); + *pixels++ = static_cast(value.w * 255.0f); } instance->Unlock(); } - void Prism_Material_Destructor(Ref* _this) + void Prism_Material_Destructor(const Ref* _this) { delete _this; } - void Prism_Material_SetFloat(Ref* _this, MonoString* uniform, float value) + void Prism_Material_SetFloat(Ref* _this, MonoString* uniform, const float value) { Ref& instance = *(Ref*)_this; instance->Set(mono_string_to_utf8(uniform), value); } - void Prism_Material_SetTexture(Ref* _this, MonoString* uniform, Ref* texture) + void Prism_Material_SetTexture(Ref* _this, MonoString* uniform, const Ref* texture) { Ref& instance = *(Ref*)_this; instance->Set(mono_string_to_utf8(uniform), *texture); } - void Prism_MaterialInstance_Destructor(Ref* _this) + void Prism_MaterialInstance_Destructor(const Ref* _this) { delete _this; } - void Prism_MaterialInstance_SetFloat(Ref* _this, MonoString* uniform, float value) + void Prism_MaterialInstance_SetFloat(Ref* _this, MonoString* uniform, const float value) { Ref& instance = *(Ref*)_this; instance->Set(mono_string_to_utf8(uniform), value); } - void Prism_MaterialInstance_SetVector3(Ref* _this, MonoString* uniform, glm::vec3* value) + void Prism_MaterialInstance_SetVector3(Ref* _this, MonoString* uniform, const glm::vec3* value) { Ref& instance = *(Ref*)_this; instance->Set(mono_string_to_utf8(uniform), *value); } - void Prism_MaterialInstance_SetVector4(Ref *_this, MonoString *uniform, glm::vec4 *value) + void Prism_MaterialInstance_SetVector4(Ref *_this, MonoString *uniform, const glm::vec4 *value) { Ref& instance = *(Ref*)_this; instance->Set(mono_string_to_utf8(uniform), *value); } - void Prism_MaterialInstance_SetTexture(Ref* _this, MonoString* uniform, Ref* texture) + void Prism_MaterialInstance_SetTexture(Ref* _this, MonoString* uniform, const Ref* texture) { Ref& instance = *(Ref*)_this; instance->Set(mono_string_to_utf8(uniform), *texture); diff --git a/Prism/src/Prism/Script/ScriptWarppers.h b/Prism/src/Prism/Script/ScriptWarppers.h index c173b2f..0c0fd80 100644 --- a/Prism/src/Prism/Script/ScriptWarppers.h +++ b/Prism/src/Prism/Script/ScriptWarppers.h @@ -6,6 +6,7 @@ #define SCRIPTWARPPERS_H #include "Prism/Core/KeyCodes.h" #include "Prism/Core/Ref.h" +#include "Prism/Physics/Physics3D.h" #include "Prism/Renderer/Material.h" #include "Prism/Renderer/Mesh.h" #include "Prism/Renderer/Texture.h" @@ -25,35 +26,44 @@ namespace Prism { namespace Script { // Entity void Prism_Entity_GetTransform(uint64_t entityID, glm::mat4* outTransform); - void Prism_Entity_SetTransform(uint64_t entityID, glm::mat4* inTransform); + void Prism_Entity_SetTransform(uint64_t entityID, const glm::mat4* inTransform); + void Prism_Entity_GetForwardDirection(uint64_t entityID, glm::vec3* outForward); + void Prism_Entity_GetRightDirection(uint64_t entityID, glm::vec3* outRight); + void Prism_Entity_GetUpDirection(uint64_t entityID, glm::vec3* outUp); + void Prism_Entity_CreateComponent(uint64_t entityID, void* type); bool Prism_Entity_HasComponent(uint64_t entityID, void* type); uint64_t Prism_Entity_FindEntityByTag(MonoString* tag); void* Prism_MeshComponent_GetMesh(uint64_t entityID); - void Prism_MeshComponent_SetMesh(uint64_t entityID, Ref* inMesh); + void Prism_MeshComponent_SetMesh(uint64_t entityID, const Ref* inMesh); // 2D Physic - void Prism_RigidBody2DComponent_ApplyLinearImpulse(uint64_t entityID, glm::vec2* impulse, glm::vec2* offset, bool wake); + void Prism_RigidBody2DComponent_ApplyLinearImpulse(uint64_t entityID, const glm::vec2* impulse, const glm::vec2* offset, bool wake); void Prism_RigidBody2DComponent_GetLinearVelocity(uint64_t entityID, glm::vec2* outVelocity); - void Prism_RigidBody2DComponent_SetLinearVelocity(uint64_t entityID, glm::vec2* velocity); + void Prism_RigidBody2DComponent_SetLinearVelocity(uint64_t entityID, const glm::vec2* velocity); + + void Prism_RigidBodyComponent_AddForce(uint64_t entityID, glm::vec3* force, ForceMode forceMode); + void Prism_RigidBodyComponent_AddTorque(uint64_t entityID, glm::vec3* torque, ForceMode forceMode); + void Prism_RigidBodyComponent_GetLinearVelocity(uint64_t entityID, glm::vec3* outVelocity); + void Prism_RigidBodyComponent_SetLinearVelocity(uint64_t entityID, glm::vec3* velocity); // Renderer // Texture2D void* Prism_Texture2D_Constructor(uint32_t width, uint32_t height); - void Prism_Texture2D_Destructor(Ref* _this); + void Prism_Texture2D_Destructor(const Ref* _this); void Prism_Texture2D_SetData(Ref* _this, MonoArray* inData, int32_t count); // Material - void Prism_Material_Destructor(Ref* _this); + void Prism_Material_Destructor(const Ref* _this); void Prism_Material_SetFloat(Ref* _this, MonoString* uniform, float value); - void Prism_Material_SetTexture(Ref* _this, MonoString* uniform, Ref* texture); + void Prism_Material_SetTexture(Ref* _this, MonoString* uniform, const Ref* texture); - void Prism_MaterialInstance_Destructor(Ref* _this); + void Prism_MaterialInstance_Destructor(const Ref* _this); void Prism_MaterialInstance_SetFloat(Ref* _this, MonoString* uniform, float value); - void Prism_MaterialInstance_SetVector3(Ref* _this, MonoString* uniform, glm::vec3* value); - void Prism_MaterialInstance_SetVector4(Ref* _this, MonoString* uniform, glm::vec4* value); - void Prism_MaterialInstance_SetTexture(Ref* _this, MonoString* uniform, Ref* texture); + void Prism_MaterialInstance_SetVector3(Ref* _this, MonoString* uniform, const glm::vec3* value); + void Prism_MaterialInstance_SetVector4(Ref* _this, MonoString* uniform, const glm::vec4* value); + void Prism_MaterialInstance_SetTexture(Ref* _this, MonoString* uniform, const Ref* texture); // Mesh Ref* Prism_Mesh_Constructor(MonoString* filepath); diff --git a/Prism/vendor/PhysX b/Prism/vendor/PhysX new file mode 160000 index 0000000..09ff24f --- /dev/null +++ b/Prism/vendor/PhysX @@ -0,0 +1 @@ +Subproject commit 09ff24f3279b735e672ff27b155cbf49f6296f4d