diff --git a/Editor/Editor/EditorLayer.cpp b/Editor/Editor/EditorLayer.cpp index 15f548e..65de028 100644 --- a/Editor/Editor/EditorLayer.cpp +++ b/Editor/Editor/EditorLayer.cpp @@ -19,6 +19,7 @@ #include "Prism/Physics/Physics3D.h" #include "Prism/Renderer/Renderer2D.h" #include "Prism/Script/ScriptEngine.h" +#include "Prism/Script/ScriptWrappers.h" namespace Prism { @@ -56,6 +57,12 @@ namespace Prism AssetEditorPanel::RegisterDefaultEditors(); FileSystem::StartWatching(); + m_ConsolePanel = CreateScope(); + Script::SetLogCallback([this](const std::string& message) + { + if (m_ConsolePanel) + m_ConsolePanel->AddMessage(message, ImVec4(1,1,1,1)); + }); } void EditorLayer::OnDetach() @@ -147,6 +154,18 @@ namespace Prism } } + + + if (m_SceneState == SceneState::Play) + { + if (Input::GetCursorMode() != CursorMode::Normal) + { + if (Input::IsKeyPressed(KeyCode::LEFT_CONTROL) && Input::IsKeyPressed(KeyCode::LEFT_ALT) && Input::IsKeyPressed(KeyCode::GRAVE_ACCENT)) + { + Input::SetCursorMode(CursorMode::Normal); + } + } + } } void EditorLayer::OnImGuiRender() @@ -278,8 +297,9 @@ namespace Prism Entity selectedEntity = m_SelectionContext.front().Entity; if (selectedEntity.HasComponent()) { - Ref mesh = selectedEntity.GetComponent().Mesh; - if (mesh) + auto& meshComponent = selectedEntity.GetComponent(); + + if (Ref mesh = meshComponent.Mesh) { auto& materials = mesh->GetMaterials(); static uint32_t selectedMaterialIndex = 0; @@ -307,27 +327,13 @@ namespace Prism } ImGui::EndChild(); } - /* - for (uint32_t i = 0; i < materials.size(); i++) - { - const auto& materialInstance = materials[i]; - - ImGuiTreeNodeFlags node_flags = (selectedMaterialIndex == i ? ImGuiTreeNodeFlags_Selected : 0) | ImGuiTreeNodeFlags_Leaf; - bool opened = ImGui::TreeNodeEx((void*)(&materialInstance), node_flags, "%s", materialInstance->GetName().c_str()); - if (ImGui::IsItemClicked()) - { - selectedMaterialIndex = i; - } - if (opened) - ImGui::TreePop(); - - } - */ ImGui::Separator(); if (selectedMaterialIndex < materials.size()) { + bool shouldUpdate = false; + auto& materialInstance = materials[selectedMaterialIndex]; ImGui::Text("Shader: %s", materialInstance->GetShader()->GetName().c_str()); // Textures ------------------------------------------------------------------------------ @@ -342,6 +348,21 @@ namespace Prism Ref albedoMap = materialInstance->TryGetResource("u_AlbedoTexture"); ImGui::Image(albedoMap ? (ImTextureRef)albedoMap->GetRendererID() : (ImTextureRef)m_CheckerboardTex->GetRendererID(), ImVec2(64, 64)); + + if (ImGui::BeginDragDropTarget()) + { + if (const auto data = ImGui::AcceptDragDropPayload("asset_payload")) + { + AssetHandle assetHandle = *(AssetHandle*)data->Data; + if (AssetsManager::IsAssetType(assetHandle, AssetType::Texture)) + { + albedoMap = AssetsManager::GetAsset(assetHandle); + shouldUpdate = true; + } + } + ImGui::EndDragDropTarget(); + } + ImGui::PopStyleVar(); if (ImGui::IsItemHovered()) { @@ -354,28 +375,23 @@ namespace Prism ImGui::Image((ImTextureRef)albedoMap->GetRendererID(), ImVec2(384, 384)); ImGui::EndTooltip(); } - if (ImGui::IsItemClicked()) - { - if (std::string filename = FileSystem::OpenFileSelector("*.png;*.tga;*.jpg;*.jpeg"); !filename.empty()) - { - albedoMap = Texture2D::Create(filename, true/*m_AlbedoInput.SRGB*/); - materialInstance->Set("u_AlbedoTexture", albedoMap); - } - } } ImGui::SameLine(); ImGui::BeginGroup(); if (ImGui::Checkbox("Use##AlbedoMap", &useAlbedoMap)) - materialInstance->Set("u_AlbedoTexToggle", useAlbedoMap ? 1.0f : 0.0f); - - /*if (ImGui::Checkbox("sRGB##AlbedoMap", &m_AlbedoInput.SRGB)) { - if (m_AlbedoInput.TextureMap) - m_AlbedoInput.TextureMap = Texture2D::Create(m_AlbedoInput.TextureMap->GetPath(), m_AlbedoInput.SRGB); - }*/ + materialInstance->Set("u_AlbedoTexToggle", useAlbedoMap ? 1.0f : 0.0f); + shouldUpdate = true; + } + + ImGui::EndGroup(); ImGui::SameLine(); - ImGui::ColorEdit3("Color##Albedo", glm::value_ptr(albedoColor), ImGuiColorEditFlags_NoInputs); + if (ImGui::ColorEdit3("Color##Albedo", glm::value_ptr(albedoColor), ImGuiColorEditFlags_NoInputs)) + { + meshComponent.UpdateMaterials(selectedMaterialIndex); + shouldUpdate = true; + } } } { @@ -388,6 +404,21 @@ namespace Prism Ref normalMap = materialInstance->TryGetResource("u_NormalTexture"); ImGui::Image(normalMap ? (ImTextureRef)normalMap->GetRendererID() : (ImTextureRef)m_CheckerboardTex->GetRendererID(), ImVec2(64, 64)); + + if (ImGui::BeginDragDropTarget()) + { + if (const auto data = ImGui::AcceptDragDropPayload("asset_payload")) + { + AssetHandle assetHandle = *(AssetHandle*)data->Data; + if (AssetsManager::IsAssetType(assetHandle, AssetType::Texture)) + { + normalMap = AssetsManager::GetAsset(assetHandle); + shouldUpdate = true; + } + } + ImGui::EndDragDropTarget(); + } + ImGui::PopStyleVar(); if (ImGui::IsItemHovered()) { @@ -406,12 +437,16 @@ namespace Prism { normalMap = Texture2D::Create(filename); materialInstance->Set("u_NormalTexture", normalMap); + shouldUpdate = true; } } } ImGui::SameLine(); if (ImGui::Checkbox("Use##NormalMap", &useNormalMap)) + { materialInstance->Set("u_NormalTexToggle", useNormalMap ? 1.0f : 0.0f); + shouldUpdate = true; + } } } { @@ -425,6 +460,21 @@ namespace Prism Ref metalnessMap = materialInstance->TryGetResource("u_MetalnessTexture"); ImGui::Image(metalnessMap ? (ImTextureRef)metalnessMap->GetRendererID() : (ImTextureRef)m_CheckerboardTex->GetRendererID(), ImVec2(64, 64)); + + if (ImGui::BeginDragDropTarget()) + { + if (const auto data = ImGui::AcceptDragDropPayload("asset_payload")) + { + AssetHandle assetHandle = *(AssetHandle*)data->Data; + if (AssetsManager::IsAssetType(assetHandle, AssetType::Texture)) + { + metalnessMap = AssetsManager::GetAsset(assetHandle); + shouldUpdate = true; + } + } + ImGui::EndDragDropTarget(); + } + ImGui::PopStyleVar(); if (ImGui::IsItemHovered()) { @@ -437,20 +487,18 @@ namespace Prism ImGui::Image((ImTextureRef)metalnessMap->GetRendererID(), ImVec2(384, 384)); ImGui::EndTooltip(); } - if (ImGui::IsItemClicked()) - { - if (std::string filename = FileSystem::OpenFileSelector("*.png;*.tga;*.jpg;*.jpeg"); !filename.empty()) - { - metalnessMap = Texture2D::Create(filename); - materialInstance->Set("u_MetalnessTexture", metalnessMap); - } - } } ImGui::SameLine(); if (ImGui::Checkbox("Use##MetalnessMap", &useMetalnessMap)) + { materialInstance->Set("u_MetalnessTexToggle", useMetalnessMap ? 1.0f : 0.0f); + shouldUpdate = true; + } ImGui::SameLine(); - ImGui::SliderFloat("Value##MetalnessInput", &metalnessValue, 0.0f, 1.0f); + if (ImGui::SliderFloat("Value##MetalnessInput", &metalnessValue, 0.0f, 1.0f)) + { + shouldUpdate = true; + } } } { @@ -463,6 +511,20 @@ namespace Prism Ref roughnessMap = materialInstance->TryGetResource("u_RoughnessTexture"); ImGui::Image(roughnessMap ? (ImTextureRef)roughnessMap->GetRendererID() : (ImTextureRef)m_CheckerboardTex->GetRendererID(), ImVec2(64, 64)); + if (ImGui::BeginDragDropTarget()) + { + if (const auto data = ImGui::AcceptDragDropPayload("asset_payload")) + { + AssetHandle assetHandle = *(AssetHandle*)data->Data; + if (AssetsManager::IsAssetType(assetHandle, AssetType::Texture)) + { + roughnessMap = AssetsManager::GetAsset(assetHandle); + shouldUpdate = true; + } + } + ImGui::EndDragDropTarget(); + } + ImGui::PopStyleVar(); if (ImGui::IsItemHovered()) { @@ -475,22 +537,21 @@ namespace Prism ImGui::Image((ImTextureRef)roughnessMap->GetRendererID(), ImVec2(384, 384)); ImGui::EndTooltip(); } - if (ImGui::IsItemClicked()) - { - if (std::string filename = FileSystem::OpenFileSelector("*.png;*.tga;*.jpg;*.jpeg"); !filename.empty()) - { - roughnessMap = Texture2D::Create(filename); - materialInstance->Set("u_RoughnessTexture", roughnessMap); - } - } } ImGui::SameLine(); if (ImGui::Checkbox("Use##RoughnessMap", &useRoughnessMap)) + { materialInstance->Set("u_RoughnessTexToggle", useRoughnessMap ? 1.0f : 0.0f); + shouldUpdate = true; + } ImGui::SameLine(); - ImGui::SliderFloat("Value##RoughnessInput", &roughnessValue, 0.0f, 1.0f); + if (ImGui::SliderFloat("Value##RoughnessInput", &roughnessValue, 0.0f, 1.0f)) + { + shouldUpdate = true; + } } } + if (shouldUpdate) meshComponent.UpdateMaterials(selectedMaterialIndex); } } } @@ -508,7 +569,8 @@ namespace Prism m_ObjectsPanel->OnImGuiRender(); m_SceneHierarchyPanel->OnImGuiRender(); - m_EditorCamera.OnImGuiRender(); + // m_EditorCamera.OnImGuiRender(); + m_ConsolePanel->OnImGuiRender(); // Editor Panel ------------------------------------------------------------------------------ ImGui::Begin("Environment"); diff --git a/Editor/Editor/EditorLayer.h b/Editor/Editor/EditorLayer.h index 25dfbf2..071f587 100644 --- a/Editor/Editor/EditorLayer.h +++ b/Editor/Editor/EditorLayer.h @@ -5,6 +5,7 @@ #ifndef EDITORLAYER_H #define EDITORLAYER_H +#include "Panels/ConsolePanel.h" #include "Prism.h" #include "Prism/Editor/ContentBrowserPanel.h" #include "Prism/Editor/ObjectsPanel.h" @@ -150,6 +151,9 @@ namespace Prism Edit = 0, Play = 1, Pause = 2 }; SceneState m_SceneState = SceneState::Edit; + + private: + Scope m_ConsolePanel; }; } diff --git a/Editor/Editor/Panels/ConsolePanel.cpp b/Editor/Editor/Panels/ConsolePanel.cpp new file mode 100644 index 0000000..5fec511 --- /dev/null +++ b/Editor/Editor/Panels/ConsolePanel.cpp @@ -0,0 +1,66 @@ +// +// Created by Atdunbg on 2026/3/26. +// + +#include "ConsolePanel.h" + +namespace Prism +{ + ConsolePanel::ConsolePanel() + { + // 预留一些空间 + m_Messages.reserve(1000); + } + + void ConsolePanel::OnImGuiRender() + { + ImGui::Begin("Console"); + + // 工具栏 + if (ImGui::Button("Clear")) + { + std::lock_guard lock(m_Mutex); + m_Messages.clear(); + } + ImGui::SameLine(); + ImGui::Checkbox("Auto-scroll", &m_AutoScroll); + ImGui::SameLine(); + m_Filter.Draw("Filter", 200); + + // 消息列表区域 + ImGui::BeginChild("ScrollingRegion", ImVec2(0, 0), ImGuiChildFlags_Borders, ImGuiWindowFlags_HorizontalScrollbar); + { + std::lock_guard lock(m_Mutex); + for (const auto& [msg, color] : m_Messages) + { + if (m_Filter.PassFilter(msg.c_str())) + { + ImGui::PushStyleColor(ImGuiCol_Text, color); + ImGui::TextUnformatted(msg.c_str()); + ImGui::PopStyleColor(); + } + } + + if (m_ScrollToBottom) + { + ImGui::SetScrollHereY(1.0f); + m_ScrollToBottom = false; + } + } + ImGui::EndChild(); + + + ImGui::End(); + } + + void ConsolePanel::AddMessage(const std::string& message, ImVec4 color) + { + std::lock_guard lock(m_Mutex); + m_Messages.emplace_back(message, color); + while (m_Messages.size() > 5000) + m_Messages.erase(m_Messages.begin()); + + if (m_AutoScroll && !m_ScrollToBottom) + m_ScrollToBottom = true; + } +} \ No newline at end of file diff --git a/Editor/Editor/Panels/ConsolePanel.h b/Editor/Editor/Panels/ConsolePanel.h new file mode 100644 index 0000000..7a892de --- /dev/null +++ b/Editor/Editor/Panels/ConsolePanel.h @@ -0,0 +1,31 @@ +// +// Created by Atdunbg on 2026/3/26. +// + +#ifndef PRISM_CONSOLEPANEL_H +#define PRISM_CONSOLEPANEL_H +#include +#include + +#include "imgui.h" + +namespace Prism +{ + class ConsolePanel + { + public: + ConsolePanel(); + void OnImGuiRender(); + + void AddMessage(const std::string& message, ImVec4 color = ImVec4(1,1,1,1)); + + private: + std::vector> m_Messages; + ImGuiTextFilter m_Filter; + bool m_AutoScroll = true; + bool m_ScrollToBottom = false; + std::mutex m_Mutex; + }; +} + +#endif //PRISM_CONSOLEPANEL_H \ No newline at end of file diff --git a/Editor/imgui.ini b/Editor/imgui.ini index a7496db..a041e11 100644 --- a/Editor/imgui.ini +++ b/Editor/imgui.ini @@ -1,6 +1,6 @@ [Window][DockSpace Demo] Pos=0,0 -Size=2560,1566 +Size=1920,1080 Collapsed=0 [Window][Debug##Default] @@ -9,32 +9,32 @@ Size=400,400 Collapsed=0 [Window][Scene Hierarchy] -Pos=2089,24 -Size=471,563 +Pos=1449,24 +Size=471,385 Collapsed=0 DockId=0x00000009,0 [Window][Properties] -Pos=2089,589 -Size=471,977 +Pos=1449,411 +Size=471,669 Collapsed=0 DockId=0x0000000A,0 [Window][Scene Renderer] -Pos=0,843 -Size=481,723 +Pos=0,585 +Size=481,495 Collapsed=0 DockId=0x00000006,0 [Window][Materials] Pos=0,24 -Size=481,817 +Size=481,559 Collapsed=0 DockId=0x00000005,0 [Window][Script Engine Debug] -Pos=2089,589 -Size=471,977 +Pos=1449,411 +Size=471,669 Collapsed=0 DockId=0x0000000A,2 @@ -52,25 +52,25 @@ DockId=0x00000001,0 [Window][Viewport] Pos=483,58 -Size=1604,955 +Size=964,647 Collapsed=0 DockId=0x0000000B,0 [Window][Environment] -Pos=2089,589 -Size=471,977 +Pos=1449,411 +Size=471,669 Collapsed=0 DockId=0x0000000A,1 [Window][Project] -Pos=483,1015 -Size=1604,551 +Pos=483,707 +Size=964,373 Collapsed=0 DockId=0x0000000C,0 [Window][Objects] -Pos=483,1015 -Size=1604,551 +Pos=483,707 +Size=964,373 Collapsed=0 DockId=0x0000000C,1 @@ -81,12 +81,18 @@ Collapsed=0 [Window][##tool_bar] Pos=483,24 -Size=1604,32 +Size=964,32 Collapsed=0 DockId=0x00000001,0 +[Window][Console] +Pos=483,707 +Size=964,373 +Collapsed=0 +DockId=0x0000000C,2 + [Docking][Data] -DockSpace ID=0xC0DFADC4 Window=0xD0388BC8 Pos=0,58 Size=2560,1542 Split=X Selected=0x0C01D6D5 +DockSpace ID=0xC0DFADC4 Window=0xD0388BC8 Pos=268,189 Size=1920,1056 Split=X Selected=0x0C01D6D5 DockNode ID=0x00000007 Parent=0xC0DFADC4 SizeRef=1557,1542 Split=X DockNode ID=0x00000003 Parent=0x00000007 SizeRef=481,1542 Split=Y Selected=0x5D711C2C DockNode ID=0x00000005 Parent=0x00000003 SizeRef=481,817 Selected=0x5D711C2C diff --git a/ExampleApp/Src/FPSPlayer.cs b/ExampleApp/Src/FPSPlayer.cs index 1aa496c..ed328d3 100644 --- a/ExampleApp/Src/FPSPlayer.cs +++ b/ExampleApp/Src/FPSPlayer.cs @@ -8,7 +8,9 @@ namespace FPSExample public float WalkingSpeed = 10.0f; public float RunSpeed = 20.0f; public float JumpForce = 50.0f; - + + public float m_Radius = 0.5f; + public float TorqueStrength = 10.0f; [NonSerialized] public float MouseSensitivity = 10.0f; @@ -68,15 +70,20 @@ namespace FPSExample UpdateRotation(ts); UpdateCameraTransform(); } + + void OnPhysicsUpdate(float fixedTimeStep) + { + UpdateMovement(); + } private void UpdateRotation(float ts) { Vec2 currentMousePosition = Input.GetMousePosition(); Vec2 delta = m_LastMousePosition - currentMousePosition; - float m_CurrentYMovement = delta.X * MouseSensitivity * ts; + m_CurrentYMovement = delta.X * MouseSensitivity * ts; float xRotation = delta.Y * MouseSensitivity * ts; - m_RigidBody.Rotate(new Vec3(0.0f, m_CurrentYMovement, 0.0f)); + // m_RigidBody.Rotate(new Vec3(0.0f, m_CurrentYMovement, 0.0f)); if (delta.X != 0 || delta.Y != 0) { @@ -90,17 +97,25 @@ namespace FPSExample private void UpdateMovementInput() { - if (Input.IsKeyPressed(KeyCode.W)) - m_MovementDirection.Y += 1.0f; - else if (Input.IsKeyPressed(KeyCode.S)) + if (Input.IsKeyPressed(KeyCode.W)){ m_MovementDirection.Y -= 1.0f; + Debug.Log("KeyPressed: W"); + } + else if (Input.IsKeyPressed(KeyCode.S)){ + m_MovementDirection.Y += 1.0f; + Debug.Log("KeyPressed: S"); + } else m_MovementDirection.Y = 0.0f; - if(Input.IsKeyPressed(KeyCode.A)) - m_MovementDirection.X -= 1.0f; - else if (Input.IsKeyPressed(KeyCode.D)) + if(Input.IsKeyPressed(KeyCode.A)){ m_MovementDirection.X += 1.0f; + Debug.Log("KeyPressed: A"); + } + else if (Input.IsKeyPressed(KeyCode.D)){ + m_MovementDirection.X -= 1.0f; + Debug.Log("KeyPressed: D"); + } else m_MovementDirection.X = 0.0f; @@ -136,26 +151,64 @@ namespace FPSExample } - void OnPhysicsUpdate(float fixedTimeStep) - { - UpdateMovement(); - } private void UpdateMovement() { - m_RigidBody.Rotate(new Vec3(0.0f, m_CurrentYMovement, 0.0f)); - - Vec3 movement = m_CameraTransform.Transform.Right * m_MovementDirection.X + m_CameraTransform.Transform.Forward * m_MovementDirection.Y; + // 2. 计算期望的移动方向(世界坐标系) + Vec3 desiredDirection = Vec3.Zero; + if (m_MovementDirection.LengthSquared() != 0.0f) { + Vec3 right = m_CameraTransform.Transform.Right; + Vec3 forward = m_CameraTransform.Transform.Forward; + right.Y = 0; forward.Y = 0; + right.Normalize(); forward.Normalize(); + + desiredDirection = right * m_MovementDirection.X + forward * m_MovementDirection.Y; + desiredDirection.Normalize(); + + /* + Vec3 movement = right * m_MovementDirection.X + forward * m_MovementDirection.Y; movement.Normalize(); Vec3 velocity = movement * m_CurrentSpeed; velocity.Y = m_RigidBody.GetLinearVelocity().Y; m_RigidBody.SetLinearVelocity(velocity); + */ } + Vec3 targetAngularVelocity = Vec3.Zero; + if (desiredDirection.LengthSquared() > 0.01f) + { + Vec3 up = Vec3.Up; + Vec3 rotationAxis = Vec3.Cross(desiredDirection, up).Normalized(); + float angularSpeed = 2 * (m_CurrentSpeed / m_Radius); + targetAngularVelocity = rotationAxis * angularSpeed; + + Vec3 currentAngular = m_RigidBody.GetAngularVelocity(); + Vec3 angularDiff = targetAngularVelocity - currentAngular; + + float inertia = 0.4f * m_RigidBody.Mass * m_Radius * m_Radius; + Vec3 torque = angularDiff * inertia * TorqueStrength; + m_RigidBody.AddTorque(torque, RigidBodyComponent.ForceMode.Force); + } + + + /* + // 3. 获取当前角速度,计算需要调整的差值 + Vec3 currentAngular = m_RigidBody.GetAngularVelocity(); + Vec3 angularDiff = targetAngularVelocity - currentAngular; + + // 4. 施加扭矩:扭矩 = 转动惯量 * 角加速度 + // 球体的转动惯量 I = (2/5) * m * r^2 (实心球) + float inertia = TorqueStrength * m_RigidBody.Mass * m_Radius * m_Radius; + // 设定一个系数控制响应速度(可调) + float torqueStrength = 5.0f; + Vec3 torque = angularDiff * inertia * torqueStrength; + m_RigidBody.AddTorque(-torque, RigidBodyComponent.ForceMode.Force); + */ if (m_ShouldJump && m_Colliding) { + Debug.Log("Jump"); m_RigidBody.AddForce(Vec3.Up * JumpForce, RigidBodyComponent.ForceMode.Impulse); m_ShouldJump = false; } @@ -163,7 +216,7 @@ namespace FPSExample private void UpdateCameraTransform(){ Vec3 position = m_Transform.Translation + m_CameraTransform.Transform.Forward * CameraForwardOffset; - position.Y += m_Transform.Translation.Y + CameraYOffset; + position.Y += CameraYOffset; m_CameraTransform.Translation = position; } } diff --git a/Prism-ScriptCore/Src/Prism/Math/Vec3.cs b/Prism-ScriptCore/Src/Prism/Math/Vec3.cs index 60669f3..3762c01 100644 --- a/Prism-ScriptCore/Src/Prism/Math/Vec3.cs +++ b/Prism-ScriptCore/Src/Prism/Math/Vec3.cs @@ -52,6 +52,15 @@ namespace Prism Y = vec.Y; Z = vec.Z; } + + public static Vec3 Cross(Vec3 a, Vec3 b) + { + return new Vec3( + a.Y * b.Z - a.Z * b.Y, + a.Z * b.X - a.X * b.Z, + a.X * b.Y - a.Y * b.X + ); + } public void Clamp(Vec3 min, Vec3 max) { @@ -59,6 +68,7 @@ namespace Prism Y = Mathf.Clamp(Y, min.Y, max.Y); Z = Mathf.Clamp(Z, min.Z, max.Z); } + public float LengthSquared() { diff --git a/Prism/CMakeLists.txt b/Prism/CMakeLists.txt index 1e72f10..f1b7cec 100644 --- a/Prism/CMakeLists.txt +++ b/Prism/CMakeLists.txt @@ -197,7 +197,45 @@ set_target_properties(${SHARED_LIBRARY} PROPERTIES ) +# static runtime library +set(RUNTIME_LIBRARY ${PROJECT_NAME}-Runtime) + +add_library(${RUNTIME_LIBRARY} STATIC ${SRC_SOURCE}) + +target_compile_definitions(${RUNTIME_LIBRARY} PRIVATE + PRISM_RUNTIME + INTERFACE + PRISM_STATIC +) + +target_include_directories(${RUNTIME_LIBRARY} PUBLIC + ${TARGET_INCLUDE_DIR} +) + +target_link_directories(${RUNTIME_LIBRARY} INTERFACE + ${PHYSX_LIB_DIR} +) + +target_link_libraries(${RUNTIME_LIBRARY} + PRIVATE + ${LINK_LIBRARIES_PRIVATE} + PUBLIC + ${LINK_LIBRARIES_PUBLIC} +) +target_precompile_headers(${RUNTIME_LIBRARY} PRIVATE + src/pmpch.h +) + +set_target_properties(${RUNTIME_LIBRARY} PROPERTIES + OUTPUT_NAME ${PROJECT_NAME} + ARCHIVE_OUTPUT_NAME ${PROJECT_NAME}rd +) + + + # alias add_library(Prism::static ALIAS Prism-static) add_library(Prism::shared ALIAS Prism-shared) add_library(Prism ALIAS Prism-shared) + +add_library(Prism::Runtime ALIAS Prism-Runtime) diff --git a/Prism/src/Prism/Asset/Asset.cpp b/Prism/src/Prism/Asset/Asset.cpp new file mode 100644 index 0000000..e9c2a4f --- /dev/null +++ b/Prism/src/Prism/Asset/Asset.cpp @@ -0,0 +1,25 @@ +// +// Created by Atdunbg on 2026/3/26. +// + +#include "Asset.h" +#include "Prism/Renderer/Texture.h" + +namespace Prism +{ + PhysicsMaterialAsset::PhysicsMaterialAsset(): StaticFriction(0), DynamicFriction(0), Bounciness(0) + { + Type = AssetType::PhysicsMaterial; + } + + PhysicsMaterialAsset::PhysicsMaterialAsset(const float staticFriction, const float dynamicFriction, + const float bounciness): StaticFriction(staticFriction), DynamicFriction(dynamicFriction), Bounciness(bounciness) + { + Type = AssetType::PhysicsMaterial; + } + + PBRMaterialAsset::PBRMaterialAsset() + { + Type = AssetType::Material; + } +} diff --git a/Prism/src/Prism/Asset/Asset.h b/Prism/src/Prism/Asset/Asset.h index fb25a71..f22ae9e 100644 --- a/Prism/src/Prism/Asset/Asset.h +++ b/Prism/src/Prism/Asset/Asset.h @@ -5,14 +5,20 @@ #ifndef PRISM_ASSET_H #define PRISM_ASSET_H +#include + #include "Prism/Core/UUID.h" #include "Prism/Core/Ref.h" namespace Prism { + class Texture2D; + class Shader; + class MaterialInstance; + enum class AssetType { - Scene = 0, Mesh, Texture, EnvMap, Audio, Script, PhysicsMaterial, Directory, Other, None + Scene = 0, Mesh, Texture, EnvMap, Audio, Script, Material, PhysicsMaterial, Directory, Other, None }; using AssetHandle = UUID; @@ -35,20 +41,17 @@ namespace Prism } }; - class PRISM_API PhysicsMaterial : public Asset + class PRISM_API PhysicsMaterialAsset : public Asset { public: float StaticFriction; float DynamicFriction; float Bounciness; - PhysicsMaterial() = default; + PhysicsMaterialAsset(); + + PhysicsMaterialAsset(const float staticFriction, const float dynamicFriction, const float bounciness); - PhysicsMaterial(const float staticFriction, const float dynamicFriction, const float bounciness) - : StaticFriction(staticFriction), DynamicFriction(dynamicFriction), Bounciness(bounciness) - { - Type = AssetType::PhysicsMaterial; - } }; // Treating directories as assets simplifies the asset manager window rendering by a lot @@ -63,6 +66,34 @@ namespace Prism } }; + class PBRMaterialAsset : public Asset + { + public: + PBRMaterialAsset(); + virtual ~PBRMaterialAsset() = default; + // Albedo + glm::vec3 AlbedoColor = glm::vec3(1.0f); + float AlbedoTexToggle = 0.0f; + Ref AlbedoTexture; + + // Normal + float NormalTexToggle = 0.0f; + Ref NormalTexture; + + // Metalness + float Metalness = 0.8f; + float MetalnessTexToggle = 0.0f; + Ref MetalnessTexture; + + // Roughness + float Roughness = 0.1f; + float RoughnessTexToggle = 0.0f; + Ref RoughnessTexture; + + bool IsDirty = true; + }; + + } #endif //PRISM_ASSET_H diff --git a/Prism/src/Prism/Asset/AssetSerializer.cpp b/Prism/src/Prism/Asset/AssetSerializer.cpp index b2b51a3..9ac6d63 100644 --- a/Prism/src/Prism/Asset/AssetSerializer.cpp +++ b/Prism/src/Prism/Asset/AssetSerializer.cpp @@ -12,6 +12,7 @@ #include "Prism/Renderer/SceneRenderer.h" #include "yaml-cpp/yaml.h" +#include "Prism/Utilities/SerializeUtils.h" namespace Prism { @@ -40,15 +41,114 @@ namespace Prism { case Prism::AssetType::PhysicsMaterial: { - Ref material = Ref(asset); - out << YAML::Key << "StaticFriction" << material->StaticFriction; - out << YAML::Key << "DynamicFriction" << material->DynamicFriction; - out << YAML::Key << "Bounciness" << material->Bounciness; + Ref physicsMaterial = Ref(asset); + out << YAML::Key << "StaticFriction" << physicsMaterial->StaticFriction; + out << YAML::Key << "DynamicFriction" << physicsMaterial->DynamicFriction; + out << YAML::Key << "Bounciness" << physicsMaterial->Bounciness; + break; + } + case AssetType::Material: + { + const auto& material = Ref(asset); + + // Albedo + out << YAML::Key << "Albedo"; + out << YAML::BeginMap; + { + out << YAML::Key << "Color" << YAML::Value << material->AlbedoColor; + out << YAML::Key << "TexToggle" << YAML::Value << material->AlbedoTexToggle; + + out << YAML::Key << "Texture"; + out << YAML::BeginMap; + if (material->AlbedoTexture) + { + out << YAML::Key << "AssetHandle" << YAML::Value << material->AlbedoTexture->Handle; + out << YAML::Key << "AssetPath" << YAML::Value << material->AlbedoTexture->FilePath; + } + else + { + out << YAML::Key << "AssetHandle" << YAML::Value << 0; + out << YAML::Key << "AssetPath" << YAML::Value << ""; + } + out << YAML::EndMap; + } + out << YAML::EndMap; + + // Normal + out << YAML::Key << "Normal"; + out << YAML::BeginMap; + { + out << YAML::Key << "TexToggle" << YAML::Value << material->NormalTexToggle; + + out << YAML::Key << "Texture"; + out << YAML::BeginMap; + if (material->NormalTexture) + { + out << YAML::Key << "AssetHandle" << YAML::Value << material->NormalTexture->Handle; + out << YAML::Key << "AssetPath" << YAML::Value << material->NormalTexture->FilePath; + } + else + { + out << YAML::Key << "AssetHandle" << YAML::Value << 0; + out << YAML::Key << "AssetPath" << YAML::Value << ""; + } + out << YAML::EndMap; + } + out << YAML::EndMap; + + // Metalness + out << YAML::Key << "Metalness"; + out << YAML::BeginMap; + { + out << YAML::Key << "Value" << YAML::Value << material->Metalness; // 金属度数值 + out << YAML::Key << "TexToggle" << YAML::Value << material->MetalnessTexToggle; + + out << YAML::Key << "Texture"; + out << YAML::BeginMap; + if (material->MetalnessTexture) + { + out << YAML::Key << "AssetHandle" << YAML::Value << material->MetalnessTexture->Handle; + out << YAML::Key << "AssetPath" << YAML::Value << material->MetalnessTexture->FilePath; + } + else + { + out << YAML::Key << "AssetHandle" << YAML::Value << 0; + out << YAML::Key << "AssetPath" << YAML::Value << ""; + } + out << YAML::EndMap; + } + out << YAML::EndMap; + + // Roughness + out << YAML::Key << "Roughness"; + out << YAML::BeginMap; + { + out << YAML::Key << "Value" << YAML::Value << material->Roughness; // 粗糙度数值 + out << YAML::Key << "TexToggle" << YAML::Value << material->RoughnessTexToggle; + + out << YAML::Key << "Texture"; + out << YAML::BeginMap; + if (material->RoughnessTexture) + { + out << YAML::Key << "AssetHandle" << YAML::Value << material->RoughnessTexture->Handle; + out << YAML::Key << "AssetPath" << YAML::Value << material->RoughnessTexture->FilePath; + } + else + { + out << YAML::Key << "AssetHandle" << YAML::Value << 0; + out << YAML::Key << "AssetPath" << YAML::Value << ""; + } + out << YAML::EndMap; + } + out << YAML::EndMap; + break; } } + out << YAML::EndMap; + PM_CORE_INFO("Save Asset change..."); std::ofstream fout(asset->FilePath); fout << out.c_str(); } @@ -61,13 +161,125 @@ namespace Prism YAML::Node data = YAML::Load(strStream.str()); - if (asset->Type == AssetType::PhysicsMaterial) + switch (asset->Type) { - float staticFriction = data["StaticFriction"].as(); - float dynamicFriction = data["DynamicFriction"].as(); - float bounciness = data["Bounciness"].as(); + case AssetType::PhysicsMaterial: + { + float staticFriction = data["StaticFriction"].as(); + float dynamicFriction = data["DynamicFriction"].as(); + float bounciness = data["Bounciness"].as(); - return Ref::Create(staticFriction, dynamicFriction, bounciness); + return Ref::Create(staticFriction, dynamicFriction, bounciness); + } + case AssetType::Material: + { + Ref material = Ref::Create(); + + // ==================== Albedo ==================== + if (data["Albedo"]) + { + auto albedoNode = data["Albedo"]; + material->AlbedoColor = albedoNode["Color"].as(); + material->AlbedoTexToggle = albedoNode["TexToggle"].as(); + + if (albedoNode["Texture"]) + { + auto texNode = albedoNode["Texture"]; + UUID texHandle = 0; + std::string texPath; + if (texNode["AssetHandle"]) + texHandle = texNode["AssetHandle"].as(); + if (texNode["AssetPath"]) + texPath = texNode["AssetPath"].as(); + + if (texHandle != 0 && AssetsManager::IsAssetHandleValid(texHandle)) + material->AlbedoTexture = AssetsManager::GetAsset(texHandle); + else if (!texPath.empty()) + material->AlbedoTexture = Texture2D::Create(texPath); + else + material->AlbedoTexture = nullptr; + } + } + + // ==================== Normal ==================== + if (data["Normal"]) + { + auto normalNode = data["Normal"]; + material->NormalTexToggle = normalNode["TexToggle"].as(); + + if (normalNode["Texture"]) + { + auto texNode = normalNode["Texture"]; + UUID texHandle = 0; + std::string texPath; + if (texNode["AssetHandle"]) + texHandle = texNode["AssetHandle"].as(); + if (texNode["AssetPath"]) + texPath = texNode["AssetPath"].as(); + + if (texHandle != 0 && AssetsManager::IsAssetHandleValid(texHandle)) + material->NormalTexture = AssetsManager::GetAsset(texHandle); + else if (!texPath.empty()) + material->NormalTexture = Texture2D::Create(texPath); + else + material->NormalTexture = nullptr; + } + } + + // ==================== Metalness ==================== + if (data["Metalness"]) + { + auto metalNode = data["Metalness"]; + material->Metalness = metalNode["Value"].as(); + material->MetalnessTexToggle = metalNode["TexToggle"].as(); + + if (metalNode["Texture"]) + { + auto texNode = metalNode["Texture"]; + UUID texHandle = 0; + std::string texPath; + if (texNode["AssetHandle"]) + texHandle = texNode["AssetHandle"].as(); + if (texNode["AssetPath"]) + texPath = texNode["AssetPath"].as(); + + if (texHandle != 0 && AssetsManager::IsAssetHandleValid(texHandle)) + material->MetalnessTexture = AssetsManager::GetAsset(texHandle); + else if (!texPath.empty()) + material->MetalnessTexture = Texture2D::Create(texPath); + else + material->MetalnessTexture = nullptr; + } + } + + // ==================== Roughness ==================== + if (data["Roughness"]) + { + auto roughNode = data["Roughness"]; + material->Roughness = roughNode["Value"].as(); + material->RoughnessTexToggle = roughNode["TexToggle"].as(); + + if (roughNode["Texture"]) + { + auto texNode = roughNode["Texture"]; + UUID texHandle = 0; + std::string texPath; + if (texNode["AssetHandle"]) + texHandle = texNode["AssetHandle"].as(); + if (texNode["AssetPath"]) + texPath = texNode["AssetPath"].as(); + + if (texHandle != 0 && AssetsManager::IsAssetHandleValid(texHandle)) + material->RoughnessTexture = AssetsManager::GetAsset(texHandle); + else if (!texPath.empty()) + material->RoughnessTexture = Texture2D::Create(texPath); + else + material->RoughnessTexture = nullptr; + } + } + + return material; + } } return nullptr; @@ -106,8 +318,10 @@ namespace Prism asset->ParentDirectory = parentHandle; asset->IsDataLoaded = false; +#ifndef PRISM_RUNTIME if (!hasMeta) CreateMetaFile(asset); +#endif return asset; } @@ -191,7 +405,9 @@ namespace Prism if (asset->FileName == "assets" && asset->Handle == 0) { asset->Handle = AssetHandle(); +#ifndef PRISM_RUNTIME CreateMetaFile(asset); +#endif } } @@ -208,4 +424,17 @@ namespace Prism std::ofstream fout(asset->FilePath + ".meta"); fout << out.c_str(); } + + void AssetSerializer::UpdateMetaFile(const Ref& asset) + { + YAML::Emitter out; + out << YAML::BeginMap; + out << YAML::Key << "Asset" << YAML::Value << asset->Handle; + out << YAML::Key << "FilePath" << YAML::Value << asset->FilePath; + out << YAML::Key << "Type" << YAML::Value << (int)asset->Type; + out << YAML::EndMap; + + std::ofstream fout(asset->FilePath + ".meta"); + fout << out.c_str(); + } } \ No newline at end of file diff --git a/Prism/src/Prism/Asset/AssetSerializer.h b/Prism/src/Prism/Asset/AssetSerializer.h index 040b9c0..b5a4d0a 100644 --- a/Prism/src/Prism/Asset/AssetSerializer.h +++ b/Prism/src/Prism/Asset/AssetSerializer.h @@ -28,6 +28,7 @@ namespace Prism static Ref DeserializeYAML(const Ref& asset); static void LoadMetaData(Ref& asset); static void CreateMetaFile(const Ref& asset); + static void UpdateMetaFile(const Ref& asset); private: friend class AssetsManager; diff --git a/Prism/src/Prism/Asset/AssetsManager.cpp b/Prism/src/Prism/Asset/AssetsManager.cpp index 53e7290..8f7a863 100644 --- a/Prism/src/Prism/Asset/AssetsManager.cpp +++ b/Prism/src/Prism/Asset/AssetsManager.cpp @@ -13,6 +13,7 @@ #include #include "AssetSerializer.h" +#include "Prism/Core/Application.h" #include "Prism/Renderer/SceneEnvironment.h" #include "Prism/Utilities/StringUtils.h" @@ -26,9 +27,13 @@ namespace Prism s_Types["dae"] = AssetType::Mesh; s_Types["obj"] = AssetType::Mesh; s_Types["png"] = AssetType::Texture; + s_Types["jpg"] = AssetType::Texture; + s_Types["jpeg"] = AssetType::Texture; + s_Types["bmp"] = AssetType::Texture; s_Types["tga"] = AssetType::Texture; s_Types["hdr"] = AssetType::EnvMap; s_Types["blend"] = AssetType::Mesh; + s_Types["pmat"] = AssetType::Material; s_Types["hpm"] = AssetType::PhysicsMaterial; s_Types["wav"] = AssetType::Audio; s_Types["ogg"] = AssetType::Audio; @@ -150,7 +155,7 @@ namespace Prism template PRISM_API Ref AssetsManager::GetAsset(AssetHandle, bool); template PRISM_API Ref AssetsManager::GetAsset(AssetHandle, bool); - template PRISM_API Ref AssetsManager::GetAsset(AssetHandle, bool); + template PRISM_API Ref AssetsManager::GetAsset(AssetHandle, bool); template PRISM_API Ref AssetsManager::GetAsset(AssetHandle, bool); template PRISM_API Ref AssetsManager::GetAsset(AssetHandle, bool); template PRISM_API Ref AssetsManager::GetAsset(AssetHandle, bool); @@ -161,35 +166,30 @@ namespace Prism return GetAsset(GetAssetHandleFromFilePath(filepath), loadData); } + template PRISM_API Ref AssetsManager::GetAsset(const std::string&, bool); template PRISM_API Ref AssetsManager::GetAsset(const std::string&, bool); - template PRISM_API Ref AssetsManager::GetAsset(const std::string&, bool); + template PRISM_API Ref AssetsManager::GetAsset(const std::string&, bool); + template PRISM_API Ref AssetsManager::GetAsset(const std::string&, bool); template PRISM_API Ref AssetsManager::GetAsset(const std::string&, bool); template PRISM_API Ref AssetsManager::GetAsset(const std::string&, bool); template PRISM_API Ref AssetsManager::GetAsset(const std::string&, bool); - - // temp - Ref AssetsManager::CreateAssetPhysicsMaterial(const std::string& filename, const AssetType type, const AssetHandle& directoryHandle, float v1, float v2, float v3) + template + Ref AssetsManager::TryGetAsset(const std::string& filepath, const bool loadData) { - - const auto& directory = GetAsset(directoryHandle); - - Ref asset = Ref::Create(v1, v2, v3); - asset->Type = type; - asset->FilePath = directory->FilePath + "/" + filename; - asset->FileName = Utils::RemoveExtension(Utils::GetFilename(asset->FilePath)); - asset->Extension = Utils::GetFilename(filename); - asset->ParentDirectory = directoryHandle; - asset->Handle = std::hash()(asset->FilePath); - asset->IsDataLoaded = true; - s_LoadedAssets[asset->Handle] = asset; - - AssetSerializer::SerializeAsset(asset); - AssetSerializer::CreateMetaFile(asset); - - return asset; + AssetHandle assetHandle = GetAssetHandleFromFilePath(filepath); + if (!assetHandle) return Ref(); + return GetAsset(assetHandle, loadData); } + template PRISM_API Ref AssetsManager::TryGetAsset(const std::string&, bool); + template PRISM_API Ref AssetsManager::TryGetAsset(const std::string&, bool); + template PRISM_API Ref AssetsManager::TryGetAsset(const std::string&, bool); + template PRISM_API Ref AssetsManager::TryGetAsset(const std::string&, bool); + template PRISM_API Ref AssetsManager::TryGetAsset(const std::string&, bool); + template PRISM_API Ref AssetsManager::TryGetAsset(const std::string&, bool); + template PRISM_API Ref AssetsManager::TryGetAsset(const std::string&, bool); + void AssetsManager::RemoveAsset(AssetHandle assetHandle) { @@ -233,7 +233,8 @@ namespace Prism asset->FileName = Utils::RemoveExtension(Utils::GetFilename(asset->FilePath)); asset->Extension = Utils::GetFilename(filename); asset->ParentDirectory = directoryHandle; - asset->Handle = std::hash()(asset->FilePath); + asset->Handle = std::hash()(asset->FilePath + std::to_string(Application::Get().GetTime())); + asset->IsDataLoaded = true; s_LoadedAssets[asset->Handle] = asset; @@ -243,6 +244,10 @@ namespace Prism return asset; } + template PRISM_API Ref AssetsManager::CreateAsset(const std::string&, AssetType, AssetHandle, float&&, float&&, float&&); + template PRISM_API Ref AssetsManager::CreateAsset( const std::string&, AssetType, AssetHandle); + + template PRISM_API Ref AssetsManager::CreateAsset( const std::string&, AssetType, AssetHandle); bool AssetsManager::IsAssetType(const AssetHandle assetHandle, const AssetType type) @@ -288,7 +293,7 @@ namespace Prism { const std::string extension = Utils::GetExtension(filepath); if (extension == "meta") - return Ref(); + return {}; const AssetType type = AssetTypes::GetAssetTypeFromExtension(extension); Ref asset = AssetSerializer::LoadAssetInfo(filepath, parentHandle, type); @@ -349,7 +354,9 @@ namespace Prism ProcessDirectory(e.FilePath, parentHandle); else { - Ref asset = ImportAsset(e.FilePath, parentHandle); + AssetHandle assetHandle = GetAssetHandleFromFilePath(e.FilePath); + if (!assetHandle) + ImportAsset(e.FilePath, parentHandle); } } @@ -366,10 +373,10 @@ namespace Prism { Ref asset = nullptr; { - const std::string oldMetaPath = std::filesystem::path(e.FilePath).parent_path().string() + "/" + e.OldName; + const std::string oldFilePath = Utils::ReplaceFilePathName(e.FilePath, e.OldName); for (auto& [handle, existingAsset] : s_LoadedAssets) { - if (existingAsset->FilePath == oldMetaPath) + if (existingAsset->FilePath == oldFilePath) { asset = existingAsset; break; @@ -379,13 +386,16 @@ namespace Prism if (asset) { + std::string extension = Utils::GetExtension(asset->FilePath); std::string oldMetaPath = asset->FilePath + ".meta"; - FileSystem::Rename(oldMetaPath, e.NewName); + FileSystem::Rename(oldMetaPath, e.NewName + "." + extension); asset->FilePath = e.FilePath; asset->FileName = e.NewName; - asset->Extension = Utils::GetExtension(e.FilePath); + asset->Extension = extension; + + AssetSerializer::UpdateMetaFile(asset); } } break; diff --git a/Prism/src/Prism/Asset/AssetsManager.h b/Prism/src/Prism/Asset/AssetsManager.h index 57d6e12..4c016c9 100644 --- a/Prism/src/Prism/Asset/AssetsManager.h +++ b/Prism/src/Prism/Asset/AssetsManager.h @@ -46,7 +46,7 @@ namespace Prism static bool IsAssetHandleValid(const AssetHandle& assetHandle); - static Ref CreateAssetPhysicsMaterial(const std::string& filename, AssetType type, const AssetHandle& directoryHandle, float v1, float v2, float v3); + static Ref CreateAssetPhysicsMaterial(const std::string& filename, AssetType type, const AssetHandle& directoryHandle, float v1, float v2, float v3); static void RemoveAsset(AssetHandle assetHandle); @@ -58,6 +58,8 @@ namespace Prism template static Ref GetAsset(const std::string& filepath, bool loadData = true); + template + static Ref TryGetAsset(const std::string& filepath, bool loadData = true); static bool IsAssetType(AssetHandle assetHandle, AssetType type); diff --git a/Prism/src/Prism/Core/EntryPoint.h b/Prism/src/Prism/Core/EntryPoint.h index 62faad1..7a93c9f 100644 --- a/Prism/src/Prism/Core/EntryPoint.h +++ b/Prism/src/Prism/Core/EntryPoint.h @@ -13,17 +13,17 @@ extern Prism::Application* Prism::CreateApplication(CommandArgs args); #ifdef PRISM_GUI -#ifdef _WIN32 -#include -int MainEntry(int argc, char* argv[]); -int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) -{ - return MainEntry(__argc, __argv); -} -#endif -int MainEntry(int argc, char** argv) + #ifdef _WIN32 + #include + int MainEntry(int argc, char* argv[]); + int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) + { + return MainEntry(__argc, __argv); + } + #endif + int MainEntry(int argc, char** argv) #else -int main(int argc, char** argv) + int main(int argc, char** argv) #endif { //TODO: this will use other method to impl diff --git a/Prism/src/Prism/Core/Math/AABB.h b/Prism/src/Prism/Core/Math/AABB.h index 073653b..8197ca6 100644 --- a/Prism/src/Prism/Core/Math/AABB.h +++ b/Prism/src/Prism/Core/Math/AABB.h @@ -19,6 +19,10 @@ namespace Prism AABB(const glm::vec3& min, const glm::vec3& max) : Min(min), Max(max) {} + bool IsValid() const { + return Min.x <= Max.x && Min.y <= Max.y && Min.z <= Max.z; + } + }; } diff --git a/Prism/src/Prism/Editor/AssetEditorPanel.cpp b/Prism/src/Prism/Editor/AssetEditorPanel.cpp index c6cd8bd..3bddd59 100644 --- a/Prism/src/Prism/Editor/AssetEditorPanel.cpp +++ b/Prism/src/Prism/Editor/AssetEditorPanel.cpp @@ -52,6 +52,7 @@ namespace Prism { RegisterEditor(AssetType::Texture); RegisterEditor(AssetType::PhysicsMaterial); + RegisterEditor(AssetType::Material); } void AssetEditorPanel::OnImGuiRender() @@ -62,6 +63,11 @@ namespace Prism void AssetEditorPanel::OpenEditor(const Ref& asset) { + if (!asset) + { + PM_CORE_WARN("asset is Invalid!"); + return; + } if (s_Editors.find(asset->Type) == s_Editors.end()) { PM_CORE_WARN("No editor registered for {0} assets", asset->Extension); diff --git a/Prism/src/Prism/Editor/ContentBrowserPanel.cpp b/Prism/src/Prism/Editor/ContentBrowserPanel.cpp index 9cf8da0..1c9f2bd 100644 --- a/Prism/src/Prism/Editor/ContentBrowserPanel.cpp +++ b/Prism/src/Prism/Editor/ContentBrowserPanel.cpp @@ -33,7 +33,9 @@ namespace Prism m_AssetIconMap["blend"] = AssetsManager::GetAsset("assets/editor/blend.png"); // TODO: get a logo for this project - m_AssetIconMap["scene"] = Texture2D::Create("assets/editor/asset.png"); + m_AssetIconMap["scene"] = AssetsManager::GetAsset("assets/editor/asset.png"); + + m_AssetIconMap["pmat"] = AssetsManager::GetAsset("assets/editor/asset.png"); m_BackbtnTex = AssetsManager::GetAsset("assets/editor/btn_back.png"); m_FwrdbtnTex = AssetsManager::GetAsset("assets/editor/btn_fwrd.png"); @@ -105,17 +107,53 @@ namespace Prism const std::string filePath = m_CurrentDirectory->FilePath + "/new folder"; FileSystem::CreateFolder(filePath); UpdateCurrentDirectory(m_CurrentDirHandle); - // const auto& createdDirectory = AssetsManager::CreateDirectory(filePath, m_CurrentDirHandle); - /* - if (createdDirectory) + } + + if (ImGui::MenuItem("PBRMaterial")) + { + + const std::string fileName = "Material.pmat"; + const auto& directory = AssetsManager::GetAsset(m_CurrentDirHandle); + + // for hash UUID use + std::string baseName = Utils::RemoveExtension(fileName); + std::string extension = Utils::GetExtension(fileName, true); + std::string finalFilename = fileName; + std::string finalPath = directory->FilePath + "/" + finalFilename; + + int counter = 1; + while (AssetsManager::GetAssetHandleFromFilePath(finalPath) != 0) { - UpdateCurrentDirectory(m_CurrentDirHandle); - m_SelectedAssets.Select(createdDirectory->Handle); - memset(m_InputBuffer, 0, MAX_INPUT_BUFFER_LENGTH); - memcpy(m_InputBuffer, createdDirectory->FileName.c_str(), createdDirectory->FileName.size()); - m_RenamingSelected = true; + finalFilename = baseName + "_" + std::to_string(counter++) + extension; + finalPath = directory->FilePath + "/" + finalFilename; } - */ + + + AssetsManager::CreateAsset(finalFilename, AssetType::Material, m_CurrentDirHandle); + UpdateCurrentDirectory(m_CurrentDirHandle); + } + + if (ImGui::MenuItem("Physics Material")) + { + const std::string fileName = "PhysicsMaterial.hpm"; + const auto& directory = AssetsManager::GetAsset(m_CurrentDirHandle); + + // for hash UUID use + std::string baseName = Utils::RemoveExtension(fileName); + std::string extension = Utils::GetExtension(fileName, true); + std::string finalFilename = fileName; + std::string finalPath = directory->FilePath + "/" + finalFilename; + + int counter = 1; + while (AssetsManager::GetAssetHandleFromFilePath(finalPath) != 0) + { + finalFilename = baseName + "_" + std::to_string(counter++) + extension; + finalPath = directory->FilePath + "/" + finalFilename; + } + + + AssetsManager::CreateAsset(finalFilename, AssetType::PhysicsMaterial, m_CurrentDirHandle, 0.6f, 0.6f, 0.0f); + UpdateCurrentDirectory(m_CurrentDirHandle); } if (ImGui::MenuItem("Scene")) @@ -128,13 +166,23 @@ namespace Prism PM_CORE_INFO("Creating Script..."); } + /* if (ImGui::MenuItem("Prefab")) { PM_CORE_INFO("Creating Prefab..."); } + */ ImGui::EndMenu(); } + ImGui::Separator(); + + if (ImGui::MenuItem("Open In Explorer")) + { + Ref asset = AssetsManager::GetAsset(m_CurrentDirHandle); + FileSystem::OpenInExplorer(asset->FilePath); + } + ImGui::Separator(); if (ImGui::MenuItem("Import")) { @@ -146,12 +194,6 @@ namespace Prism UpdateCurrentDirectory(m_CurrentDirHandle); } - if (ImGui::MenuItem("Physics Material")) - { - // TODO: use template - AssetsManager::CreateAssetPhysicsMaterial("New Physics Material.hpm", AssetType::PhysicsMaterial, m_CurrentDirHandle, 0.6f, 0.6f, 0.0f); - UpdateCurrentDirectory(m_CurrentDirHandle); - } ImGui::EndPopup(); } @@ -305,6 +347,12 @@ namespace Prism if (ImGui::BeginPopupContextItem()) { + if (ImGui::MenuItem("Open In Explorer")) + { + FileSystem::OpenInExplorer(asset->FilePath); + } + ImGui::Separator(); + if (ImGui::MenuItem("Rename")) { m_SelectedAssets.Select(assetHandle); @@ -528,7 +576,7 @@ namespace Prism if (ImGui::InputText("##rename_dummy", m_InputBuffer, MAX_INPUT_BUFFER_LENGTH, ImGuiInputTextFlags_EnterReturnsTrue)) { PM_CORE_INFO("Renaming to {0}", m_InputBuffer); - const std::string filename = m_InputBuffer + Utils::GetExtension(asset->FilePath); + const std::string filename = m_InputBuffer; FileSystem::Rename(asset->FilePath, filename); m_RenamingSelected = false; m_SelectedAssets.Clear(); diff --git a/Prism/src/Prism/Editor/DefaultAssetEditors.cpp b/Prism/src/Prism/Editor/DefaultAssetEditors.cpp index 311066c..219b876 100644 --- a/Prism/src/Prism/Editor/DefaultAssetEditors.cpp +++ b/Prism/src/Prism/Editor/DefaultAssetEditors.cpp @@ -13,6 +13,12 @@ namespace Prism PhysicsMaterialEditor::PhysicsMaterialEditor() : AssetEditor("Edit Physics Material") {} + void PhysicsMaterialEditor::SetAsset(const Ref& asset) + { + if (m_Asset) AssetSerializer::SerializeAsset(m_Asset); + m_Asset = static_cast>(asset); + } + void PhysicsMaterialEditor::Render() { if (!m_Asset) @@ -37,6 +43,12 @@ namespace Prism SetMaxSize(500, 1000); } + void TextureViewer::SetAsset(const Ref& asset) + { + if (m_Asset) AssetSerializer::SerializeAsset(m_Asset); + m_Asset = static_cast>(asset); + } + void TextureViewer::Render() { if (!m_Asset) @@ -58,4 +70,214 @@ namespace Prism UI::EndPropertyGrid(); } + PBRMaterialEditor::PBRMaterialEditor() : AssetEditor("Material Editor") + { + } + + + // 辅助函数:绘制纹理拖拽槽 + void DrawTextureSlot(Ref& texture, const std::function)>& onDrop) + { + static Ref s_Checkerboard = nullptr; + if (!s_Checkerboard) + s_Checkerboard = AssetsManager::GetAsset("assets/editor/Checkerboard.tga"); + + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10)); + ImGui::Image(texture ? (ImTextureID)(intptr_t)texture->GetRendererID() : (ImTextureID)(intptr_t)s_Checkerboard->GetRendererID(), + ImVec2(64, 64)); + ImGui::PopStyleVar(); + + if (ImGui::BeginDragDropTarget()) + { + if (const auto data = ImGui::AcceptDragDropPayload("asset_payload")) + { + AssetHandle assetHandle = *(AssetHandle*)data->Data; + if (AssetsManager::IsAssetType(assetHandle, AssetType::Texture)) + { + Ref newTex = AssetsManager::GetAsset(assetHandle); + if (onDrop) onDrop(newTex); + } + } + ImGui::EndDragDropTarget(); + } + + if (ImGui::IsItemHovered()) + { + if (texture) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextUnformatted(texture->GetPath().c_str()); + ImGui::PopTextWrapPos(); + ImGui::Image((ImTextureID)(intptr_t)texture->GetRendererID(), ImVec2(384, 384)); + ImGui::EndTooltip(); + } + + /* + // TODO: how to solve this + if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) + { + std::string filename = FileSystem::OpenFileSelector("*.png;*.tga;*.jpg;*.jpeg"); + if (!filename.empty()) + { + Ref newTex = Texture2D::Create(filename); + if (onDrop) onDrop(newTex); + } + } + */ + } + } + + + void PBRMaterialEditor::SetAsset(const Ref& asset) + { + if (m_Asset) + { + if (m_Asset->Handle == asset->Handle) return; + if (AssetsManager::IsAssetHandleValid(m_Asset->Handle)) + AssetSerializer::SerializeAsset(m_Asset); + } + m_Asset = static_cast>(asset); + } + + void PBRMaterialEditor::Render() + { + if (!m_Asset) return; + + auto& material = m_Asset; + + if (ImGui::BeginTabBar("MaterialProperties", ImGuiTabBarFlags_None)) + { + // ==================== Parameters ==================== + if (ImGui::BeginTabItem("Parameters")) + { + ImGui::Spacing(); + + if (ImGui::CollapsingHeader("Albedo", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::Indent(); + + if (ImGui::ColorEdit3("Color##Albedo", glm::value_ptr(material->AlbedoColor))) + { + m_Asset->IsDirty = true; + } + + bool useAlbedoMap = (material->AlbedoTexToggle > 0.5f); + if (ImGui::Checkbox("Use Texture##Albedo", &useAlbedoMap)) + { + material->AlbedoTexToggle = useAlbedoMap ? 1.0f : 0.0f; + m_Asset->IsDirty = true; + } + + DrawTextureSlot(material->AlbedoTexture, [&](const Ref& newTex) { + material->AlbedoTexture = newTex; + material->AlbedoTexToggle = true; + m_Asset->IsDirty = true; + }); + ImGui::SameLine(); + ImGui::Text("Albedo Texture"); + + ImGui::Unindent(); + } + + // Normal Map + if (ImGui::CollapsingHeader("Normal Map", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::Indent(); + + bool useNormalMap = (material->NormalTexToggle > 0.5f); + if (ImGui::Checkbox("Use Texture##Normal", &useNormalMap)) + { + material->NormalTexToggle = useNormalMap ? 1.0f : 0.0f; + m_Asset->IsDirty = true; + } + + DrawTextureSlot(material->NormalTexture, [&](const Ref& newTex) { + material->NormalTexture = newTex; + material->NormalTexToggle = true; + m_Asset->IsDirty = true; + }); + ImGui::SameLine(); + ImGui::Text("Normal Texture"); + + ImGui::Unindent(); + } + + // Metalness + if (ImGui::CollapsingHeader("Metalness", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::Indent(); + + if (ImGui::SliderFloat("Value##Metalness", &material->Metalness, 0.0f, 1.0f)) + { + // 自动保存 + m_Asset->IsDirty = true; + } + + bool useMetalnessMap = (material->MetalnessTexToggle > 0.5f); + if (ImGui::Checkbox("Use Texture##Metalness", &useMetalnessMap)) + { + material->MetalnessTexToggle = useMetalnessMap ? 1.0f : 0.0f; + m_Asset->IsDirty = true; + } + + DrawTextureSlot(material->MetalnessTexture, [&](const Ref& newTex) { + material->MetalnessTexture = newTex; + material->MetalnessTexToggle = true; + m_Asset->IsDirty = true; + }); + ImGui::SameLine(); + ImGui::Text("Metalness Texture"); + + ImGui::Unindent(); + } + + // Roughness + if (ImGui::CollapsingHeader("Roughness", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::Indent(); + + if (ImGui::SliderFloat("Value##Roughness", &material->Roughness, 0.0f, 1.0f)) + { + // 自动保存 + m_Asset->IsDirty = true; + } + + bool useRoughnessMap = (material->RoughnessTexToggle > 0.5f); + if (ImGui::Checkbox("Use Texture##Roughness", &useRoughnessMap)) + { + material->RoughnessTexToggle = useRoughnessMap ? 1.0f : 0.0f; + m_Asset->IsDirty = true; + } + + DrawTextureSlot(material->RoughnessTexture, [&](const Ref& newTex) { + material->RoughnessTexture = newTex; + material->RoughnessTexToggle = true; + m_Asset->IsDirty = true; + }); + ImGui::SameLine(); + ImGui::Text("Roughness Texture"); + + ImGui::Unindent(); + } + + ImGui::EndTabItem(); + } + + // ==================== 预览 ==================== + if (ImGui::BeginTabItem("Preview")) + { + // 简单显示纹理预览 + if (material->AlbedoTexture) + { + ImGui::Text("Albedo Preview"); + ImGui::Image((ImTextureID)(intptr_t)material->AlbedoTexture->GetRendererID(), ImVec2(128, 128)); + } + ImGui::EndTabItem(); + } + + ImGui::EndTabBar(); + } + } + } diff --git a/Prism/src/Prism/Editor/DefaultAssetEditors.h b/Prism/src/Prism/Editor/DefaultAssetEditors.h index b367cd2..587c5b9 100644 --- a/Prism/src/Prism/Editor/DefaultAssetEditors.h +++ b/Prism/src/Prism/Editor/DefaultAssetEditors.h @@ -15,14 +15,14 @@ namespace Prism public: PhysicsMaterialEditor(); - virtual Ref GetAsset() override { return m_Asset; } - virtual void SetAsset(const Ref& asset) override { m_Asset = (Ref)asset; } + Ref GetAsset() override { return m_Asset; } + void SetAsset(const Ref& asset) override; private: - virtual void Render() override; + void Render() override; private: - Ref m_Asset; + Ref m_Asset; }; class TextureViewer : public AssetEditor @@ -30,16 +30,31 @@ namespace Prism public: TextureViewer(); - virtual Ref GetAsset() override { return m_Asset; } - virtual void SetAsset(const Ref& asset) override { m_Asset = static_cast>(asset); } + Ref GetAsset() override { return m_Asset; } + void SetAsset(const Ref& asset) override; private: - virtual void Render() override; + void Render() override; private: Ref m_Asset; }; + class PBRMaterialEditor : public AssetEditor + { + public: + PBRMaterialEditor(); + + Ref GetAsset() override { return m_Asset; } + void SetAsset(const Ref& asset) override; + + private: + void Render() override; + + private: + Ref m_Asset; + }; + } #endif //PRISM_DEFAULTASSETEDITORS_H \ No newline at end of file diff --git a/Prism/src/Prism/Editor/SceneHierachyPanel.cpp b/Prism/src/Prism/Editor/SceneHierachyPanel.cpp index cbd5492..aee12b3 100644 --- a/Prism/src/Prism/Editor/SceneHierachyPanel.cpp +++ b/Prism/src/Prism/Editor/SceneHierachyPanel.cpp @@ -14,6 +14,7 @@ #include #include +#include "AssetEditorPanel.h" #include "Prism/Core/Application.h" #include "Prism/Core/Math/Math.h" #include "Prism/Physics/PhysicsLayer.h" @@ -547,7 +548,7 @@ namespace Prism template static void DrawComponent(const std::string& name, Entity entity, UIFunction uiFunction) { - const ImGuiTreeNodeFlags treeNodeFlags = ImGuiTreeNodeFlags_DefaultOpen | + constexpr ImGuiTreeNodeFlags treeNodeFlags = ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_AllowOverlap | @@ -886,13 +887,50 @@ namespace Prism DrawComponent("Mesh", entity, [](MeshComponent& meshComponent) { UI::BeginPropertyGrid(); - UI::PropertyAssetReference("Mesh", meshComponent.Mesh, AssetType::Mesh); - // UI::Property("AnimationPlaying", meshComponent.Mesh->m_AnimationPlaying); - // UI::Property("TimeMultiple", meshComponent.Mesh->m_TimeMultiplier); - // UI::Property("AnimationTime", meshComponent.Mesh->m_AnimationTime); - // UI::Property("WorldTime", meshComponent.Mesh->m_WorldTime); + if (UI::PropertyAssetReference("Mesh", meshComponent.Mesh, AssetType::Mesh)) + { + meshComponent.MaterialInstances.clear(); + meshComponent.MaterialDescs.clear(); + const auto& materialInstances = meshComponent.Mesh->GetMaterials(); + for (uint32_t i = 0; i < materialInstances.size(); i++) + { + Ref materialInstance = MaterialInstance::Copy(materialInstances[i]); + meshComponent.MaterialInstances.push_back(materialInstance); + } + meshComponent.MaterialDescs.resize(materialInstances.size()); + } UI::EndPropertyGrid(); + + for (auto i = 0; i < meshComponent.MaterialDescs.size(); i++) + { + + // TODO: 这里通过 MaterialDesc进行存储信息,然后修改后由此处更新MaterialInstances,同时还缺少一个在MeshComponent中MaterialDesc的序列化 + if (UI::BeginTreeNode((std::string("Slot ") + std::to_string(i)).c_str())) + { + UI::BeginPropertyGrid(); + if (meshComponent.MaterialDescs[i]) + { + if (ImGui::Button("X")) + { + meshComponent.MaterialDescs[i] = nullptr; + meshComponent.UpdateMaterials(i); + } + ImGui::SameLine(); + } + + if (ImGui::Button("Edit")) AssetEditorPanel::OpenEditor(meshComponent.MaterialDescs[i]); + ImGui::SameLine(); + if (UI::PropertyAssetReference(meshComponent.MaterialInstances[i]->GetName().c_str(), meshComponent.MaterialDescs[i], AssetType::Material)) + { + meshComponent.UpdateMaterials(-1, true); + } + UI::EndPropertyGrid(); + + UI::EndTreeNode(); + } + } + }); DrawComponent("AnimatorController", entity, [this](AnimationComponent& animatorComponent) @@ -1360,7 +1398,7 @@ namespace Prism if (UI::Property("Size", bcc.Size)) { - bcc.DebugMesh = MeshFactory::CreateBox(bcc.Size); + bcc.DebugMesh = MeshFactory::CreateBox(bcc.Size * 2.0f); } UI::Property("IsTrigger", bcc.IsTrigger); diff --git a/Prism/src/Prism/Physics/PhysicsActor.cpp b/Prism/src/Prism/Physics/PhysicsActor.cpp index cc5d253..ed322e3 100644 --- a/Prism/src/Prism/Physics/PhysicsActor.cpp +++ b/Prism/src/Prism/Physics/PhysicsActor.cpp @@ -11,6 +11,8 @@ #include "Prism/Script/ScriptEngine.h" #include +#include "glm/gtx/euler_angles.hpp" + namespace Prism { PhysicsActor::PhysicsActor(Entity entity) @@ -177,15 +179,24 @@ namespace Prism Ref scene = Scene::GetScene(m_Entity.GetSceneUUID()); glm::mat4 transform = scene->GetTransformRelativeToParent(m_Entity); - if (m_RigidBody.BodyType == RigidBodyComponent::Type::Static) - { - m_ActorInternal = physics.createRigidStatic(ToPhysXTransform(transform)); - } - else + glm::vec3 translation, rotationEuler, scale; + Math::DecomposeTransform(transform, translation, rotationEuler, scale); + + const glm::mat4 rotMat = glm::eulerAngleYXZ(rotationEuler.y, rotationEuler.x, rotationEuler.z); + const glm::quat rotationQuat = glm::quat_cast(rotMat); + + physx::PxTransform pxTransform(ToPhysXVector(translation), ToPhysXQuat(rotationQuat)); + + // PhysicsActor::Initialize 中 + m_WorldScale = scale; + + + if (IsDynamic()) { + const PhysicsSettings& settings = Physics3D::GetSettings(); - physx::PxRigidDynamic* actor = physics.createRigidDynamic(ToPhysXTransform(transform)); + physx::PxRigidDynamic* actor = physics.createRigidDynamic(pxTransform); actor->setLinearDamping(m_RigidBody.LinearDrag); actor->setAngularDamping(m_RigidBody.AngularDrag); actor->setRigidBodyFlag(physx::PxRigidBodyFlag::eKINEMATIC, m_RigidBody.IsKinematic); @@ -198,15 +209,26 @@ namespace Prism actor->setActorFlag(physx::PxActorFlag::eDISABLE_GRAVITY, m_RigidBody.DisableGravity); actor->setSolverIterationCounts(settings.SolverIterations, settings.SolverVelocityIterations); - physx::PxRigidBodyExt::setMassAndUpdateInertia(*actor, m_RigidBody.Mass); m_ActorInternal = actor; } + else + { + m_ActorInternal = physics.createRigidStatic(pxTransform); + } + // Add Collider if (m_Entity.HasComponent()) PhysicsWrappers::AddBoxCollider(*this); if (m_Entity.HasComponent()) PhysicsWrappers::AddSphereCollider(*this); if (m_Entity.HasComponent()) PhysicsWrappers::AddCapsuleCollider(*this); if (m_Entity.HasComponent()) PhysicsWrappers::AddMeshCollider(*this); + + if (IsDynamic()) + { + auto* dynamicActor = static_cast(m_ActorInternal); + physx::PxRigidBodyExt::setMassAndUpdateInertia(*dynamicActor, m_RigidBody.Mass); + } + if (!PhysicsLayerManager::IsLayerValid(m_RigidBody.Layer)) m_RigidBody.Layer = 0; diff --git a/Prism/src/Prism/Physics/PhysicsActor.h b/Prism/src/Prism/Physics/PhysicsActor.h index 9d73233..11468f3 100644 --- a/Prism/src/Prism/Physics/PhysicsActor.h +++ b/Prism/src/Prism/Physics/PhysicsActor.h @@ -49,6 +49,8 @@ namespace Prism Entity& GetEntity() { return m_Entity; } + glm::vec3 GetWorldScale() const { return m_WorldScale; } + private: void Initialize(); void Spawn() const; @@ -64,6 +66,8 @@ namespace Prism physx::PxRigidActor* m_ActorInternal; + glm::vec3 m_WorldScale = glm::vec3(1.0f); + friend class Physics3D; friend class PhysicsWrappers; diff --git a/Prism/src/Prism/Physics/PhysicsUtils.cpp b/Prism/src/Prism/Physics/PhysicsUtils.cpp index 5d296ad..2e282e9 100644 --- a/Prism/src/Prism/Physics/PhysicsUtils.cpp +++ b/Prism/src/Prism/Physics/PhysicsUtils.cpp @@ -36,12 +36,12 @@ namespace Prism physx::PxVec3 ToPhysXVector(const glm::vec3& vector) { - return *(physx::PxVec3*)&vector; + return physx::PxVec3(vector.x, vector.y, vector.z); } physx::PxVec4 ToPhysXVector(const glm::vec4& vector) { - return *(physx::PxVec4*)&vector; + return physx::PxVec4(vector.x, vector.y, vector.z, vector.w); } physx::PxQuat ToPhysXQuat(const glm::quat& quat) diff --git a/Prism/src/Prism/Physics/PhysicsWrappers.cpp b/Prism/src/Prism/Physics/PhysicsWrappers.cpp index f3797b8..5a99920 100644 --- a/Prism/src/Prism/Physics/PhysicsWrappers.cpp +++ b/Prism/src/Prism/Physics/PhysicsWrappers.cpp @@ -184,16 +184,11 @@ namespace Prism auto& collider = actor.m_Entity.GetComponent(); if (!collider.Material) - collider.Material = Ref::Create(0.6F, 0.6F, 0.0f); + collider.Material = Ref::Create(0.6F, 0.6F, 0.0f); - const glm::vec3 scale = actor.m_Entity.Transform().Scale; - glm::vec3 colliderSize = collider.Size; + glm::vec3 colliderSize = collider.Size * actor.GetWorldScale(); - if (scale.x != 0.0f) colliderSize.x *= scale.x; - if (scale.y != 0.0f) colliderSize.y *= scale.y; - if (scale.z != 0.0f) colliderSize.z *= scale.z; - - const auto boxGeometry = physx::PxBoxGeometry(colliderSize.x / 2.0f, colliderSize.y / 2.0f, colliderSize.z / 2.0f); + const auto boxGeometry = physx::PxBoxGeometry(colliderSize.x, colliderSize.y, colliderSize.z); const physx::PxMaterial* material = s_Physics->createMaterial(collider.Material->StaticFriction, collider.Material->DynamicFriction, collider.Material->Bounciness); physx::PxShape* shape = physx::PxRigidActorExt::createExclusiveShape(*actor.m_ActorInternal, boxGeometry, *material); @@ -207,7 +202,7 @@ namespace Prism { auto& collider = actor.m_Entity.GetComponent(); if (!collider.Material) - collider.Material = Ref::Create(0.6F, 0.6F, 0.0f); + collider.Material = Ref::Create(0.6F, 0.6F, 0.0f); const glm::vec3 scale = actor.m_Entity.Transform().Scale; float colliderRadius = collider.Radius; @@ -227,7 +222,7 @@ namespace Prism { auto& collider = actor.m_Entity.GetComponent(); if (!collider.Material) - collider.Material = Ref::Create(0.6F, 0.6F, 0.0f); + collider.Material = Ref::Create(0.6F, 0.6F, 0.0f); const glm::vec3 scale = actor.m_Entity.Transform().Scale; float colliderRadius = collider.Radius; @@ -255,7 +250,7 @@ namespace Prism { auto& collider = actor.m_Entity.GetComponent(); if (!collider.Material) - collider.Material = Ref::Create(0.6f, 0.6f, 0.0f); + collider.Material = Ref::Create(0.6f, 0.6f, 0.0f); glm::vec3 scale = actor.m_Entity.Transform().Scale; physx::PxMaterial* material = s_Physics->createMaterial(collider.Material->StaticFriction, collider.Material->DynamicFriction, collider.Material->Bounciness); diff --git a/Prism/src/Prism/Platform/OpenGL/OpenGLRenderPass.h b/Prism/src/Prism/Platform/OpenGL/OpenGLRenderPass.h index 90c66d3..3261856 100644 --- a/Prism/src/Prism/Platform/OpenGL/OpenGLRenderPass.h +++ b/Prism/src/Prism/Platform/OpenGL/OpenGLRenderPass.h @@ -15,8 +15,8 @@ namespace Prism OpenGLRenderPass(const RenderPassSpecification& spec); virtual ~OpenGLRenderPass(); - virtual RenderPassSpecification& GetSpecification() override { return m_Spec; } - virtual const RenderPassSpecification& GetSpecification() const { return m_Spec; } + RenderPassSpecification& GetSpecification() override { return m_Spec; } + const RenderPassSpecification& GetSpecification() const override { return m_Spec; } private: RenderPassSpecification m_Spec; diff --git a/Prism/src/Prism/Platform/OpenGL/OpenGLRendererAPI.cpp b/Prism/src/Prism/Platform/OpenGL/OpenGLRendererAPI.cpp index 0191703..4393b02 100644 --- a/Prism/src/Prism/Platform/OpenGL/OpenGLRendererAPI.cpp +++ b/Prism/src/Prism/Platform/OpenGL/OpenGLRendererAPI.cpp @@ -157,10 +157,13 @@ namespace Prism glClearColor(r, g, b, a); } - void RendererAPI::DrawIndexed(uint32_t count, PrimitiveType type, bool depthTest, bool faceCulling) + void RendererAPI::DrawIndexed(const uint32_t count, const PrimitiveType type, const bool depthTest, const bool faceCulling) { if (!depthTest) + { glDisable(GL_DEPTH_TEST); + glDisable(GL_BLEND); + } GLenum glPrimitiveType = 0; switch (type) @@ -181,7 +184,10 @@ namespace Prism glDrawElements(glPrimitiveType, count, GL_UNSIGNED_INT, nullptr); if (!depthTest) + { + glEnable(GL_BLEND); glEnable(GL_DEPTH_TEST); + } } void RendererAPI::SetLineThickness(const float thickness) diff --git a/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.cpp b/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.cpp index 173e84a..812472f 100644 --- a/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.cpp +++ b/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.cpp @@ -54,7 +54,7 @@ namespace Prism // Texture2D // ****************************************** - OpenGLTexture2D::OpenGLTexture2D(TextureFormat format, uint32_t width, uint32_t height, TextureWrap wrap) + OpenGLTexture2D::OpenGLTexture2D(const TextureFormat format, const uint32_t width, const uint32_t height, const TextureWrap wrap) : m_Format(format), m_Width(width), m_Height(height), m_Wrap(wrap) { Ref instance = this; @@ -83,6 +83,53 @@ namespace Prism m_ImageData.Allocate(width * height * GetBPP(m_Format)); } + OpenGLTexture2D::OpenGLTexture2D(const TextureFormat format, const uint32_t width, const uint32_t height, const void* data, const TextureWrap wrap) + : m_Format(format), m_Width(width), m_Height(height), m_Wrap(wrap) + { + // 计算图像数据大小(假设是 RGBA8,或根据格式动态计算) + uint32_t bpp = GetBPP(format); + uint32_t dataSize = width * height * bpp; + + // 保存一份数据到 CPU 缓冲区(供后续可能的读取) + if (data) + { + m_ImageData.Allocate(dataSize); + memcpy(m_ImageData.Data, data, dataSize); + } + else + { + m_ImageData.Allocate(dataSize); + memset(m_ImageData.Data, 0, dataSize); // 可选:初始化为0 + } + + Ref instance = this; + Renderer::Submit([instance]() mutable { + glGenTextures(1, &instance->m_RendererID); + glBindTexture(GL_TEXTURE_2D, instance->m_RendererID); + + // 设置纹理参数 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + GLint wrap = instance->m_Wrap == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT; + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap); + glTextureParameterf(instance->m_RendererID, GL_TEXTURE_MAX_ANISOTROPY, RendererAPI::GetCapabilities().MaxAnisotropy); + + // 上传数据(如果已有数据则使用,否则传 nullptr 创建空纹理) + glTexImage2D(GL_TEXTURE_2D, 0, + SizedInternalFormat(instance->m_Format), + (GLint)instance->m_Width, (GLint)instance->m_Height, 0, + ImageFormat(instance->m_Format), + DataType(instance->m_Format), + instance->m_ImageData.Data); // 这里传入数据指针 + + // 如果需要生成 mipmap,取消注释下一行 + // glGenerateMipmap(GL_TEXTURE_2D); + + glBindTexture(GL_TEXTURE_2D, 0); + }); + } + OpenGLTexture2D::OpenGLTexture2D(const std::string& path, bool srgb) : m_FilePath(path) diff --git a/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.h b/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.h index ebee207..d2d9669 100644 --- a/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.h +++ b/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.h @@ -14,6 +14,7 @@ namespace Prism { public: OpenGLTexture2D(TextureFormat format, uint32_t width, uint32_t height, TextureWrap wrap); + OpenGLTexture2D(TextureFormat format, uint32_t width, uint32_t height, const void* data, TextureWrap wrap = TextureWrap::Clamp); OpenGLTexture2D(const std::string& path, bool srgb); virtual ~OpenGLTexture2D(); diff --git a/Prism/src/Prism/Platform/Windows/WindowsFileSystemWatcher.cpp b/Prism/src/Prism/Platform/Windows/WindowsFileSystemWatcher.cpp index 98d97a2..e2385cf 100644 --- a/Prism/src/Prism/Platform/Windows/WindowsFileSystemWatcher.cpp +++ b/Prism/src/Prism/Platform/Windows/WindowsFileSystemWatcher.cpp @@ -16,6 +16,7 @@ #include "Prism/Core/Application.h" #include "efsw/efsw.hpp" +#include "Prism/Utilities/StringUtils.h" namespace Prism { @@ -30,22 +31,22 @@ namespace Prism public: void handleFileAction(efsw::WatchID watchid, const std::string& dir, - const std::string& filename, + const std::string& filepath, efsw::Action action, - std::string oldFilename = "") override + std::string oldFilepath = "") override { // 如果引擎自身操作设置了忽略标志,则跳过本次事件 if (FileSystem::s_IgnoreNextChange.load()) return; - std::string fullPath = (std::filesystem::path(dir) / filename).string(); + std::string fullPath = (std::filesystem::path(dir) / filepath).string(); - std::replace(fullPath.begin(), fullPath.end(), '\\', '/'); + fullPath = Utils::NormalizePath(fullPath); FileSystemChangedEvent e; e.FilePath = fullPath; - e.NewName = filename; - e.OldName = oldFilename; // efsw 在重命名时会提供旧文件名 + e.NewName = Utils::GetFilename(filepath); + e.OldName = Utils::GetFilename(oldFilepath); // efsw 在重命名时会提供旧文件名 e.IsDirectory = false; // 稍后根据实际情况判断 // 判断是否为目录(可能抛出异常,使用 error_code 版本) @@ -163,6 +164,30 @@ namespace Prism return result ? std::string(result) : std::string(); } + void FileSystem::OpenInExplorer(const std::string& path) + { + const std::filesystem::path absPath = std::filesystem::absolute(path); + if (!std::filesystem::exists(absPath)) + { + PM_CORE_WARN("Path does not exist: {}", path); + return; + } + + std::string cmd; + if (std::filesystem::is_directory(absPath)) + { + // 打开目录 + cmd = absPath.string(); + ShellExecuteA(nullptr, "open", "explorer.exe", cmd.c_str(), NULL, SW_SHOW); + } + else + { + // 打开并选中文件 + cmd = "/select, \"" + absPath.string() + "\""; + ShellExecuteA(nullptr, "open", "explorer.exe", cmd.c_str(), NULL, SW_SHOW); + } + } + bool FileSystem::CreateFolder(const std::filesystem::path& filepath) { diff --git a/Prism/src/Prism/Renderer/Material.cpp b/Prism/src/Prism/Renderer/Material.cpp index a82689d..fbab3f1 100644 --- a/Prism/src/Prism/Renderer/Material.cpp +++ b/Prism/src/Prism/Renderer/Material.cpp @@ -140,6 +140,27 @@ namespace Prism return Ref::Create(material); } + + Ref MaterialInstance::Copy(Ref other) + { + if (!other) return nullptr; + + auto newInstance = Create(other->m_Material); + newInstance->m_Name = other->m_Name + "_Override"; + + // 复制 uniform 缓冲区 + newInstance->m_VSUniformStorageBuffer = Buffer::Copy(other->m_VSUniformStorageBuffer.Data, other->m_VSUniformStorageBuffer.GetSize()); + newInstance->m_PSUniformStorageBuffer = Buffer::Copy(other->m_PSUniformStorageBuffer.Data, other->m_PSUniformStorageBuffer.GetSize()); + + // 复制纹理列表(共享纹理引用) + newInstance->m_Textures = other->m_Textures; + + // 复制覆盖标记集合 + newInstance->m_OverriddenValues = other->m_OverriddenValues; + + return newInstance; + } + void MaterialInstance::OnShaderReloaded() { AllocateStorage(); diff --git a/Prism/src/Prism/Renderer/Material.h b/Prism/src/Prism/Renderer/Material.h index 487958a..d3f970f 100644 --- a/Prism/src/Prism/Renderer/Material.h +++ b/Prism/src/Prism/Renderer/Material.h @@ -119,6 +119,11 @@ namespace Prism static Ref Create(const Ref& material); + /** + * + * @param other copy other data to a new Data + * @return the new Data will as Ref return + */ static Ref Copy(Ref other); template diff --git a/Prism/src/Prism/Renderer/Mesh.cpp b/Prism/src/Prism/Renderer/Mesh.cpp index 30690af..8fcfa11 100644 --- a/Prism/src/Prism/Renderer/Mesh.cpp +++ b/Prism/src/Prism/Renderer/Mesh.cpp @@ -64,6 +64,13 @@ namespace Prism return result; } + static AABB UnionAABB(const AABB& a, const AABB& b) { + AABB result; + result.Min = glm::min(a.Min, b.Min); + result.Max = glm::max(a.Max, b.Max); + return result; + } + void AnimatedVertex::AddBoneData(uint32_t BoneID, float Weight) { @@ -300,9 +307,9 @@ namespace Prism std::string texturePath = parentPath.string(); PM_MESH_LOG(" Albedo map path = {0}", texturePath); - auto texture = AssetsManager::GetAsset(texturePath); + auto texture = AssetsManager::TryGetAsset(texturePath); // auto texture = Texture2D::Create(texturePath, true); - if (texture->Loaded()) + if (texture && texture->Loaded()) { m_Textures[i] = texture; mi->Set("u_AlbedoTexture", m_Textures[i]); @@ -333,9 +340,9 @@ namespace Prism std::string texturePath = parentPath.string(); PM_MESH_LOG(" Normal map path = {0}", texturePath); - auto texture = AssetsManager::GetAsset(texturePath); + auto texture = AssetsManager::TryGetAsset(texturePath); // auto texture = Texture2D::Create(texturePath); - if (texture->Loaded()) + if (texture && texture->Loaded()) { mi->Set("u_NormalTexture", texture); mi->Set("u_NormalTexToggle", 1.0f); @@ -362,9 +369,9 @@ namespace Prism std::string texturePath = parentPath.string(); PM_MESH_LOG(" Roughness map path = {0}", texturePath); - auto texture = AssetsManager::GetAsset(texturePath); + auto texture = AssetsManager::TryGetAsset(texturePath); // auto texture = Texture2D::Create(texturePath); - if (texture->Loaded()) + if (texture && texture->Loaded()) { PM_CORE_TRACE(" Roughness map path = {0}", texturePath); mi->Set("u_RoughnessTexture", texture); @@ -458,9 +465,9 @@ namespace Prism PM_MESH_LOG(" Metalness map path = {0}", texturePath); - auto texture = AssetsManager::GetAsset(texturePath); + auto texture = AssetsManager::TryGetAsset(texturePath); // auto texture = Texture2D::Create(texturePath); - if (texture->Loaded()) + if (texture && texture->Loaded()) { mi->Set("u_MetalnessTexture", texture); mi->Set("u_MetalnessTexToggle", 1.0f); @@ -517,6 +524,32 @@ namespace Prism PipelineSpecification pipelineSpecification; pipelineSpecification.Layout = vertexBufferLayout; m_Pipeline = Pipeline::Create(pipelineSpecification); + + + if (!m_IsAnimated) + { + for (const auto& submesh : m_Submeshes) { + glm::vec3 corners[8]; + corners[0] = submesh.Transform * glm::vec4(submesh.BoundingBox.Min, 1.0f); + corners[1] = submesh.Transform * glm::vec4(submesh.BoundingBox.Max, 1.0f); + corners[2] = submesh.Transform * glm::vec4(glm::vec3(submesh.BoundingBox.Min.x, submesh.BoundingBox.Min.y, submesh.BoundingBox.Max.z), 1.0f); + corners[3] = submesh.Transform * glm::vec4(glm::vec3(submesh.BoundingBox.Min.x, submesh.BoundingBox.Max.y, submesh.BoundingBox.Min.z), 1.0f); + corners[4] = submesh.Transform * glm::vec4(glm::vec3(submesh.BoundingBox.Min.x, submesh.BoundingBox.Max.y, submesh.BoundingBox.Max.z), 1.0f); + corners[5] = submesh.Transform * glm::vec4(glm::vec3(submesh.BoundingBox.Max.x, submesh.BoundingBox.Min.y, submesh.BoundingBox.Min.z), 1.0f); + corners[6] = submesh.Transform * glm::vec4(glm::vec3(submesh.BoundingBox.Max.x, submesh.BoundingBox.Min.y, submesh.BoundingBox.Max.z), 1.0f); + corners[7] = submesh.Transform * glm::vec4(glm::vec3(submesh.BoundingBox.Max.x, submesh.BoundingBox.Max.y, submesh.BoundingBox.Min.z), 1.0f); + + AABB transformedAABB; + transformedAABB.Min = corners[0]; + transformedAABB.Max = corners[0]; + for (int i = 1; i < 8; ++i) { + transformedAABB.Min = glm::min(transformedAABB.Min, corners[i]); + transformedAABB.Max = glm::max(transformedAABB.Max, corners[i]); + } + + m_BoundingBox = UnionAABB(m_BoundingBox, transformedAABB); + } + } } Mesh::Mesh(const std::vector& vertices, const std::vector& indices, const glm::mat4& transform) @@ -541,6 +574,16 @@ namespace Prism { ShaderDataType::Float2, "a_TexCoord" }, }; m_Pipeline = Pipeline::Create(pipelineSpecification); + + + // boundingbox + m_BoundingBox.Min = glm::vec3(FLT_MAX); + m_BoundingBox.Max = glm::vec3(-FLT_MAX); + for (const auto& vertex : vertices) { + glm::vec3 transformedPos = transform * glm::vec4(vertex.Position, 1.0f); + m_BoundingBox.Min = glm::min(m_BoundingBox.Min, transformedPos); + m_BoundingBox.Max = glm::max(m_BoundingBox.Max, transformedPos); + } } Mesh::~Mesh() = default; @@ -569,6 +612,24 @@ namespace Prism */ } + void Mesh::TraverseNodes(const aiNode* node, const glm::mat4& parentTransform, uint32_t level) + { + const glm::mat4 localTransform = parentTransform * Mat4FromAssimpMat4(node->mTransformation); + glm::mat4 transform = parentTransform * localTransform; + for (uint32_t i = 0; i < node->mNumMeshes; i++) + { + const uint32_t mesh = node->mMeshes[i]; + auto& submesh = m_Submeshes[mesh]; + submesh.NodeName = node->mName.C_Str(); + submesh.Transform = transform; + submesh.LocalTransform = localTransform; + } + + for (uint32_t i = 0; i < node->mNumChildren; i++) + { + TraverseNodes(node->mChildren[i], localTransform, level + 1); + } + } void Mesh::DumpVertexBuffer() { @@ -657,24 +718,6 @@ namespace Prism } */ - void Mesh::TraverseNodes(const aiNode* node, const glm::mat4& parentTransform, uint32_t level) - { - const glm::mat4 localTransform = parentTransform * Mat4FromAssimpMat4(node->mTransformation); - glm::mat4 transform = parentTransform * localTransform; - for (uint32_t i = 0; i < node->mNumMeshes; i++) - { - const uint32_t mesh = node->mMeshes[i]; - auto& submesh = m_Submeshes[mesh]; - submesh.NodeName = node->mName.C_Str(); - submesh.Transform = transform; - submesh.LocalTransform = localTransform; - } - - for (uint32_t i = 0; i < node->mNumChildren; i++) - { - TraverseNodes(node->mChildren[i], localTransform, level + 1); - } - } /* const aiNodeAnim* Mesh::FindNodeAnim(const aiAnimation* animation, const std::string& nodeName) diff --git a/Prism/src/Prism/Renderer/Mesh.h b/Prism/src/Prism/Renderer/Mesh.h index 918fa60..cb5d2f2 100644 --- a/Prism/src/Prism/Renderer/Mesh.h +++ b/Prism/src/Prism/Renderer/Mesh.h @@ -141,6 +141,9 @@ namespace Prism { return m_AnimatorController ? m_AnimatorController->GetFinalBoneTransforms() : m_EmptyTransforms; } + + const AABB& GetBoundingBox() const { return m_BoundingBox; } + private: void TraverseNodes(const aiNode* node, const glm::mat4& parentTransform = glm::mat4(1.0f), uint32_t level = 0); @@ -182,6 +185,9 @@ namespace Prism // float m_TimeMultiplier = 1.0f; std::string m_FilePath; + + AABB m_BoundingBox; + private: friend class Renderer; friend class SceneHierarchyPanel; diff --git a/Prism/src/Prism/Renderer/RenderPass.h b/Prism/src/Prism/Renderer/RenderPass.h index dae3773..e46f79b 100644 --- a/Prism/src/Prism/Renderer/RenderPass.h +++ b/Prism/src/Prism/Renderer/RenderPass.h @@ -20,6 +20,7 @@ namespace Prism virtual ~RenderPass() = default; virtual RenderPassSpecification& GetSpecification() = 0; + virtual const RenderPassSpecification& GetSpecification() const = 0; static Ref Create(const RenderPassSpecification& spec); }; diff --git a/Prism/src/Prism/Renderer/Renderer.cpp b/Prism/src/Prism/Renderer/Renderer.cpp index 6ce7568..8d03405 100644 --- a/Prism/src/Prism/Renderer/Renderer.cpp +++ b/Prism/src/Prism/Renderer/Renderer.cpp @@ -42,8 +42,8 @@ namespace Prism // FullScreen Quad static float fullScreenQuadVertex[] = { -1.0f, -1.0f, 0.1f, 0.0f, 0.0f, - 1.0f, -1.0f, 0.1f, 1.0f, 0.0f, - 1.0f, 1.0f, 0.1f, 1.0f, 1.0f, + 1.0f, -1.0f, 0.1f, 1.0f, 0.0f, + 1.0f, 1.0f, 0.1f, 1.0f, 1.0f, -1.0f, 1.0f, 0.1f, 0.0f, 1.0f }; static uint32_t fullScreenQuadIndices[] = { @@ -66,7 +66,7 @@ namespace Prism { Submit([]() { - RendererAPI::Clear(0.0f, 0.0f, 0.0f, 1.0f); + RendererAPI::Clear(0.0f, 0.0f, 0.0f, 1.0f); }); } @@ -81,6 +81,13 @@ namespace Prism { } + Ref Renderer::GetShaderLibrary() + { + return s_Data.m_ShaderLibrary; + } + + + void Renderer::DrawIndexed(const uint32_t count, const PrimitiveType type, const bool depthTest, bool cullFace) { Submit([=]() { @@ -88,13 +95,6 @@ namespace Prism }); } - - - Ref Renderer::GetShaderLibrary() - { - return s_Data.m_ShaderLibrary; - } - void Renderer::SetLineThickness(const float thickness) { Submit([=]() { @@ -135,7 +135,7 @@ namespace Prism void Renderer::SubmitQuad(Ref& material, const glm::mat4& transform) { bool depthTest = true; - bool cullFace = true; + bool cullFace = true; if (material) { @@ -172,6 +172,55 @@ namespace Prism Renderer::DrawIndexed(6, PrimitiveType::Triangles, depthTest, cullFace); } + void Renderer::SubmitMesh(Ref& mesh, const glm::mat4& transform, const std::vector>& overrideMaterials) + { + // auto material = overrideMaterial ? overrideMaterial : mesh->GetMaterialInstance(); + // auto shader = material->GetShader(); + + // TODO: Sort this out + mesh->m_VertexBuffer->Bind(); + mesh->m_Pipeline->Bind(); + mesh->m_IndexBuffer->Bind(); + + const auto& materials = mesh->GetMaterials(); + for (Submesh& submesh : mesh->m_Submeshes) + { + // Material + auto material = overrideMaterials.empty() ? materials[submesh.MaterialIndex] : overrideMaterials[submesh.MaterialIndex]; + auto shader = material->GetShader(); + material->Bind(); + + if (mesh->m_IsAnimated) + { + const auto& boneTransform = mesh->GetBoneTransforms(); + for (size_t i = 0; i < boneTransform.size(); i++) + { + std::string uniformName = std::string("u_BoneTransforms[") + std::to_string(i) + std::string("]"); + shader->SetMat4(uniformName, boneTransform[i]); + } + } + shader->SetMat4("u_Transform", transform * submesh.Transform); + + Renderer::Submit([submesh, material]() { + if (material->GetFlag(MaterialFlag::DepthTest)) + { + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + } + else + glDisable(GL_DEPTH_TEST); + + if (!material->GetFlag(MaterialFlag::TwoSided)) + glEnable(GL_CULL_FACE); + else + glDisable(GL_CULL_FACE); + + + glDrawElementsBaseVertex(GL_TRIANGLES, submesh.IndexCount, GL_UNSIGNED_INT, (void*)(sizeof(uint32_t) * submesh.BaseIndex), submesh.BaseVertex); + }); + } + } + void Renderer::SubmitMesh(Ref& mesh, const glm::mat4& transform, const Ref& overrideMaterial) { // auto material = overrideMaterial ? overrideMaterial : mesh->GetMaterialInstance(); @@ -246,32 +295,6 @@ namespace Prism } } - void Renderer::DrawAABB(const Ref& mesh, const glm::mat4& transform, const glm::vec4& color) - { - for (const Submesh& submesh : mesh->m_Submeshes) - { - const auto& aabb = submesh.BoundingBox; - auto aabbTransform = transform * submesh.Transform; - DrawAABB(aabb, aabbTransform, color); - } - } - - void Renderer::DispatchCompute(int x, int y, int z) - { - Submit([x, y, z]() - { - RendererAPI::DispatchCompute(x, y, z); - }); - } - - void Renderer::MemoryBarrier(int barrier) - { - Submit([barrier]() - { - RendererAPI::MemoryBarrier(barrier); - }); - } - void Renderer::DrawAABB(const AABB& aabb, const glm::mat4& transform, const glm::vec4& color) { glm::vec4 min = { aabb.Min.x, aabb.Min.y, aabb.Min.z, 1.0f }; @@ -300,6 +323,32 @@ namespace Prism Renderer2D::DrawLine(corners[i], corners[i + 4], color); } + void Renderer::DrawAABB(const Ref& mesh, const glm::mat4& transform, const glm::vec4& color) + { + for (const Submesh& submesh : mesh->m_Submeshes) + { + const auto& aabb = submesh.BoundingBox; + auto aabbTransform = transform * submesh.Transform; + DrawAABB(aabb, aabbTransform, color); + } + } + + void Renderer::DispatchCompute(int x, int y, int z) + { + Submit([x, y, z]() + { + RendererAPI::DispatchCompute(x, y, z); + }); + } + + void Renderer::MemoryBarrier(int barrier) + { + Submit([barrier]() + { + RendererAPI::MemoryBarrier(barrier); + }); + } + RenderCommandQueue& Renderer::GetRenderCommandQueue() { return s_Data.m_CommandQueue; diff --git a/Prism/src/Prism/Renderer/Renderer.h b/Prism/src/Prism/Renderer/Renderer.h index 4be8899..0649dd6 100644 --- a/Prism/src/Prism/Renderer/Renderer.h +++ b/Prism/src/Prism/Renderer/Renderer.h @@ -54,7 +54,8 @@ namespace Prism static void SubmitQuad(Ref& material, const glm::mat4& transform = glm::mat4(1.0f)); static void SubmitFullscreenQuad(Ref material); - static void SubmitMesh(Ref& mesh, const glm::mat4& transform, const Ref& overrideMaterial = nullptr); + static void SubmitMesh(Ref& mesh, const glm::mat4& transform, const std::vector>& overrideMaterials = {}); + static void SubmitMesh(Ref& mesh, const glm::mat4& transform, const Ref& overrideMaterial = nullptr); static void SubmitMeshWithShader(Ref mesh, const glm::mat4& transform, Ref shader); static void DrawAABB(const AABB& aabb, const glm::mat4& transform, const glm::vec4& color = glm::vec4(1.0f)); diff --git a/Prism/src/Prism/Renderer/Renderer3D.cpp b/Prism/src/Prism/Renderer/Renderer3D.cpp index 1b71f89..03e60f7 100644 --- a/Prism/src/Prism/Renderer/Renderer3D.cpp +++ b/Prism/src/Prism/Renderer/Renderer3D.cpp @@ -100,7 +100,7 @@ namespace Prism struct DrawCommand { Ref mesh; - Ref Material; + std::vector> MaterialInstances; glm::mat4 Transform; }; std::vector DrawList; @@ -128,6 +128,7 @@ namespace Prism SceneRendererOptions Options; Ref BlackCubeTexture; + Ref BlackTexture; }; struct Renderer3DStats @@ -267,6 +268,7 @@ namespace Prism uint32_t blackTextureData[6] = { 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000 }; s_Data.BlackCubeTexture = TextureCube::Create(TextureFormat::RGBA, 1, 1, &blackTextureData); + s_Data.BlackTexture = Texture2D::Create(TextureFormat::RGBA, 1, 1, &blackTextureData[0]); } void Renderer3D::SetViewportSize(const uint32_t width, const uint32_t height) @@ -295,39 +297,39 @@ namespace Prism FlushDrawList(renderPass); } - void Renderer3D::SubmitMesh(const Ref& mesh, const glm::mat4& transform, const Ref& overrideMaterial) + void Renderer3D::SubmitMesh(const Ref& mesh, const glm::mat4& transform, const std::vector>& overrideMaterials) { // TODO: Culling, sorting, etc. - s_Data.DrawList.push_back({ mesh, overrideMaterial, transform }); - s_Data.ShadowPassDrawList.push_back({ mesh, overrideMaterial, transform }); + s_Data.DrawList.push_back({ mesh, overrideMaterials, transform }); + s_Data.ShadowPassDrawList.push_back({ mesh, overrideMaterials, transform }); } - void Renderer3D::SubmitSelectedMesh(const Ref& mesh, const glm::mat4& transform) + void Renderer3D::SubmitSelectedMesh(const Ref& mesh, const glm::mat4& transform, const std::vector>& overrideMaterials) { - s_Data.SelectedMeshDrawList.push_back({ mesh, nullptr, transform }); - s_Data.ShadowPassDrawList.push_back({ mesh, nullptr, transform }); + s_Data.SelectedMeshDrawList.push_back({ mesh, overrideMaterials, transform }); + s_Data.ShadowPassDrawList.push_back({ mesh, overrideMaterials, transform }); } void Renderer3D::SubmitColliderMesh(const BoxColliderComponent& component, const glm::mat4& parentTransform) { - s_Data.ColliderDrawList.push_back({ component.DebugMesh, nullptr, glm::translate(parentTransform, component.Offset)}); + s_Data.ColliderDrawList.push_back({ component.DebugMesh, {}, glm::translate(parentTransform, component.Offset)}); } void Renderer3D::SubmitColliderMesh(const SphereColliderComponent& component, const glm::mat4& parentTransform) { - s_Data.ColliderDrawList.push_back({ component.DebugMesh, nullptr, parentTransform }); + s_Data.ColliderDrawList.push_back({ component.DebugMesh, {}, parentTransform }); } void Renderer3D::SubmitColliderMesh(const CapsuleColliderComponent& component, const glm::mat4& parentTransform) { - s_Data.ColliderDrawList.push_back({ component.DebugMesh, nullptr, parentTransform }); + s_Data.ColliderDrawList.push_back({ component.DebugMesh, {}, parentTransform }); } void Renderer3D::SubmitColliderMesh(const MeshColliderComponent& component, const glm::mat4& parentTransform) { - for (const auto debugMesh : component.ProcessedMeshes) - s_Data.ColliderDrawList.push_back({ debugMesh, nullptr, parentTransform }); + for (const auto& debugMesh : component.ProcessedMeshes) + s_Data.ColliderDrawList.push_back({ debugMesh, {}, parentTransform }); } // TODO: temp @@ -451,6 +453,11 @@ namespace Prism return s_Data.BlackCubeTexture; } + Ref Renderer3D::GetBlackTexture() + { + return s_Data.BlackTexture; + } + void Renderer3D::FlushDrawList(Ref& outRenderPass) { @@ -468,24 +475,22 @@ namespace Prism Renderer::Submit([] { s_Stats.GeometryPass = s_Stats.GeometryPassTimer.ElapsedMillis(); }); } - ResolveMSAA(); - - // Compute average luminance and update exposure (GPU-copy + mipmap -> read 1 texel) { Renderer::Submit([]() { s_Stats.AutoExposurePassTimer.Reset(); }); AutoExposurePass(); Renderer::Submit([] { s_Stats.AutoExposurePass = s_Stats.AutoExposurePassTimer.ElapsedMillis(); }); } + ResolveMSAA(); + BloomBlurPass(); - OverlayPass(); + GridPass(); { Renderer::Submit([]() { s_Stats.CompositePassTimer.Reset(); }); CompositePass(outRenderPass); Renderer::Submit([] { s_Stats.CompositePass = s_Stats.CompositePassTimer.ElapsedMillis(); }); - // BloomBlurPass(); } s_Data.DrawList.clear(); @@ -655,19 +660,6 @@ namespace Prism baseMaterial->Set("u_ViewProjectionMatrix", cameraViewProjection); baseMaterial->Set("u_ViewMatrix", sceneCamera.ViewMatrix); baseMaterial->Set("u_CameraPosition", cameraPosition); - // baseMaterial->Set("u_LightMatrixCascade0", s_Data.LightMatrices[0]); - // baseMaterial->Set("u_LightMatrixCascade1", s_Data.LightMatrices[1]); - // baseMaterial->Set("u_LightMatrixCascade2", s_Data.LightMatrices[2]); - // baseMaterial->Set("u_LightMatrixCascade3", s_Data.LightMatrices[3]); - // baseMaterial->Set("u_ShowCascades", s_Data.ShowCascades); - // baseMaterial->Set("u_LightView", s_Data.LightViewMatrix); - // baseMaterial->Set("u_CascadeSplits", s_Data.CascadeSplits); - // baseMaterial->Set("u_SoftShadows", s_Data.SoftShadows); - // baseMaterial->Set("u_LightSize", s_Data.LightSize); - // baseMaterial->Set("u_MaxShadowDistance", s_Data.MaxShadowDistance); - // baseMaterial->Set("u_ShadowFade", s_Data.ShadowFade); - // baseMaterial->Set("u_CascadeFading", s_Data.CascadeFading); - // baseMaterial->Set("u_CascadeTransitionFade", s_Data.CascadeTransitionFade); baseMaterial->Set("u_IBLContribution", s_Data.SceneData.SceneEnvironmentIntensity); // Environment (TODO: don't do this per mesh) @@ -704,38 +696,7 @@ namespace Prism }); } - /* - auto rd = baseMaterial->FindResourceDeclaration("u_ShadowMapTexture"); - if (rd) - { - auto reg = rd->GetRegister(); - - auto tex = s_Data.ShadowMapRenderPass[0]->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID(); - auto tex1 = s_Data.ShadowMapRenderPass[1]->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID(); - auto tex2 = s_Data.ShadowMapRenderPass[2]->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID(); - auto tex3 = s_Data.ShadowMapRenderPass[3]->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID(); - - Renderer::Submit([reg, tex, tex1, tex2, tex3]() mutable - { - // 4 cascades - glBindTextureUnit(reg, tex); - glBindSampler(reg++, s_Data.ShadowMapSampler); - - glBindTextureUnit(reg, tex1); - glBindSampler(reg++, s_Data.ShadowMapSampler); - - glBindTextureUnit(reg, tex2); - glBindSampler(reg++, s_Data.ShadowMapSampler); - - glBindTextureUnit(reg, tex3); - glBindSampler(reg++, s_Data.ShadowMapSampler); - }); - } - */ - - - constexpr auto overrideMaterial = nullptr; // dc.Material; - Renderer::SubmitMesh(dc.mesh, dc.Transform, overrideMaterial); + Renderer::SubmitMesh(dc.mesh, dc.Transform, dc.MaterialInstances); } if (outline) @@ -752,14 +713,6 @@ namespace Prism baseMaterial->Set("u_ViewProjectionMatrix", cameraViewProjection); baseMaterial->Set("u_ViewMatrix", sceneCamera.ViewMatrix); baseMaterial->Set("u_CameraPosition", cameraPosition); - // baseMaterial->Set("u_CascadeSplits", s_Data.CascadeSplits); - // baseMaterial->Set("u_ShowCascades", s_Data.ShowCascades); - // baseMaterial->Set("u_SoftShadows", s_Data.SoftShadows); - // baseMaterial->Set("u_LightSize", s_Data.LightSize); - // baseMaterial->Set("u_MaxShadowDistance", s_Data.MaxShadowDistance); - // baseMaterial->Set("u_ShadowFade", s_Data.ShadowFade); - // baseMaterial->Set("u_CascadeFading", s_Data.CascadeFading); - // baseMaterial->Set("u_CascadeTransitionFade", s_Data.CascadeTransitionFade); baseMaterial->Set("u_IBLContribution", s_Data.SceneData.SceneEnvironmentIntensity); @@ -768,11 +721,6 @@ namespace Prism baseMaterial->Set("u_EnvIrradianceTex", s_Data.SceneData.SceneEnvironment->IrradianceMap); baseMaterial->Set("u_BRDFLUTTexture", s_Data.BRDFLUT); - // baseMaterial->Set("u_LightMatrixCascade0", s_Data.LightMatrices[0]); - // baseMaterial->Set("u_LightMatrixCascade1", s_Data.LightMatrices[1]); - // baseMaterial->Set("u_LightMatrixCascade2", s_Data.LightMatrices[2]); - // baseMaterial->Set("u_LightMatrixCascade3", s_Data.LightMatrices[3]); - // Set lights (TODO: move to light environment and don't do per mesh) baseMaterial->Set("u_DirectionalLights", s_Data.SceneData.SceneLightEnvironment.DirectionalLights[0]); baseMaterial->Set("u_PointLightCount", s_Data.SceneData.SceneLightEnvironment.PointLightCount); @@ -801,37 +749,8 @@ namespace Prism glBindSampler(reg, s_Data.ShadowMapSampler); }); } - /* - auto rd = baseMaterial->FindResourceDeclaration("u_ShadowMapTexture"); - if (rd) - { - auto reg = rd->GetRegister(); - auto tex = s_Data.ShadowMapRenderPass[0]->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID(); - auto tex1 = s_Data.ShadowMapRenderPass[1]->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID(); - auto tex2 = s_Data.ShadowMapRenderPass[2]->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID(); - auto tex3 = s_Data.ShadowMapRenderPass[3]->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID(); - - Renderer::Submit([reg, tex, tex1, tex2, tex3]() mutable - { - // 4 cascades - glBindTextureUnit(reg, tex); - glBindSampler(reg++, s_Data.ShadowMapSampler); - - glBindTextureUnit(reg, tex1); - glBindSampler(reg++, s_Data.ShadowMapSampler); - - glBindTextureUnit(reg, tex2); - glBindSampler(reg++, s_Data.ShadowMapSampler); - - glBindTextureUnit(reg, tex3); - glBindSampler(reg++, s_Data.ShadowMapSampler); - }); - } - */ - - constexpr auto overrideMaterial = nullptr; // dc.Material; - Renderer::SubmitMesh(dc.mesh, dc.Transform, overrideMaterial); + Renderer::SubmitMesh(dc.mesh, dc.Transform, dc.MaterialInstances); } @@ -881,9 +800,6 @@ namespace Prism { Renderer::Submit([]() { - // glStencilFunc(GL_NOTEQUAL, 1, 0xff); - // glStencilMask(0); - glLineWidth(1); glEnable(GL_LINE_SMOOTH); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); @@ -912,8 +828,6 @@ namespace Prism Renderer::Submit([]() { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - // glStencilMask(0xff); - // glStencilFunc(GL_ALWAYS, 1, 0xff); glEnable(GL_DEPTH_TEST); }); } @@ -976,11 +890,6 @@ namespace Prism Renderer::EndRenderPass(); } - // 将最终模糊结果拷贝到 BloomBlendPass(供合成使用) - uint32_t finalBlurTex = (iterations % 2 == 0) ? - s_Data.BloomBlurPass[1]->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID() : - s_Data.BloomBlurPass[0]->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID(); - Renderer::BeginRenderPass(s_Data.BloomBlendPass); s_Data.BloomBlurShader->Bind(); s_Data.BloomBlurShader->SetInt("u_Texture", 0); @@ -994,12 +903,16 @@ namespace Prism Renderer::EndRenderPass(); } - void Renderer3D::OverlayPass() + void Renderer3D::GridPass() { Renderer::BeginRenderPass(s_Data.GeoPass, false); if (const auto option = GetOptions(); option.ShowGrid) { + Renderer::Submit([]() { + glDepthMask(GL_FALSE); + }); + const auto& sceneCamera = s_Data.SceneData.SceneCamera; const auto cameraProjection = sceneCamera.Camera.GetProjectionMatrix(); @@ -1019,6 +932,10 @@ namespace Prism s_Data.GridData.GridMaterial->Set("u_FadeDistance", s_Data.GridData.FadeDistance); Renderer::SubmitFullscreenQuad(s_Data.GridData.GridMaterial); + + Renderer::Submit([]() { + glDepthMask(GL_TRUE); + }); } Renderer::EndRenderPass(); @@ -1043,6 +960,18 @@ namespace Prism void Renderer3D::CompositePass(const Ref& outRenderPass) { + + Renderer::Submit([srcFB = s_Data.GeoPass->GetSpecification().TargetFramebuffer, + dstFB = outRenderPass->GetSpecification().TargetFramebuffer]() + { + glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFB->GetRendererID()); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFB->GetRendererID()); + glBlitFramebuffer(0, 0, srcFB->GetWidth(), srcFB->GetHeight(), + 0, 0, dstFB->GetWidth(), dstFB->GetHeight(), + GL_DEPTH_BUFFER_BIT, GL_NEAREST); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + }); + Renderer::BeginRenderPass(outRenderPass); s_Data.CompositeShader->Bind(); @@ -1054,10 +983,8 @@ namespace Prism s_Data.CompositeShader->SetBool("u_EnableBloom", s_Data.EnableBloom); // 绑定几何阶段颜色纹理(多重采样) - s_Data.GeoPass->GetSpecification().TargetFramebuffer->BindTexture(0); // 通常绑定到单元0 - Renderer::Submit([]() { - glBindTextureUnit(1, s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID()); - }); + s_Data.GeoPass->GetSpecification().TargetFramebuffer->BindTexture(); + s_Data.GeoPass->GetSpecification().TargetFramebuffer->BindDepthTexture(1); if (s_Data.EnableBloom) { @@ -1216,19 +1143,6 @@ namespace Prism UI::EndTreeNode(); } - /* - if (UI::BeginTreeNode("Auto Exposure", false)) - { - UI::BeginPropertyGrid(); - UI::Property("Enable Auto Exposure", s_Data.AutoExposureData.EnableAutoExposure); - UI::Property("Key (middle gray)", s_Data.AutoExposureData.Key, 0.001f, 0.001f, 2.5f); - UI::Property("Adaptation Speed", s_Data.AutoExposureData.AdaptationSpeed, 0.01f, 0.001f, 5.0f); - UI::Property("Current Exposure", s_Data.AutoExposureData.CurrentExposure, 0.01f, 0.0f, 0.0f, true); - UI::EndPropertyGrid(); - - UI::EndTreeNode(); - } - */ if (UI::BeginTreeNode("Auto Exposure", false)) { diff --git a/Prism/src/Prism/Renderer/Renderer3D.h b/Prism/src/Prism/Renderer/Renderer3D.h index e11a3ef..0ae2d19 100644 --- a/Prism/src/Prism/Renderer/Renderer3D.h +++ b/Prism/src/Prism/Renderer/Renderer3D.h @@ -33,8 +33,8 @@ namespace Prism static void BeginScene(const Scene* scene, const SceneRendererCamera& camera); static void EndScene(Ref& renderPass); - static void SubmitMesh(const Ref& mesh, const glm::mat4& transform = glm::mat4(1.0f), const Ref& overrideMaterial = nullptr); - static void SubmitSelectedMesh(const Ref& mesh, const glm::mat4& transform = glm::mat4(1.0f)); + static void SubmitMesh(const Ref& mesh, const glm::mat4& transform = glm::mat4(1.0f), const std::vector>& overrideMaterials = {}); + static void SubmitSelectedMesh(const Ref& mesh, const glm::mat4& transform = glm::mat4(1.0f), const std::vector>& overrideMaterials = {}); static void SubmitColliderMesh(const BoxColliderComponent& component, const glm::mat4& parentTransform = glm::mat4(1.0f)); static void SubmitColliderMesh(const SphereColliderComponent& component, const glm::mat4& parentTransform = glm::mat4(1.0f)); @@ -54,6 +54,7 @@ namespace Prism static SceneRendererOptions& GetOptions(); static Ref GetBlackCubeTexture(); + static Ref GetBlackTexture(); private: static void FlushDrawList(Ref& outRenderPass); @@ -62,7 +63,7 @@ namespace Prism static void ShadowMapPass(); static void GeometryPass(); static void BloomBlurPass(); - static void OverlayPass(); + static void GridPass(); static void CompositePass(const Ref& outRenderPass); diff --git a/Prism/src/Prism/Renderer/SceneRenderer.cpp b/Prism/src/Prism/Renderer/SceneRenderer.cpp index 5915c17..596baef 100644 --- a/Prism/src/Prism/Renderer/SceneRenderer.cpp +++ b/Prism/src/Prism/Renderer/SceneRenderer.cpp @@ -142,14 +142,14 @@ namespace Prism //////////////////// 3D API //////////////////// - void SceneRenderer::SubmitMesh(const Ref& mesh, const glm::mat4& transform, const Ref& overrideMaterial) + void SceneRenderer::SubmitMesh(const Ref& mesh, const glm::mat4& transform, const std::vector>& overrideMaterials) { - Renderer3D::SubmitMesh(mesh, transform, overrideMaterial); + Renderer3D::SubmitMesh(mesh, transform, overrideMaterials); } - void SceneRenderer::SubmitSelectedMesh(const Ref& mesh, const glm::mat4& transform) + void SceneRenderer::SubmitSelectedMesh(const Ref& mesh, const glm::mat4& transform, const std::vector>& overrideMaterials) { - Renderer3D::SubmitSelectedMesh(mesh, transform); + Renderer3D::SubmitSelectedMesh(mesh, transform, overrideMaterials); } void SceneRenderer::SubmitColliderMesh(const BoxColliderComponent& component, const glm::mat4& parentTransform) @@ -222,10 +222,10 @@ namespace Prism glBindFramebuffer(GL_READ_FRAMEBUFFER, fb->GetColorAttachmentRendererID()); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - glBlitFramebuffer(0, 0, fbWidth, fbHeight, // 源矩形 - 0, 0, fbWidth, fbHeight, // 目标矩形 - GL_COLOR_BUFFER_BIT, // 只复制颜色缓冲 - GL_NEAREST); // 过滤器 + glBlitFramebuffer(0, 0, fbWidth, fbHeight, + 0, 0, fbWidth, fbHeight, + GL_COLOR_BUFFER_BIT, + GL_NEAREST); }); } } diff --git a/Prism/src/Prism/Renderer/SceneRenderer.h b/Prism/src/Prism/Renderer/SceneRenderer.h index 4a8fe86..a6e806e 100644 --- a/Prism/src/Prism/Renderer/SceneRenderer.h +++ b/Prism/src/Prism/Renderer/SceneRenderer.h @@ -70,8 +70,8 @@ namespace Prism // Renderer3D - static void SubmitMesh(const Ref& mesh, const glm::mat4& transform = glm::mat4(1.0f), const Ref& overrideMaterial = nullptr); - static void SubmitSelectedMesh(const Ref& mesh, const glm::mat4& transform = glm::mat4(1.0f)); + static void SubmitMesh(const Ref& mesh, const glm::mat4& transform = glm::mat4(1.0f), const std::vector>& overrideMaterials = {}); + static void SubmitSelectedMesh(const Ref& mesh, const glm::mat4& transform = glm::mat4(1.0f), const std::vector>& overrideMaterials = {}); static void SubmitColliderMesh(const BoxColliderComponent& component, const glm::mat4& parentTransform = glm::mat4(1.0f)); static void SubmitColliderMesh(const SphereColliderComponent& component, const glm::mat4& parentTransform = glm::mat4(1.0f)); diff --git a/Prism/src/Prism/Renderer/Texture.cpp b/Prism/src/Prism/Renderer/Texture.cpp index 9affbae..e84aeb8 100644 --- a/Prism/src/Prism/Renderer/Texture.cpp +++ b/Prism/src/Prism/Renderer/Texture.cpp @@ -38,6 +38,16 @@ namespace Prism return nullptr; } + Ref Texture2D::Create(TextureFormat format, unsigned int width, unsigned int height, const void* data, TextureWrap wrap) + { + switch (RendererAPI::Current()) + { + case RendererAPIType::None: return nullptr; + case RendererAPIType::OpenGL: return Ref::Create(format, width, height, data, wrap); + } + return nullptr; + } + Ref Texture2D::Create(const std::string& path, bool srgb) { diff --git a/Prism/src/Prism/Renderer/Texture.h b/Prism/src/Prism/Renderer/Texture.h index 6223dfb..02f331e 100644 --- a/Prism/src/Prism/Renderer/Texture.h +++ b/Prism/src/Prism/Renderer/Texture.h @@ -5,9 +5,9 @@ #ifndef TEXTURE_H #define TEXTURE_H #include "RendererAPI.h" +#include "Prism/Asset/Asset.h" #include "Prism/Core/Buffer.h" #include "Prism/Core/Ref.h" -#include "../Asset/Asset.h" namespace Prism @@ -53,6 +53,7 @@ namespace Prism { public: static Ref Create(TextureFormat format, unsigned int width, unsigned int height, TextureWrap wrap = TextureWrap::Clamp); + static Ref Create(TextureFormat format, unsigned int width, unsigned int height, const void* data, TextureWrap wrap = TextureWrap::Clamp); static Ref Create(const std::string& path, bool srgb = false); diff --git a/Prism/src/Prism/Scene/Components.h b/Prism/src/Prism/Scene/Components.h index e41bdb1..1d9068b 100644 --- a/Prism/src/Prism/Scene/Components.h +++ b/Prism/src/Prism/Scene/Components.h @@ -81,8 +81,9 @@ namespace Prism } glm::mat4 GetTransform() const { + return glm::translate(glm::mat4(1.0f), Translation) - * glm::toMat4(glm::quat((Rotation))) + * glm::toMat4(glm::quat(Rotation)) * glm::scale(glm::mat4(1.0f), Scale); } }; @@ -91,32 +92,112 @@ namespace Prism struct MeshComponent { Ref Mesh; - // std::vector> Materials; + std::vector> MaterialInstances; + std::vector> MaterialDescs; MeshComponent() = default; - MeshComponent(const MeshComponent& other) = default; + MeshComponent(const MeshComponent& other) + : Mesh(other.Mesh) + { + MaterialInstances.clear(); + MaterialDescs.clear(); + for (auto i = 0; i < other.MaterialInstances.size(); i ++) + { + Ref materialInstance = MaterialInstance::Copy(other.MaterialInstances[i]); + MaterialInstances.push_back(materialInstance); + MaterialDescs.push_back(other.MaterialDescs[i]); + } + UpdateMaterials(); + } MeshComponent(const Ref& mesh) - : Mesh(mesh) {} - - operator Ref () { return Mesh; } - - /* - MeshComponent(Ref mesh) : Mesh(mesh) { - // 复制 Mesh 的材质实例,每个实体拥有独立副本 - if (mesh) + MaterialInstances.clear(); + MaterialDescs.clear(); + const auto& materialInstances = Mesh->GetMaterials(); + for (const auto & i : materialInstances) { - const auto& srcMaterials = mesh->GetMaterials(); - Materials.reserve(srcMaterials.size()); - for (auto& srcMat : srcMaterials) + Ref materialInstance = MaterialInstance::Copy(i); + MaterialInstances.push_back(materialInstance); + } + MaterialDescs.resize(materialInstances.size()); + } + + void UpdateMaterials(const int index = -1, bool forceUpdate = false) + { + if (index <= -1) + { + for (uint32_t i = 0; i < MaterialInstances.size(); i++) { - auto newMat = MaterialInstance::Copy(srcMat); - Materials.push_back(newMat); + if (auto& desc = MaterialDescs[i]) + { + if (!desc->IsDirty && !forceUpdate) continue; + MaterialInstances[i]->Set("u_AlbedoColor", desc->AlbedoColor); + MaterialInstances[i]->Set("u_AlbedoTexToggle", desc->AlbedoTexToggle); + MaterialInstances[i]->Set("u_AlbedoTexture", desc->AlbedoTexture); + MaterialInstances[i]->Set("u_NormalTexToggle", desc->NormalTexToggle); + MaterialInstances[i]->Set("u_NormalTexture", desc->NormalTexture); + MaterialInstances[i]->Set("u_Metalness", desc->Metalness); + MaterialInstances[i]->Set("u_MetalnessTexToggle", desc->MetalnessTexToggle); + MaterialInstances[i]->Set("u_MetalnessTexture", desc->MetalnessTexture); + MaterialInstances[i]->Set("u_Roughness", desc->Roughness); + MaterialInstances[i]->Set("u_RoughnessTexToggle", desc->RoughnessTexToggle); + MaterialInstances[i]->Set("u_RoughnessTexture", desc->RoughnessTexture); + }else + { + auto& baseMaterial = Mesh->GetMaterials(); + + MaterialInstances[i]->Set("u_AlbedoColor", baseMaterial[i]->Get("u_AlbedoColor")); + MaterialInstances[i]->Set("u_AlbedoTexToggle", baseMaterial[i]->Get("u_AlbedoTexToggle")); + MaterialInstances[i]->Set("u_AlbedoTexture", baseMaterial[i]->TryGetResource("u_AlbedoTexture")); + MaterialInstances[i]->Set("u_NormalTexToggle", baseMaterial[i]->Get("u_NormalTexToggle")); + MaterialInstances[i]->Set("u_NormalTexture", baseMaterial[i]->TryGetResource("u_NormalTexture")); + MaterialInstances[i]->Set("u_Metalness", baseMaterial[i]->Get("u_Metalness")); + MaterialInstances[i]->Set("u_MetalnessTexToggle", baseMaterial[i]->Get("u_MetalnessTexToggle")); + MaterialInstances[i]->Set("u_MetalnessTexture", baseMaterial[i]->TryGetResource("u_MetalnessTexture")); + MaterialInstances[i]->Set("u_Roughness", baseMaterial[0]->Get("u_Roughness")); + MaterialInstances[i]->Set("u_RoughnessTexToggle", baseMaterial[i]->Get("u_RoughnessTexToggle")); + MaterialInstances[i]->Set("u_RoughnessTexture", baseMaterial[i]->TryGetResource("u_RoughnessTexture")); + } } + }else + { + if (index >= MaterialInstances.size()) return; + const auto& desc = MaterialDescs[index]; + if (desc) + { + MaterialInstances[index]->Set("u_AlbedoColor", desc->AlbedoColor); + MaterialInstances[index]->Set("u_AlbedoTexToggle", desc->AlbedoTexToggle); + MaterialInstances[index]->Set("u_AlbedoTexture", desc->AlbedoTexture); + MaterialInstances[index]->Set("u_NormalTexToggle", desc->NormalTexToggle); + MaterialInstances[index]->Set("u_NormalTexture", desc->NormalTexture); + MaterialInstances[index]->Set("u_Metalness", desc->Metalness); + MaterialInstances[index]->Set("u_MetalnessTexToggle", desc->MetalnessTexToggle); + MaterialInstances[index]->Set("u_MetalnessTexture", desc->MetalnessTexture); + MaterialInstances[index]->Set("u_Roughness", desc->Roughness); + MaterialInstances[index]->Set("u_RoughnessTexToggle", desc->RoughnessTexToggle); + MaterialInstances[index]->Set("u_RoughnessTexture", desc->RoughnessTexture); + }else + { + auto& baseMaterial = Mesh->GetMaterials(); + + MaterialInstances[index]->Set("u_AlbedoColor", baseMaterial[index]->Get("u_AlbedoColor")); + MaterialInstances[index]->Set("u_AlbedoTexToggle", baseMaterial[index]->Get("u_AlbedoTexToggle")); + MaterialInstances[index]->Set("u_AlbedoTexture", baseMaterial[index]->TryGetResource("u_AlbedoTexture")); + MaterialInstances[index]->Set("u_NormalTexToggle", baseMaterial[index]->Get("u_NormalTexToggle")); + MaterialInstances[index]->Set("u_NormalTexture", baseMaterial[index]->TryGetResource("u_NormalTexture")); + MaterialInstances[index]->Set("u_Metalness", baseMaterial[index]->Get("u_Metalness")); + MaterialInstances[index]->Set("u_MetalnessTexToggle", baseMaterial[index]->Get("u_MetalnessTexToggle")); + MaterialInstances[index]->Set("u_MetalnessTexture", baseMaterial[index]->TryGetResource("u_MetalnessTexture")); + MaterialInstances[index]->Set("u_Roughness", baseMaterial[0]->Get("u_Roughness")); + MaterialInstances[index]->Set("u_RoughnessTexToggle", baseMaterial[index]->Get("u_RoughnessTexToggle")); + MaterialInstances[index]->Set("u_RoughnessTexture", baseMaterial[index]->TryGetResource("u_RoughnessTexture")); + } + } } - */ + + operator Ref () { return Mesh; } }; struct AnimationComponent @@ -305,7 +386,7 @@ namespace Prism { float Radius = 0.5f; bool IsTrigger = false; - Ref Material; + Ref Material; // The mesh that will be drawn in the editor to show the collision bounds Ref DebugMesh; @@ -344,7 +425,7 @@ namespace Prism glm::vec3 Size = { 1.0f, 1.0f, 1.0f }; glm::vec3 Offset = { 0.0f, 0.0f, 0.0f }; bool IsTrigger = false; - Ref Material; + Ref Material; // The mesh that will be drawn in the editor to show the collision bounds Ref DebugMesh; @@ -358,7 +439,7 @@ namespace Prism float Radius = 0.5f; float Height = 1.0f; bool IsTrigger = false; - Ref Material; + Ref Material; Ref DebugMesh; @@ -373,7 +454,7 @@ namespace Prism bool IsConvex = false; bool IsTrigger = false; bool OverrideMesh = false; - Ref Material; + Ref Material; MeshColliderComponent() = default; MeshColliderComponent(const MeshColliderComponent& other) = default; diff --git a/Prism/src/Prism/Scene/Scene.cpp b/Prism/src/Prism/Scene/Scene.cpp index 35a0307..8d29f39 100644 --- a/Prism/src/Prism/Scene/Scene.cpp +++ b/Prism/src/Prism/Scene/Scene.cpp @@ -81,6 +81,7 @@ namespace Prism { b2DestroyWorld(m_Registry.get(m_SceneEntity).World); Physics3D::DestroyScene(); + ScriptEngine::OnSceneDestruct(m_SceneID); } void Scene::OnUpdate(TimeStep ts) @@ -90,14 +91,14 @@ namespace Prism const auto sceneView = m_Registry.view(); const auto& box2DWorld = m_Registry.get(sceneView.front()).World; - int32_t velocityIterations = 6; constexpr int32_t positionIterations = 2; - // box2DWorld->Step(ts, velocityIterations, positionIterations); b2World_Step(box2DWorld, ts, positionIterations); - // Process Contact Envents box2d version 3.0^ should impl contact event after b2World_Step Physics2D::ProcessContactEvents(box2DWorld); + // Physics3D + Physics3D::Simulate(ts); + { const auto view = m_Registry.view(); for (const auto entity : view) @@ -137,8 +138,6 @@ namespace Prism } - Physics3D::Simulate(ts); - // Update all entities { const auto view = m_Registry.view(); @@ -149,6 +148,7 @@ namespace Prism ScriptEngine::OnUpdateEntity(e, ts); } } + } void Scene::OnRenderRuntime(const TimeStep ts) @@ -188,19 +188,35 @@ namespace Prism SceneRenderer::BeginScene(this, { static_cast(camera), cameraViewMatrix }, false); { const auto group = m_Registry.group(entt::get); + + // this maybe not to set + // in Editor actually only one materialdesc will be changed + Ref materialAsset; + for (const auto entity : group) { const auto& [transformComponent, meshComponent] = group.get(entity); if (meshComponent.Mesh) { + + for (auto i = 0; i < meshComponent.MaterialInstances.size(); i++) + { + if (meshComponent.MaterialDescs[i] && meshComponent.MaterialDescs[i]->IsDirty) + { + materialAsset = meshComponent.MaterialDescs[i]; + meshComponent.UpdateMaterials(i); + } + } + meshComponent.Mesh->OnUpdate(ts); glm::mat4 transform = GetTransformRelativeToParent(Entity(entity, this)); // TODO: Should we render (logically) - SceneRenderer::SubmitMesh(meshComponent, transform); + SceneRenderer::SubmitMesh(meshComponent, transform, meshComponent.MaterialInstances); } } + if (materialAsset) materialAsset->IsDirty = false; ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// @@ -271,21 +287,35 @@ namespace Prism const auto group = m_Registry.group(entt::get); { + + // in Editor actually only one materialdesc will be changed + Ref materialAsset; + for (const auto [entity, meshComponent, transformComponent]: group.each()) { Entity e = {entity, this}; if (meshComponent.Mesh) { + + for (auto i = 0; i < meshComponent.MaterialInstances.size(); i++) + { + if (meshComponent.MaterialDescs[i] && meshComponent.MaterialDescs[i]->IsDirty) + { + materialAsset = meshComponent.MaterialDescs[i]; + meshComponent.UpdateMaterials(i); + } + } + meshComponent.Mesh->OnUpdate(ts); glm::mat4 transform = GetTransformRelativeToParent(e); // TODO: Should we render (logically) if (m_SelectedEntity == entity) - SceneRenderer::SubmitSelectedMesh(meshComponent, transform); + SceneRenderer::SubmitSelectedMesh(meshComponent, transform, meshComponent.MaterialInstances); else - SceneRenderer::SubmitMesh(meshComponent, transform); + SceneRenderer::SubmitMesh(meshComponent, transform, meshComponent.MaterialInstances); } // Renderer Collider @@ -303,6 +333,8 @@ namespace Prism SceneRenderer::SubmitColliderMesh(*collider, transform); } } + + if (materialAsset) materialAsset->IsDirty = false; } ///////////////////////////////////////////////////////////////////// diff --git a/Prism/src/Prism/Scene/Scene.h b/Prism/src/Prism/Scene/Scene.h index 766ba5d..a8c56a6 100644 --- a/Prism/src/Prism/Scene/Scene.h +++ b/Prism/src/Prism/Scene/Scene.h @@ -169,7 +169,7 @@ namespace Prism Ref m_SkyboxTexture; Ref m_SkyboxMaterial; - float m_SkyboxLod = 1.0f; + float m_SkyboxLod = 0.0f; Ref m_CameraIcon; diff --git a/Prism/src/Prism/Scene/SceneSerializer.cpp b/Prism/src/Prism/Scene/SceneSerializer.cpp index 8357e00..733d3d1 100644 --- a/Prism/src/Prism/Scene/SceneSerializer.cpp +++ b/Prism/src/Prism/Scene/SceneSerializer.cpp @@ -13,142 +13,13 @@ #include "Prism/Physics/PhysicsLayer.h" #include "Prism/Physics/PhysicsWrappers.h" #include "Prism/Renderer/Meshfactory.h" -#include "../Asset/AssetsManager.h" +#include "Prism/Asset/AssetsManager.h" -namespace YAML -{ - - template<> - struct convert - { - static Node encode(const glm::vec2& rhs) - { - Node node; - node.push_back(rhs.x); - node.push_back(rhs.y); - return node; - } - - static bool decode(const Node& node, glm::vec2& rhs) - { - if (!node.IsSequence() || node.size() != 2) - return false; - - rhs.x = node[0].as(); - rhs.y = node[1].as(); - return true; - } - }; - - template<> - struct convert - { - static Node encode(const glm::vec3& rhs) - { - Node node; - node.push_back(rhs.x); - node.push_back(rhs.y); - node.push_back(rhs.z); - return node; - } - - static bool decode(const Node& node, glm::vec3& rhs) - { - if (!node.IsSequence() || node.size() != 3) - return false; - - rhs.x = node[0].as(); - rhs.y = node[1].as(); - rhs.z = node[2].as(); - return true; - } - }; - - template<> - struct convert - { - static Node encode(const glm::vec4& rhs) - { - Node node; - node.push_back(rhs.x); - node.push_back(rhs.y); - node.push_back(rhs.z); - node.push_back(rhs.w); - return node; - } - - static bool decode(const Node& node, glm::vec4& rhs) - { - if (!node.IsSequence() || node.size() != 4) - return false; - - rhs.x = node[0].as(); - rhs.y = node[1].as(); - rhs.z = node[2].as(); - rhs.w = node[3].as(); - return true; - } - }; - - template<> - struct convert - { - static Node encode(const glm::quat& rhs) - { - Node node; - node.push_back(rhs.w); - node.push_back(rhs.x); - node.push_back(rhs.y); - node.push_back(rhs.z); - return node; - } - - static bool decode(const Node& node, glm::quat& rhs) - { - if (!node.IsSequence() || node.size() != 4) - return false; - - rhs.w = node[0].as(); - rhs.x = node[1].as(); - rhs.y = node[2].as(); - rhs.z = node[3].as(); - return true; - } - }; -} +#include "Prism/Utilities/SerializeUtils.h" namespace Prism { - YAML::Emitter& operator<<(YAML::Emitter& out, const glm::vec2& v) - { - out << YAML::Flow; - out << YAML::BeginSeq << v.x << v.y << YAML::EndSeq; - return out; - } - - YAML::Emitter& operator<<(YAML::Emitter& out, const glm::vec3& v) - { - out << YAML::Flow; - out << YAML::BeginSeq << v.x << v.y << v.z << YAML::EndSeq; - return out; - } - - - YAML::Emitter& operator<<(YAML::Emitter& out, const glm::vec4& v) - { - out << YAML::Flow; - out << YAML::BeginSeq << v.x << v.y << v.z << v.w << YAML::EndSeq; - return out; - } - - YAML::Emitter& operator<<(YAML::Emitter& out, const glm::quat& v) - { - out << YAML::Flow; - out << YAML::BeginSeq << v.w << v.x << v.y << v.z << YAML::EndSeq; - return out; - } - SceneSerializer::SceneSerializer(const Ref& scene) : m_Scene(scene) { @@ -163,7 +34,7 @@ namespace Prism if (entity.HasComponent()) { - auto& relationshipComponent = entity.GetComponent(); + const auto& relationshipComponent = entity.GetComponent(); out << YAML::Key << "Parent" << YAML::Value << relationshipComponent.ParentHandle; out << YAML::Key << "Children"; @@ -258,11 +129,38 @@ namespace Prism out << YAML::Key << "MeshComponent"; out << YAML::BeginMap; // MeshComponent - const auto mesh = entity.GetComponent().Mesh; - if (mesh) + const auto& meshComponent = entity.GetComponent(); + if (meshComponent.Mesh) { + const auto& mesh = meshComponent.Mesh; out << YAML::Key << "AssetID" << YAML::Value << mesh->Handle; out << YAML::Key << "AssetPath" << YAML::Value << mesh->FilePath; + + if (!meshComponent.MaterialDescs.empty()) + { + + out << YAML::Key << "Materials"; + out << YAML::BeginMap; + for (auto i = 0; i < meshComponent.MaterialDescs.size(); ++i) + { + { + std::string slots = "Slot " + std::to_string(i); + out << YAML::Key << slots; + out << YAML::BeginMap; + if (meshComponent.MaterialDescs[i]) + { + out << YAML::Key << "AssetHandle" << YAML::Value << meshComponent.MaterialDescs[i]->Handle; + out << YAML::Key << "AssetPath" << YAML::Value << meshComponent.MaterialDescs[i]->FilePath; + }else + { + out << YAML::Key << "AssetHandle" << YAML::Value << 0; + out << YAML::Key << "AssetPath" << YAML::Value << ""; + } + out << YAML::EndMap; + } + } + out << YAML::EndMap; + } } else { @@ -602,7 +500,7 @@ namespace Prism out << YAML::Key << "MeshColliderComponent"; out << YAML::BeginMap; // MeshColliderComponent - auto meshColliderComponent = entity.GetComponent(); + const auto& meshColliderComponent = entity.GetComponent(); if (meshColliderComponent.OverrideMesh && meshColliderComponent.CollisionMesh) { out << YAML::Key << "AssetID" << YAML::Value << meshColliderComponent.CollisionMesh->Handle; @@ -883,7 +781,46 @@ namespace Prism if (AssetsManager::IsAssetHandleValid(assetID) && !deserializedEntity.HasComponent()) { - deserializedEntity.AddComponent(AssetsManager::GetAsset(assetID)); + auto& mc = deserializedEntity.AddComponent(AssetsManager::GetAsset(assetID)); + + if (meshComponent["Materials"]) + { + auto materialsNode = meshComponent["Materials"]; + // 遍历 "Slot X" 键 + for (auto it = materialsNode.begin(); it != materialsNode.end(); ++it) + { + std::string slotKey = it->first.as(); + if (slotKey.rfind("Slot ", 0) == 0) // 确保是 "Slot X" + { + int slotIndex = std::stoi(slotKey.substr(5)); + auto slotNode = it->second; + + // 获取材质资产的 Handle + UUID materialHandle = 0; + if (slotNode["AssetPath"]) + { + std::string matPath = slotNode["AssetPath"].as(); + if (!matPath.empty()) + materialHandle = AssetsManager::GetAssetHandleFromFilePath(matPath); + } + else if (slotNode["AssetHandle"]) + { + materialHandle = slotNode["AssetHandle"].as(); + } + + // 调整 MaterialDescs 大小(确保索引有效) + if (slotIndex >= mc.MaterialDescs.size()) + mc.MaterialDescs.resize(slotIndex + 1); + + // 加载材质资产并赋值 + if (materialHandle != 0 && AssetsManager::IsAssetHandleValid(materialHandle)) + mc.MaterialDescs[slotIndex] = AssetsManager::GetAsset(materialHandle); + else + mc.MaterialDescs[slotIndex] = nullptr; + } + } + mc.UpdateMaterials(-1, true); + } } } @@ -1099,18 +1036,18 @@ namespace Prism auto material = boxColliderComponent["Material"]; if (material && AssetsManager::IsAssetHandleValid(material.as())) { - component.Material = AssetsManager::GetAsset(material.as()); + component.Material = AssetsManager::GetAsset(material.as()); }else { const auto materialPath = boxColliderComponent["MaterialPath"].as(); if (const auto assetId = AssetsManager::GetAssetHandleFromFilePath(materialPath); assetId != 0) { - component.Material = AssetsManager::GetAsset(assetId); + component.Material = AssetsManager::GetAsset(assetId); } } - component.DebugMesh = MeshFactory::CreateBox(component.Size); + component.DebugMesh = MeshFactory::CreateBox(component.Size * 2.0f); } if (auto sphereColliderComponent = entity["SphereColliderComponent"]) @@ -1122,13 +1059,13 @@ namespace Prism auto material = sphereColliderComponent["Material"]; if (material && AssetsManager::IsAssetHandleValid(material.as())) { - component.Material = AssetsManager::GetAsset(material.as()); + component.Material = AssetsManager::GetAsset(material.as()); }else { const auto materialPath = sphereColliderComponent["MaterialPath"].as(); if (const auto assetId = AssetsManager::GetAssetHandleFromFilePath(materialPath); assetId != 0) { - component.Material = AssetsManager::GetAsset(assetId); + component.Material = AssetsManager::GetAsset(assetId); } } @@ -1146,13 +1083,13 @@ namespace Prism auto material = capsuleColliderComponent["Material"]; if (material && AssetsManager::IsAssetHandleValid(material.as())) { - component.Material = AssetsManager::GetAsset(material.as()); + component.Material = AssetsManager::GetAsset(material.as()); }else { const auto materialPath = capsuleColliderComponent["MaterialPath"].as(); if (const auto assetId = AssetsManager::GetAssetHandleFromFilePath(materialPath); assetId != 0) { - component.Material = AssetsManager::GetAsset(assetId); + component.Material = AssetsManager::GetAsset(assetId); } } @@ -1193,7 +1130,7 @@ namespace Prism auto material = meshColliderComponent["Material"]; if (material && AssetsManager::IsAssetHandleValid(material.as())) { - component.Material = AssetsManager::GetAsset(material.as()); + component.Material = AssetsManager::GetAsset(material.as()); if (component.IsConvex) PhysicsWrappers::CreateConvexMesh(component, deserializedEntity.Transform().Scale); @@ -1204,7 +1141,7 @@ namespace Prism const auto materialPath = meshColliderComponent["MaterialPath"].as(); if (const auto assetId = AssetsManager::GetAssetHandleFromFilePath(materialPath); assetId != 0) { - component.Material = AssetsManager::GetAsset(assetId); + component.Material = AssetsManager::GetAsset(assetId); if (component.IsConvex) PhysicsWrappers::CreateConvexMesh(component, deserializedEntity.Transform().Scale); @@ -1228,7 +1165,7 @@ namespace Prism if (physicsMaterialComponent) { //auto& component = deserializedEntity.AddComponent(); - Ref material = Ref::Create(); + Ref material = Ref::Create(); material->StaticFriction = physicsMaterialComponent["StaticFriction"].as(); material->DynamicFriction = physicsMaterialComponent["DynamicFriction"].as(); material->Bounciness = physicsMaterialComponent["Bounciness"].as(); diff --git a/Prism/src/Prism/Script/ScriptWrappers.cpp b/Prism/src/Prism/Script/ScriptWrappers.cpp index 0831387..fefd67c 100644 --- a/Prism/src/Prism/Script/ScriptWrappers.cpp +++ b/Prism/src/Prism/Script/ScriptWrappers.cpp @@ -37,14 +37,21 @@ namespace Prism { namespace Script { // Debug //////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////// + static LogCallback s_LogCallback = nullptr; + + void SetLogCallback(const LogCallback& callback) + { + s_LogCallback = callback; + } + void Prism_Log_Native(MonoString* message) { if (message) { - char* utf8 = mono_string_to_utf8(message); - if (utf8) + if (char* utf8 = mono_string_to_utf8(message)) { PM_CLIENT_INFO("[c#]: {}", utf8); + if (s_LogCallback) s_LogCallback(utf8); mono_free(utf8); } } @@ -404,7 +411,8 @@ namespace Prism { namespace Script { Entity entity = entityMap.at(entityID); - auto& transform = entity.GetComponent() = *inTransform; + auto& transform = entity.GetComponent(); + transform = *inTransform; transform.Rotation = glm::radians(transform.Rotation); } @@ -473,7 +481,13 @@ 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); - entity.GetComponent().Rotation = glm::radians(*inRotation); + auto& transformComponent = entity.GetComponent(); + transformComponent.Rotation = glm::radians(*inRotation); + + const auto rotationQuat = glm::quat(transformComponent.Rotation); + transformComponent.Up = glm::normalize(glm::rotate(rotationQuat, glm::vec3(0.0f, 1.0f, 0.0f))); + transformComponent.Right = glm::normalize(glm::rotate(rotationQuat, glm::vec3(1.0f, 0.0f, 0.0f))); + transformComponent.Forward = glm::normalize(glm::rotate(rotationQuat, glm::vec3(0.0f, 0.0f, -1.0f))); } void Prism_TransformComponent_GetScale(uint64_t entityID, glm::vec3* outScale) diff --git a/Prism/src/Prism/Script/ScriptWrappers.h b/Prism/src/Prism/Script/ScriptWrappers.h index d4b2183..deae5a5 100644 --- a/Prism/src/Prism/Script/ScriptWrappers.h +++ b/Prism/src/Prism/Script/ScriptWrappers.h @@ -14,7 +14,11 @@ extern "C" { typedef struct _MonoArray MonoArray; } -namespace Prism { namespace Script { +namespace Prism::Script +{ + + using LogCallback = std::function; + void SetLogCallback(const LogCallback& callback); /* struct ScriptTransform @@ -117,7 +121,7 @@ namespace Prism { namespace Script { void* Prism_MeshComponent_GetMesh(uint64_t entityID); void Prism_MeshComponent_SetMesh(uint64_t entityID, const Ref* inMesh); -} } +} #endif //SCRIPTWRAPPERS_H diff --git a/Prism/src/Prism/Utilities/FileSystem.h b/Prism/src/Prism/Utilities/FileSystem.h index 9aee3db..e767e31 100644 --- a/Prism/src/Prism/Utilities/FileSystem.h +++ b/Prism/src/Prism/Utilities/FileSystem.h @@ -38,6 +38,8 @@ namespace Prism static std::string OpenFileSelector(const std::string& filter = ""); static std::string SaveFileSelector(const std::string& filter = ""); + static void OpenInExplorer(const std::string& path); + static bool CreateFolder(const std::filesystem::path& filepath); static bool Exists(const std::string& filepath); static std::string Rename(const std::string& filepath, const std::string& newName); diff --git a/Prism/src/Prism/Utilities/SerializeUtils.h b/Prism/src/Prism/Utilities/SerializeUtils.h new file mode 100644 index 0000000..29dc716 --- /dev/null +++ b/Prism/src/Prism/Utilities/SerializeUtils.h @@ -0,0 +1,145 @@ +// +// Created by Atdunbg on 2026/3/25. +// + +#ifndef PRISM_SERIALIZEUTILS_H +#define PRISM_SERIALIZEUTILS_H + +#include +#include + +namespace YAML +{ + template<> + struct convert + { + static Node encode(const glm::vec2& rhs) + { + Node node; + node.push_back(rhs.x); + node.push_back(rhs.y); + return node; + } + + static bool decode(const Node& node, glm::vec2& rhs) + { + if (!node.IsSequence() || node.size() != 2) + return false; + + rhs.x = node[0].as(); + rhs.y = node[1].as(); + return true; + } + }; + + template<> + struct convert + { + static Node encode(const glm::vec3& rhs) + { + Node node; + node.push_back(rhs.x); + node.push_back(rhs.y); + node.push_back(rhs.z); + return node; + } + + static bool decode(const Node& node, glm::vec3& rhs) + { + if (!node.IsSequence() || node.size() != 3) + return false; + + rhs.x = node[0].as(); + rhs.y = node[1].as(); + rhs.z = node[2].as(); + return true; + } + }; + + template<> + struct convert + { + static Node encode(const glm::vec4& rhs) + { + Node node; + node.push_back(rhs.x); + node.push_back(rhs.y); + node.push_back(rhs.z); + node.push_back(rhs.w); + return node; + } + + static bool decode(const Node& node, glm::vec4& rhs) + { + if (!node.IsSequence() || node.size() != 4) + return false; + + rhs.x = node[0].as(); + rhs.y = node[1].as(); + rhs.z = node[2].as(); + rhs.w = node[3].as(); + return true; + } + }; + + template<> + struct convert + { + static Node encode(const glm::quat& rhs) + { + Node node; + node.push_back(rhs.w); + node.push_back(rhs.x); + node.push_back(rhs.y); + node.push_back(rhs.z); + return node; + } + + static bool decode(const Node& node, glm::quat& rhs) + { + if (!node.IsSequence() || node.size() != 4) + return false; + + rhs.w = node[0].as(); + rhs.x = node[1].as(); + rhs.y = node[2].as(); + rhs.z = node[3].as(); + return true; + } + }; +} + +namespace Prism +{ + inline YAML::Emitter& operator<<(YAML::Emitter& out, const glm::vec2& v) + { + out << YAML::Flow; + out << YAML::BeginSeq << v.x << v.y << YAML::EndSeq; + return out; + } + + inline YAML::Emitter& operator<<(YAML::Emitter& out, const glm::vec3& v) + { + out << YAML::Flow; + out << YAML::BeginSeq << v.x << v.y << v.z << YAML::EndSeq; + return out; + } + + + inline YAML::Emitter& operator<<(YAML::Emitter& out, const glm::vec4& v) + { + out << YAML::Flow; + out << YAML::BeginSeq << v.x << v.y << v.z << v.w << YAML::EndSeq; + return out; + } + + inline YAML::Emitter& operator<<(YAML::Emitter& out, const glm::quat& v) + { + out << YAML::Flow; + out << YAML::BeginSeq << v.w << v.x << v.y << v.z << YAML::EndSeq; + return out; + } +} + + +#endif //PRISM_SERIALIZEUTILS_H \ No newline at end of file diff --git a/Prism/src/Prism/Utilities/StringUtils.cpp b/Prism/src/Prism/Utilities/StringUtils.cpp index 1c0b8b1..0f54231 100644 --- a/Prism/src/Prism/Utilities/StringUtils.cpp +++ b/Prism/src/Prism/Utilities/StringUtils.cpp @@ -4,6 +4,8 @@ #include "StringUtils.h" +#include + namespace Prism::Utils { @@ -17,10 +19,16 @@ namespace Prism::Utils return ""; } + std::string ReplaceFilePathName(const std::string& filepath, const std::string& newName) + { + const std::string extension = GetExtension(filepath, true); + return std::filesystem::path(filepath).parent_path().string() + "/" + newName + extension; + } + std::string GetExtension(const std::string& filename, const bool includeDot) { if (const std::vector parts = SplitString(filename, '.'); parts.size() > 1) - return parts[ includeDot ? parts.size() - 1 : parts.size()]; + return (includeDot ? "." : "") + parts[parts.size() - 1]; return ""; } diff --git a/Prism/src/Prism/Utilities/StringUtils.h b/Prism/src/Prism/Utilities/StringUtils.h index b032193..51e920b 100644 --- a/Prism/src/Prism/Utilities/StringUtils.h +++ b/Prism/src/Prism/Utilities/StringUtils.h @@ -9,8 +9,10 @@ namespace Prism::Utils { + std::string ReplaceFilePathName(const std::string& filepath, const std::string& newName); + std::string GetFilename(const std::string& filepath); - std::string GetExtension(const std::string& filename, bool includeDot = true); + std::string GetExtension(const std::string& filename, bool includeDot = false); std::string RemoveExtension(const std::string& filename); std::string NormalizePath(std::string path); std::string StringToLower(const std::string& str); diff --git a/PrismRuntime/CMakeLists.txt b/PrismRuntime/CMakeLists.txt index 0933b45..edb7c9c 100644 --- a/PrismRuntime/CMakeLists.txt +++ b/PrismRuntime/CMakeLists.txt @@ -4,8 +4,8 @@ file(GLOB_RECURSE SRC_SOURCE ./PrismRuntime/**.cpp) add_executable(${PROJECT_NAME} WIN32 ${SRC_SOURCE}) target_compile_definitions(${PROJECT_NAME} PRIVATE PRISM_GUI) -target_link_libraries(${PROJECT_NAME} PRIVATE Prism-static) +target_link_libraries(${PROJECT_NAME} PRIVATE Prism-Runtime) add_executable(${PROJECT_NAME}-Console ${SRC_SOURCE}) -target_link_libraries(${PROJECT_NAME}-Console PRIVATE Prism-static) +target_link_libraries(${PROJECT_NAME}-Console PRIVATE Prism-Runtime) diff --git a/PrismRuntime/PrismRuntime/PrismRuntime.cpp b/PrismRuntime/PrismRuntime/PrismRuntime.cpp index a764645..bbd7998 100644 --- a/PrismRuntime/PrismRuntime/PrismRuntime.cpp +++ b/PrismRuntime/PrismRuntime/PrismRuntime.cpp @@ -4,6 +4,7 @@ #include "PrismRuntime.h" +#include "Prism/Core/Input.h" #include "Prism/Renderer/Renderer.h" #include "Prism/Renderer/SceneRenderer.h" #include "Prism/Scene/SceneSerializer.h" @@ -15,13 +16,31 @@ void PrismRuntime::OnAttach() AppInstance = &Prism::Application::Get(); - PM_CLIENT_INFO("Create Scene"); + sceneName.emplace_back("assets/scenes/FPS.scene"); + sceneName.emplace_back("assets/scenes/FPSdemo.scene"); + + LoadScene(sceneName[0]); +} + +void PrismRuntime::OnDetach() +{ + PM_CLIENT_INFO("Scene Shutdown"); + m_CurrentScene->OnShutdown(); +} + +void PrismRuntime::LoadScene(const std::string& scene) +{ + if (m_CurrentScene) + { + PM_CLIENT_INFO("Scene Shutdown"); + m_CurrentScene->OnShutdown(); + } + const Prism::Ref newScene = Prism::Ref::Create("runtime Scene", false, true); Prism::SceneSerializer serializer(newScene); - const char* scenePath = "assets/scenes/FPS.scene"; - PM_CLIENT_INFO("loading Scene: ", scenePath); - serializer.Deserialize(scenePath); + PM_CLIENT_INFO("loading Scene: ", scene); + serializer.Deserialize(scene); m_CurrentScene = newScene; @@ -32,16 +51,9 @@ void PrismRuntime::OnAttach() m_CurrentScene->SetViewportSize(windowSize); } - PM_CLIENT_INFO("Scene Start"); m_CurrentScene->OnRuntimeStart(); } -void PrismRuntime::OnDetach() -{ - PM_CLIENT_INFO("Scene Shutdown"); - m_CurrentScene->OnShutdown(); -} - void PrismRuntime::OnUpdate(const Prism::TimeStep deltaTime) { m_CurrentScene->OnUpdate(deltaTime); @@ -52,10 +64,25 @@ void PrismRuntime::OnUpdate(const Prism::TimeStep deltaTime) { m_CurrentScene->SetViewportSize(windowSize); } + + if (shouldChangeScene) + { + LoadScene(sceneName[nextScene]); + shouldChangeScene = false; + } } void PrismRuntime::OnEvent(Prism::Event& e) { + if (Prism::Input::IsKeyPressed(Prism::KeyCode::L) && nextScene == 0) + { + shouldChangeScene = true; + nextScene++; + } else if (Prism::Input::IsKeyPressed(Prism::KeyCode::K) && nextScene == 1) + { + shouldChangeScene = true; + nextScene--; + } } void PrismRuntime::OnImGuiRender() diff --git a/PrismRuntime/PrismRuntime/PrismRuntime.h b/PrismRuntime/PrismRuntime/PrismRuntime.h index 628e67d..9b5dad4 100644 --- a/PrismRuntime/PrismRuntime/PrismRuntime.h +++ b/PrismRuntime/PrismRuntime/PrismRuntime.h @@ -15,6 +15,8 @@ public: void OnAttach() override; void OnDetach() override; + void LoadScene(const std::string& scene); + void OnUpdate(Prism::TimeStep deltaTime) override; void OnEvent(Prism::Event& e) override; void OnImGuiRender() override; @@ -24,6 +26,12 @@ private: Prism::Ref m_CurrentScene; Prism::Application* AppInstance = nullptr; + + bool shouldChangeScene = false; + + // debug + std::vector sceneName; + int nextScene = 0; };