add simple runtime; fix the issue of crashing when creating file and folder; some tweaks

This commit is contained in:
2026-03-25 21:36:38 +08:00
parent f1de5df4de
commit ef4ea45edc
48 changed files with 996 additions and 362 deletions

View File

@ -23,4 +23,5 @@ endif ()
add_subdirectory(Prism) add_subdirectory(Prism)
add_subdirectory(Sandbox) add_subdirectory(Sandbox)
add_subdirectory(Editor) add_subdirectory(Editor)
add_subdirectory(PrismRuntime)

View File

@ -12,7 +12,7 @@ file(COPY ${IMGUI_INI} DESTINATION ${CMAKE_BINARY_DIR})
file(GLOB DOTNET_LIBRARY library) file(GLOB DOTNET_LIBRARY library)
file(COPY ${DOTNET_LIBRARY} DESTINATION ${CMAKE_BINARY_DIR}) file(COPY ${DOTNET_LIBRARY} DESTINATION ${CMAKE_BINARY_DIR})
file(GLOB_RECURSE SRC_SOURCE ./**.cpp) file(GLOB_RECURSE SRC_SOURCE ./Editor/**.cpp)
add_executable(${PROJECT_NAME} ${SRC_SOURCE}) add_executable(${PROJECT_NAME} ${SRC_SOURCE})

View File

@ -51,8 +51,11 @@ namespace Prism
NewScene(); NewScene();
m_CurrentScene = m_EditorScene; m_CurrentScene = m_EditorScene;
SceneRenderer::GetOptions().ShowGrid = true;
AssetEditorPanel::RegisterDefaultEditors(); AssetEditorPanel::RegisterDefaultEditors();
FileSystem::StartWatching(); FileSystem::StartWatching();
} }
void EditorLayer::OnDetach() void EditorLayer::OnDetach()
@ -105,7 +108,7 @@ namespace Prism
Renderer::BeginRenderPass(SceneRenderer::GetFinalRenderPass(), false); Renderer::BeginRenderPass(SceneRenderer::GetFinalRenderPass(), false);
const auto viewProj = m_EditorCamera.GetViewProjection(); const auto viewProj = m_EditorCamera.GetViewProjection();
Renderer2D::BeginScene(viewProj, false); Renderer2D::BeginScene(viewProj, false);
Renderer2D::DrawRotatedRect({ transform.Translation.x + collider.Offset.x, transform.Translation.y + collider.Offset.y }, {transform.Scale.x * collider.Size.x, transform.Scale.y * collider.Size.y}, transform.Rotation.z, { 0.0f, 0.0f, 1.0f, 1.0f }); Renderer2D::DrawRotatedRect({ transform.Translation.x + collider.Offset.x, transform.Translation.y + collider.Offset.y , transform.Translation.z}, {transform.Scale.x * collider.Size.x, transform.Scale.y * collider.Size.y}, transform.Rotation.z, { 0.0f, 0.0f, 1.0f, 1.0f });
Renderer2D::EndScene(); Renderer2D::EndScene();
Renderer::EndRenderPass(); Renderer::EndRenderPass();
} }
@ -117,7 +120,7 @@ namespace Prism
Renderer::BeginRenderPass(SceneRenderer::GetFinalRenderPass(), false); Renderer::BeginRenderPass(SceneRenderer::GetFinalRenderPass(), false);
const auto viewProj = m_EditorCamera.GetViewProjection(); const auto viewProj = m_EditorCamera.GetViewProjection();
Renderer2D::BeginScene(viewProj, false); Renderer2D::BeginScene(viewProj, false);
Renderer2D::DrawCircle({ transform.Translation.x + collider.Offset.x, transform.Translation.y + collider.Offset.y}, collider.Radius, { 0.0f, 1.0f, 1.0f, 1.0f }); Renderer2D::DrawCircle({ transform.Translation.x + collider.Offset.x, transform.Translation.y + collider.Offset.y, transform.Translation.z}, collider.Radius, { 0.0f, 1.0f, 1.0f, 1.0f });
Renderer2D::EndScene(); Renderer2D::EndScene();
Renderer::EndRenderPass(); Renderer::EndRenderPass();
} }
@ -237,7 +240,7 @@ namespace Prism
{ {
// temp // temp
if (ImGui::MenuItem("Reload C# Assembly")) if (ImGui::MenuItem("Reload C# Assembly"))
ScriptEngine::ReloadAssembly("assets/scripts/ExampleApp.dll"); ScriptEngine::ReloadAssembly("assets/scripts/Assembly-Script.dll");
ImGui::MenuItem("Reload assembly on play", nullptr, &m_ReloadScriptOnPlay); ImGui::MenuItem("Reload assembly on play", nullptr, &m_ReloadScriptOnPlay);
ImGui::EndMenu(); ImGui::EndMenu();
@ -1054,17 +1057,6 @@ namespace Prism
}); });
if (!m_SelectionContext.empty()) if (!m_SelectionContext.empty())
{ {
if (auto alreadySelectedEntity = m_SceneHierarchyPanel->GetSelected();
m_SelectionContext.size() != 1 && alreadySelectedEntity)
{
const auto alreadySelectedEntityID = alreadySelectedEntity.GetUUID();
for (const auto& selectedEntity : m_SelectionContext)
{
if (alreadySelectedEntityID == selectedEntity.Entity.GetUUID()) continue;
return false;
}
}
OnSelected(m_SelectionContext[0]); OnSelected(m_SelectionContext[0]);
} }
} }

View File

@ -0,0 +1,336 @@
Scene: Scene Name
Environment:
AssetHandle: 5211537204242875091
Entities:
- Entity: 8293051279669100759
Parent: 0
Children:
[]
TagComponent:
Tag: Cube
TransformComponent:
Position: [1.736814, 1.4724115, -4.2181306]
Rotation: [0, 0, 0]
Scale: [1, 1, 1]
MeshComponent:
AssetID: 18328012085543462741
AssetPath: assets/meshes/Default/Cube.fbx
RigidBodyComponent:
BodyType: 1
Mass: 1
LinearDrag: 0
AngularDrag: 0.05
DisableGravity: false
IsKinematic: false
Layer: 0
Constraints:
LockPositionX: false
LockPositionY: false
LockPositionZ: false
LockRotationX: false
LockRotationY: false
LockRotationZ: false
BoxColliderComponent:
Offset: [0, 0, 0]
Size: [2, 2, 2]
IsTrigger: false
Material: 0
MaterialPath: ""
- Entity: 5834225236589765516
Parent: 0
Children:
[]
TagComponent:
Tag: Cube
TransformComponent:
Position: [-2.6417403, 1.4724115, -7.9285727]
Rotation: [0.52199936, 0, 0]
Scale: [1, 1.0000001, 1.0000001]
MeshComponent:
AssetID: 18328012085543462741
AssetPath: assets/meshes/Default/Cube.fbx
RigidBodyComponent:
BodyType: 1
Mass: 1
LinearDrag: 0
AngularDrag: 0.05
DisableGravity: false
IsKinematic: false
Layer: 0
Constraints:
LockPositionX: false
LockPositionY: false
LockPositionZ: false
LockRotationX: false
LockRotationY: false
LockRotationZ: false
BoxColliderComponent:
Offset: [0, 0, 0]
Size: [2, 2, 2]
IsTrigger: false
Material: 0
MaterialPath: ""
- Entity: 8234256119181302872
Parent: 0
Children:
[]
TagComponent:
Tag: Cube
TransformComponent:
Position: [1.736814, 1.4724115, -7.9285727]
Rotation: [0, 0, 0]
Scale: [1, 1, 1]
MeshComponent:
AssetID: 18328012085543462741
AssetPath: assets/meshes/Default/Cube.fbx
RigidBodyComponent:
BodyType: 1
Mass: 1
LinearDrag: 0
AngularDrag: 0.05
DisableGravity: false
IsKinematic: false
Layer: 0
Constraints:
LockPositionX: false
LockPositionY: false
LockPositionZ: false
LockRotationX: false
LockRotationY: false
LockRotationZ: false
BoxColliderComponent:
Offset: [0, 0, 0]
Size: [2, 2, 2]
IsTrigger: false
Material: 0
MaterialPath: ""
- Entity: 12935252585493481950
Parent: 0
Children:
[]
TagComponent:
Tag: Cube
TransformComponent:
Position: [-1.5106764, 6.237644, -4.2181306]
Rotation: [0, 0, 0]
Scale: [1, 1, 1]
MeshComponent:
AssetID: 18328012085543462741
AssetPath: assets/meshes/Default/Cube.fbx
RigidBodyComponent:
BodyType: 1
Mass: 1
LinearDrag: 0
AngularDrag: 0.05
DisableGravity: false
IsKinematic: false
Layer: 0
Constraints:
LockPositionX: false
LockPositionY: false
LockPositionZ: false
LockRotationX: false
LockRotationY: false
LockRotationZ: false
BoxColliderComponent:
Offset: [0, 0, 0]
Size: [2, 2, 2]
IsTrigger: false
Material: 0
MaterialPath: ""
- Entity: 3328246672296261054
Parent: 0
Children:
[]
TagComponent:
Tag: Cube
TransformComponent:
Position: [1.736814, 1.4724115, -0.88378817]
Rotation: [0, 0, 0]
Scale: [1, 1, 1]
MeshComponent:
AssetID: 18328012085543462741
AssetPath: assets/meshes/Default/Cube.fbx
RigidBodyComponent:
BodyType: 1
Mass: 1
LinearDrag: 0
AngularDrag: 0.05
DisableGravity: false
IsKinematic: false
Layer: 0
Constraints:
LockPositionX: false
LockPositionY: false
LockPositionZ: false
LockRotationX: false
LockRotationY: false
LockRotationZ: false
BoxColliderComponent:
Offset: [0, 0, 0]
Size: [2, 2, 2]
IsTrigger: false
Material: 0
MaterialPath: ""
- Entity: 4208267561919679628
Parent: 0
Children:
[]
TagComponent:
Tag: Cube
TransformComponent:
Position: [-2.6417403, 1.4724115, -4.8956265]
Rotation: [-0.4034239, 0, 0]
Scale: [1, 0.99999994, 0.99999994]
MeshComponent:
AssetID: 18328012085543462741
AssetPath: assets/meshes/Default/Cube.fbx
RigidBodyComponent:
BodyType: 1
Mass: 1
LinearDrag: 0
AngularDrag: 0.05
DisableGravity: true
IsKinematic: false
Layer: 0
Constraints:
LockPositionX: false
LockPositionY: false
LockPositionZ: false
LockRotationX: false
LockRotationY: false
LockRotationZ: false
BoxColliderComponent:
Offset: [0, 0, 0]
Size: [2, 2, 2]
IsTrigger: false
Material: 0
MaterialPath: ""
- Entity: 8114736924719261351
Parent: 0
Children:
[]
TagComponent:
Tag: Camera
TransformComponent:
Position: [0, 0.8097433, 4.573171]
Rotation: [0, 0, 0]
Scale: [1, 1, 1]
CameraComponent:
Camera:
ProjectionType: 0
PerspectiveFOV: 45
PerspectiveNear: 0.01
PerspectiveFar: 10000
OrthographicSize: 10
OrthographicNear: -1
OrthographicFar: 1
Primary: true
- Entity: 9267298328378270409
Parent: 0
Children:
[]
TagComponent:
Tag: Player
TransformComponent:
Position: [0, 0.70693016, 0]
Rotation: [0, 0, 0]
Scale: [1, 1, 1]
ScriptComponent:
ModuleName: FPSExample.FPSPlayer
StoredFields:
- Name: WalkingSpeed
Type: 1
Data: 2
- Name: RunSpeed
Type: 1
Data: 5
- Name: JumpForce
Type: 1
Data: 1
- Name: MouseSensitivity
Type: 1
Data: 10
- Name: CameraForwardOffset
Type: 1
Data: -2
- Name: CameraYOffset
Type: 1
Data: 2
MeshComponent:
AssetID: 3043502408333723884
AssetPath: assets/meshes/Default/Capsule.fbx
RigidBodyComponent:
BodyType: 1
Mass: 1
LinearDrag: 0
AngularDrag: 0.05
DisableGravity: false
IsKinematic: false
Layer: 0
Constraints:
LockPositionX: false
LockPositionY: false
LockPositionZ: false
LockRotationX: true
LockRotationY: false
LockRotationZ: true
MeshColliderComponent:
IsConvex: true
IsTrigger: false
OverrideMesh: false
Material: 0
MaterialPath: ""
- Entity: 10732070446010033158
Parent: 0
Children:
[]
TagComponent:
Tag: Cube
TransformComponent:
Position: [0, -2.6466873, 0]
Rotation: [0, 0, 0]
Scale: [100, 1, 100]
MeshComponent:
AssetID: 18328012085543462741
AssetPath: assets/meshes/Default/Cube.fbx
RigidBodyComponent:
BodyType: 0
Mass: 1
LinearDrag: 0
AngularDrag: 0.05
DisableGravity: false
IsKinematic: false
Layer: 0
Constraints:
LockPositionX: false
LockPositionY: false
LockPositionZ: false
LockRotationX: false
LockRotationY: false
LockRotationZ: false
BoxColliderComponent:
Offset: [0, 0, 0]
Size: [2, 2, 2]
IsTrigger: false
Material: 0
MaterialPath: ""
- Entity: 5099152432245948441
Parent: 0
Children:
[]
TagComponent:
Tag: venice_dawn_1_4k
TransformComponent:
Position: [0, 0, 0]
Rotation: [0, 0, 0]
Scale: [1, 1, 1]
SkyLightComponent:
EnvironmentMap: 5211537204242875091
EnvironmentAssetPath: assets/env/venice_dawn_1_4k.hdr
Intensity: 1
Angle: 0
DynamicSky: false
TurbidityAzimuthInclination: [2, 0, 0]
PhysicsLayers:
[]

View File

@ -1,11 +1,50 @@
Scene: Scene Name Scene: Scene Name
Environment: Environment:
AssetHandle: 10549690553241162923 AssetHandle: 6095149963749185931
Light:
Direction: [-0.314, -0.941, -0.209]
Radiance: [0, 0, 0]
Multiplier: 1
Entities: Entities:
- Entity: 6421668200759325475
Parent: 0
Children:
[]
TagComponent:
Tag: M1911Materials
TransformComponent:
Position: [0, 3.159583, 0]
Rotation: [0, 0, 0]
Scale: [1, 1, 1]
MeshComponent:
AssetID: 7219694555758922702
AssetPath: assets/models/m1911/M1911Materials.fbx
- Entity: 16992665426857995732
Parent: 0
Children:
[]
TagComponent:
Tag: Cube
TransformComponent:
Position: [0, 0, 0]
Rotation: [0, 0, 0]
Scale: [50, 1, 50]
MeshComponent:
AssetID: 18328012085543462741
AssetPath: assets/meshes/Default/Cube.fbx
- Entity: 18182275256052989728
Parent: 0
Children:
[]
TagComponent:
Tag: Sky Light
TransformComponent:
Position: [0, 0, 0]
Rotation: [0, 0, 0]
Scale: [1, 1, 1]
SkyLightComponent:
EnvironmentMap: 6095149963749185931
EnvironmentAssetPath: ""
Intensity: 1
Angle: 0
DynamicSky: true
TurbidityAzimuthInclination: [2, 0.15, 0.71]
- Entity: 17803125207910630398 - Entity: 17803125207910630398
Parent: 0 Parent: 0
Children: Children:
@ -20,30 +59,6 @@ Entities:
Radiance: [1, 1, 1] Radiance: [1, 1, 1]
CastShadows: true CastShadows: true
SoftShadows: true SoftShadows: true
LightSize: 0.5 LightSize: 0.9
- Entity: 4315886439647742331
Parent: 0
Children:
[]
TagComponent:
Tag: Cube
TransformComponent:
Position: [0, 2.048974, 0]
Rotation: [0, 0, 0]
Scale: [1, 1, 1]
MeshComponent:
AssetID: 3580169978473467053
- Entity: 16992665426857995732
Parent: 0
Children:
[]
TagComponent:
Tag: Cube
TransformComponent:
Position: [0, 0, 0]
Rotation: [0, 0, 0]
Scale: [50, 1, 50]
MeshComponent:
AssetID: 3580169978473467053
PhysicsLayers: PhysicsLayers:
[] []

View File

@ -1,12 +1,21 @@
Scene: Scene Name Scene: Scene Name
Environment: Environment:
AssetHandle: 17073147362577408906 AssetHandle: 5211537204242875091
Light:
Direction: [-0.314, -0.941, -0.209]
Radiance: [0, 0, 0]
Multiplier: 1
Entities: Entities:
- Entity: 3696833073589069488 - Entity: 15706224176559717512
Parent: 0
Children:
[]
TagComponent:
Tag: Cube
TransformComponent:
Position: [0, 0, 0]
Rotation: [0, 0, 0]
Scale: [1, 1, 1]
MeshComponent:
AssetID: 18328012085543462741
AssetPath: assets/meshes/Default/Cube.fbx
- Entity: 8041206185299282567
Parent: 0 Parent: 0
Children: Children:
[] []
@ -17,8 +26,11 @@ Entities:
Rotation: [0, 0, 0] Rotation: [0, 0, 0]
Scale: [1, 1, 1] Scale: [1, 1, 1]
SkyLightComponent: SkyLightComponent:
EnvironmentMap: 17073147362577408906 EnvironmentMap: 5211537204242875091
EnvironmentAssetPath: assets/env/venice_dawn_1_4k.hdr
Intensity: 1 Intensity: 1
Angle: 0 Angle: 0
DynamicSky: false
TurbidityAzimuthInclination: [2, 0, 0]
PhysicsLayers: PhysicsLayers:
[] []

View File

@ -4,6 +4,7 @@
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,3 +1,4 @@
using System.Runtime.InteropServices;
using Prism; using Prism;
namespace FPSExample namespace FPSExample
@ -46,6 +47,9 @@ namespace FPSExample
m_LastMousePosition = Input.GetMousePosition(); m_LastMousePosition = Input.GetMousePosition();
Input.SetCursorMode(Input.CursorMode.Locked); Input.SetCursorMode(Input.CursorMode.Locked);
int size = Marshal.SizeOf<Transform>();
Console.WriteLine($"C# size of Transform: {size}");
} }
void OnUpdate(float ts) void OnUpdate(float ts)

View File

@ -5,6 +5,7 @@
<RootNamespace>Prism_ScriptCore</RootNamespace> <RootNamespace>Prism_ScriptCore</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -0,0 +1,15 @@
using System.Runtime.CompilerServices;
namespace Prism
{
public class Debug
{
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void Log_Native(string message);
public static void Log(string message)
{
Log_Native(message);
}
}
}

View File

@ -9,8 +9,8 @@ namespace Prism
public Vec3 Rotation; public Vec3 Rotation;
public Vec3 Scale; public Vec3 Scale;
public Vec3 Up { get; } public Vec3 Up;
public Vec3 Right { get; } public Vec3 Right;
public Vec3 Forward { get; } public Vec3 Forward;
} }
} }

View File

@ -132,25 +132,6 @@ namespace Prism
return assetHandle != 0 && s_LoadedAssets.find(assetHandle) != s_LoadedAssets.end(); return assetHandle != 0 && s_LoadedAssets.find(assetHandle) != s_LoadedAssets.end();
} }
void AssetsManager::Rename(Ref<Asset>& asset, const std::string& newName)
{
const std::string newFilePath = FileSystem::Rename(asset->FilePath, newName);
const std::string oldFilePath = asset->FilePath;
asset->FilePath = newFilePath;
asset->FileName = newName;
if (FileSystem::Exists(oldFilePath + ".meta"))
{
std::string metaFileName = oldFilePath;
if (!asset->Extension.empty())
metaFileName += "." + asset->Extension;
FileSystem::PrismDeleteFile(oldFilePath + ".meta");
AssetSerializer::CreateMetaFile(asset);
}
}
template <typename T> template <typename T>
Ref<T> AssetsManager::GetAsset(AssetHandle assetHandle, bool loadData) Ref<T> AssetsManager::GetAsset(AssetHandle assetHandle, bool loadData)
{ {
@ -383,41 +364,29 @@ namespace Prism
break; break;
case FileSystemAction::Rename: case FileSystemAction::Rename:
{ {
Ref<Asset> asset; Ref<Asset> asset = nullptr;
for (auto it = s_LoadedAssets.begin(); it != s_LoadedAssets.end(); it++)
{ {
if (it->second->FileName == e.OldName) const std::string oldMetaPath = std::filesystem::path(e.FilePath).parent_path().string() + "/" + e.OldName;
for (auto& [handle, existingAsset] : s_LoadedAssets)
{ {
asset = it->second; if (existingAsset->FilePath == oldMetaPath)
{
asset = existingAsset;
break;
}
} }
} }
if (asset) if (asset)
{ {
if (asset->Type != AssetTypes::GetAssetTypeFromExtension(Utils::GetExtension(e.FilePath))) std::string oldMetaPath = asset->FilePath + ".meta";
{
RemoveAsset(asset->Handle);
FileSystem::PrismDeleteFile(asset->FilePath + ".meta");
asset = ImportAsset(e.FilePath, parentHandle);
}else
{
std::string oldMetaPath = asset->FilePath + ".meta";
std::string newMetaPath = e.FilePath + ".meta";
std::error_code ec; FileSystem::Rename(oldMetaPath, e.NewName);
std::filesystem::rename(oldMetaPath, newMetaPath, ec);
if (ec)
{
PM_CORE_ERROR("Failed to rename meta file: {}", ec.message());
}
asset->FilePath = e.FilePath;
asset->FileName = e.NewName;
}
}
asset->FilePath = e.FilePath;
asset->FileName = e.NewName;
asset->Extension = Utils::GetExtension(e.FilePath);
}
} }
break; break;
case FileSystemAction::Delete: case FileSystemAction::Delete:

View File

@ -45,7 +45,6 @@ namespace Prism
static AssetHandle GetAssetHandleFromFilePath(const std::string& filepath); static AssetHandle GetAssetHandleFromFilePath(const std::string& filepath);
static bool IsAssetHandleValid(const AssetHandle& assetHandle); static bool IsAssetHandleValid(const AssetHandle& assetHandle);
static void Rename(Ref<Asset>& asset, const std::string& newName);
static Ref<PhysicsMaterial> CreateAssetPhysicsMaterial(const std::string& filename, AssetType type, const AssetHandle& directoryHandle, float v1, float v2, float v3); static Ref<PhysicsMaterial> CreateAssetPhysicsMaterial(const std::string& filename, AssetType type, const AssetHandle& directoryHandle, float v1, float v2, float v3);

View File

@ -36,7 +36,6 @@ namespace Prism
m_Window = std::unique_ptr<Window>(Window::Create(WindowProps{props.Name, props.Width, props.Height})); m_Window = std::unique_ptr<Window>(Window::Create(WindowProps{props.Name, props.Width, props.Height}));
m_Window->SetEventCallback(BIND_EVENT_FN(OnEvent)); m_Window->SetEventCallback(BIND_EVENT_FN(OnEvent));
m_Window->SetVSync(true); m_Window->SetVSync(true);
m_Window->Maximize();
m_ImGuiLayer = new ImGuiLayer("ImGui Layer"); m_ImGuiLayer = new ImGuiLayer("ImGui Layer");
PushOverlay(m_ImGuiLayer); PushOverlay(m_ImGuiLayer);
@ -107,6 +106,7 @@ namespace Prism
for (Layer* layer : m_LayerStack) for (Layer* layer : m_LayerStack)
layer->OnImGuiRender(); layer->OnImGuiRender();
/*
ImGui::Begin("Renderer"); ImGui::Begin("Renderer");
const auto& caps = RendererAPI::GetCapabilities(); const auto& caps = RendererAPI::GetCapabilities();
ImGui::Text("Vendor: %s", caps.Vendor.c_str()); ImGui::Text("Vendor: %s", caps.Vendor.c_str());
@ -114,6 +114,7 @@ namespace Prism
ImGui::Text("Version: %s", caps.Version.c_str()); ImGui::Text("Version: %s", caps.Version.c_str());
ImGui::Text("Frame Time: %.2fms\n", m_TimeStep.GetMilliseconds()); ImGui::Text("Frame Time: %.2fms\n", m_TimeStep.GetMilliseconds());
ImGui::End(); ImGui::End();
*/
m_ImGuiLayer->End(); m_ImGuiLayer->End();
} }

View File

@ -12,7 +12,19 @@
extern Prism::Application* Prism::CreateApplication(CommandArgs args); extern Prism::Application* Prism::CreateApplication(CommandArgs args);
#ifdef PRISM_GUI
#ifdef _WIN32
#include <windows.h>
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 //TODO: this will use other method to impl
std::cout << std::filesystem::current_path() << std::endl; std::cout << std::filesystem::current_path() << std::endl;
@ -33,6 +45,7 @@ int main(int argc, char** argv)
Prism::ShutdownCore(); Prism::ShutdownCore();
#endif #endif
return 0;
} }
#endif //ENTRYPOINT_H #endif //ENTRYPOINT_H

View File

@ -45,6 +45,49 @@ namespace Prism {
EVENT_CLASS_CATEGORY(EventCategoryApplication) EVENT_CLASS_CATEGORY(EventCategoryApplication)
}; };
class PRISM_API WindowFocusEvent : public Event
{
public:
WindowFocusEvent() = default;
EVENT_CLASS_TYPE(WindowFocus)
EVENT_CLASS_CATEGORY(EventCategoryApplication)
};
class PRISM_API WindowLostFocusEvent : public Event
{
public:
WindowLostFocusEvent() = default;
EVENT_CLASS_TYPE(WindowLostFocus)
EVENT_CLASS_CATEGORY(EventCategoryApplication)
};
class PRISM_API WindowMovedEvent : public Event
{
public:
WindowMovedEvent(const int32_t x, const int32_t y)
: m_X(x), m_Y(y)
{
}
inline int32_t GetX() const { return m_X; }
inline int32_t GetY() const { return m_Y; }
std::string ToString() const override
{
std::stringstream ss;
ss << "WindowMovedEvent: " << m_X << ", " << m_Y;
return ss.str();
}
EVENT_CLASS_TYPE(WindowMoved)
EVENT_CLASS_CATEGORY(EventCategoryApplication)
private:
int32_t m_X, m_Y;
};
class PRISM_API AppTickEvent : public Event class PRISM_API AppTickEvent : public Event
{ {
public: public:

View File

@ -24,7 +24,6 @@ namespace Prism
static std::shared_ptr<spdlog::logger> s_CoreLogger; static std::shared_ptr<spdlog::logger> s_CoreLogger;
static std::shared_ptr<spdlog::logger> s_ClientLogger; static std::shared_ptr<spdlog::logger> s_ClientLogger;
}; };
}
#ifdef _DEBUG #ifdef _DEBUG
#define PM_CORE_TRACE(...) SPDLOG_LOGGER_TRACE(::Prism::Log::GetCoreLogger(), __VA_ARGS__) #define PM_CORE_TRACE(...) SPDLOG_LOGGER_TRACE(::Prism::Log::GetCoreLogger(), __VA_ARGS__)
@ -41,6 +40,8 @@ namespace Prism
#define PM_CORE_ERROR(...) ::Prism::Log::GetCoreLogger()->error(__VA_ARGS__) #define PM_CORE_ERROR(...) ::Prism::Log::GetCoreLogger()->error(__VA_ARGS__)
#define PM_CORE_FATAL(...) ::Prism::Log::GetCoreLogger()->critical(__VA_ARGS__) #define PM_CORE_FATAL(...) ::Prism::Log::GetCoreLogger()->critical(__VA_ARGS__)
#endif #endif
}
#define PM_CLIENT_TRACE(...) ::Prism::Log::GetClientLogger()->trace(__VA_ARGS__) #define PM_CLIENT_TRACE(...) ::Prism::Log::GetClientLogger()->trace(__VA_ARGS__)

View File

@ -21,7 +21,7 @@ namespace Prism
operator float() { return m_Time; } operator float() { return m_Time; }
private: private:
float m_Time; float m_Time = 0.0f;
}; };
} }

View File

@ -10,6 +10,7 @@
#include "Ref.h" #include "Ref.h"
#include "Events/Event.h" #include "Events/Event.h"
#include "Prism/Core/Core.h" #include "Prism/Core/Core.h"
#include <glm/glm.hpp>
namespace Prism namespace Prism
@ -39,8 +40,8 @@ namespace Prism
virtual void SetEventCallback(const EventCallbackFn& callback) = 0; virtual void SetEventCallback(const EventCallbackFn& callback) = 0;
virtual uint32_t GetWidth() const = 0; virtual uint32_t GetWidth() const = 0;
virtual uint32_t GetHeight() const = 0; virtual uint32_t GetHeight() const = 0;
virtual std::pair<uint32_t, uint32_t> GetSize() const = 0; virtual glm::ivec2 GetSize() const = 0;
virtual std::pair<float, float> GetWindowPos() const = 0; virtual glm::vec2 GetWindowPos() const = 0;
virtual void SetVSync(bool enable) = 0; virtual void SetVSync(bool enable) = 0;
virtual bool const IsVSync() const = 0; virtual bool const IsVSync() const = 0;

View File

@ -11,6 +11,7 @@
#include "Prism/Core/Application.h" #include "Prism/Core/Application.h"
#include "Prism/Core/Input.h" #include "Prism/Core/Input.h"
#include "Prism/Core/Log.h" #include "Prism/Core/Log.h"
#include "Prism/Utilities/StringUtils.h"
namespace Prism namespace Prism
{ {
@ -101,16 +102,20 @@ namespace Prism
if (ImGui::MenuItem("Folder")) if (ImGui::MenuItem("Folder"))
{ {
PM_CORE_INFO("Creating Folder..."); PM_CORE_INFO("Creating Folder...");
const bool created = FileSystem::CreateFolder(m_CurrentDirectory->FilePath + "/New Folder"); const std::string filePath = m_CurrentDirectory->FilePath + "/new folder";
if (created) FileSystem::CreateFolder(filePath);
UpdateCurrentDirectory(m_CurrentDirHandle);
// const auto& createdDirectory = AssetsManager::CreateDirectory(filePath, m_CurrentDirHandle);
/*
if (createdDirectory)
{ {
UpdateCurrentDirectory(m_CurrentDirHandle); UpdateCurrentDirectory(m_CurrentDirHandle);
const auto& createdDirectory = AssetsManager::GetAsset<Directory>(AssetsManager::GetAssetHandleFromFilePath(m_CurrentDirectory->FilePath + "/New Folder"));
m_SelectedAssets.Select(createdDirectory->Handle); m_SelectedAssets.Select(createdDirectory->Handle);
memset(m_InputBuffer, 0, MAX_INPUT_BUFFER_LENGTH); memset(m_InputBuffer, 0, MAX_INPUT_BUFFER_LENGTH);
memcpy(m_InputBuffer, createdDirectory->FileName.c_str(), createdDirectory->FileName.size()); memcpy(m_InputBuffer, createdDirectory->FileName.c_str(), createdDirectory->FileName.size());
m_RenamingSelected = true; m_RenamingSelected = true;
} }
*/
} }
if (ImGui::MenuItem("Scene")) if (ImGui::MenuItem("Scene"))
@ -523,7 +528,8 @@ namespace Prism
if (ImGui::InputText("##rename_dummy", m_InputBuffer, MAX_INPUT_BUFFER_LENGTH, ImGuiInputTextFlags_EnterReturnsTrue)) if (ImGui::InputText("##rename_dummy", m_InputBuffer, MAX_INPUT_BUFFER_LENGTH, ImGuiInputTextFlags_EnterReturnsTrue))
{ {
PM_CORE_INFO("Renaming to {0}", m_InputBuffer); PM_CORE_INFO("Renaming to {0}", m_InputBuffer);
AssetsManager::Rename(asset, m_InputBuffer); const std::string filename = m_InputBuffer + Utils::GetExtension(asset->FilePath);
FileSystem::Rename(asset->FilePath, filename);
m_RenamingSelected = false; m_RenamingSelected = false;
m_SelectedAssets.Clear(); m_SelectedAssets.Clear();
m_UpdateDirectoryNextFrame = true; m_UpdateDirectoryNextFrame = true;

View File

@ -1090,18 +1090,33 @@ namespace Prism
}); });
DrawComponent<ScriptComponent>("Script", entity, [=](ScriptComponent& scriptComponent) mutable { DrawComponent<ScriptComponent>("Script", entity, [=](ScriptComponent& scriptComponent) mutable {
UI::BeginPropertyGrid();
const std::string oldName = scriptComponent.ModuleName;
if (UI::Property("Module Name", scriptComponent.ModuleName, !ScriptEngine::ModuleExists(scriptComponent.ModuleName))) // TODO: no live edit
{
// Shutdown old script
if (ScriptEngine::ModuleExists(oldName))
ScriptEngine::ShutdownScriptEntity(entity, oldName);
if (ScriptEngine::ModuleExists(scriptComponent.ModuleName)) const std::string oldName = scriptComponent.ModuleName;
ScriptEngine::InitScriptEntity(entity);
if (ImGui::BeginCombo("Module Name", scriptComponent.ModuleName.c_str()))
{
const auto& availableScripts = ScriptEngine::GetAvailableScripts();
for (const auto& script : availableScripts)
{
const bool isSelected = (scriptComponent.ModuleName == script);
if (ImGui::Selectable(script.c_str(), isSelected))
{
// 切换逻辑
if (ScriptEngine::ModuleExists(oldName))
ScriptEngine::ShutdownScriptEntity(entity, oldName);
scriptComponent.ModuleName = script;
if (ScriptEngine::ModuleExists(scriptComponent.ModuleName))
ScriptEngine::InitScriptEntity(entity);
}
if (isSelected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
} }
UI::BeginPropertyGrid();
// Public Fields // Public Fields
if (ScriptEngine::ModuleExists(scriptComponent.ModuleName)) if (ScriptEngine::ModuleExists(scriptComponent.ModuleName))
{ {

View File

@ -85,7 +85,8 @@ namespace Prism
void Physics3D::Simulate(const TimeStep ts) void Physics3D::Simulate(const TimeStep ts)
{ {
auto& time = s_SimulationTime;
auto& sett = s_Settings;
// TODO: Allow projects to control the fixed step amount // TODO: Allow projects to control the fixed step amount
s_SimulationTime += ts.GetMilliseconds(); s_SimulationTime += ts.GetMilliseconds();
@ -106,7 +107,7 @@ namespace Prism
void Physics3D::DestroyScene() void Physics3D::DestroyScene()
{ {
PM_CORE_ASSERT(s_Scene); if (!s_Scene) return;
s_Actors.clear(); s_Actors.clear();
s_Scene->release(); s_Scene->release();

View File

@ -230,4 +230,12 @@ namespace Prism
glBindTextureUnit(slot, instance->m_ColorAttachments[attachmentIndex]); glBindTextureUnit(slot, instance->m_ColorAttachments[attachmentIndex]);
}); });
} }
void OpenGLFrameBuffer::BindDepthTexture(uint32_t slot) const
{
Ref<const OpenGLFrameBuffer> instance = this;
Renderer::Submit([instance, slot]() {
glBindTextureUnit(slot, instance->m_DepthAttachment);
});
}
} }

View File

@ -21,6 +21,7 @@ namespace Prism
void Resize(uint32_t width, uint32_t height, bool forceReCreate) override; void Resize(uint32_t width, uint32_t height, bool forceReCreate) override;
void BindTexture(uint32_t attachmentIndex, uint32_t slot) const override; void BindTexture(uint32_t attachmentIndex, uint32_t slot) const override;
void BindDepthTexture(uint32_t slot = 0) const override;
uint32_t GetWidth() const override { return m_Specification.Width; } uint32_t GetWidth() const override { return m_Specification.Width; }
uint32_t GetHeight() const override { return m_Specification.Height; } uint32_t GetHeight() const override { return m_Specification.Height; }

View File

@ -186,7 +186,7 @@ namespace Prism
}); });
} }
void OpenGLTexture2D::SetData(const void* data, int count) void OpenGLTexture2D::SetData(const void* data, uint32_t count)
{ {
Lock(); Lock();

View File

@ -30,7 +30,7 @@ namespace Prism
virtual void Lock() override; virtual void Lock() override;
virtual void Unlock() override; virtual void Unlock() override;
virtual void SetData(const void* data, int count) override; virtual void SetData(const void* data, uint32_t count) override;
virtual void Resize(uint32_t width, uint32_t height) override; virtual void Resize(uint32_t width, uint32_t height) override;
virtual Buffer GetWriteableBuffer() override; virtual Buffer GetWriteableBuffer() override;

View File

@ -38,10 +38,12 @@ namespace Prism
if (FileSystem::s_IgnoreNextChange.load()) if (FileSystem::s_IgnoreNextChange.load())
return; return;
std::filesystem::path fullPath = std::filesystem::path(dir) / filename; std::string fullPath = (std::filesystem::path(dir) / filename).string();
std::replace(fullPath.begin(), fullPath.end(), '\\', '/');
FileSystemChangedEvent e; FileSystemChangedEvent e;
e.FilePath = fullPath.string(); e.FilePath = fullPath;
e.NewName = filename; e.NewName = filename;
e.OldName = oldFilename; // efsw 在重命名时会提供旧文件名 e.OldName = oldFilename; // efsw 在重命名时会提供旧文件名
e.IsDirectory = false; // 稍后根据实际情况判断 e.IsDirectory = false; // 稍后根据实际情况判断

View File

@ -62,7 +62,7 @@ namespace Prism
m_Data.VSync = enable; m_Data.VSync = enable;
} }
std::pair<float, float> WindowsWindow::GetWindowPos() const glm::vec2 WindowsWindow::GetWindowPos() const
{ {
int x, y; int x, y;
glfwGetWindowPos(m_Window, &x, &y); glfwGetWindowPos(m_Window, &x, &y);
@ -91,6 +91,8 @@ namespace Prism
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_DEPTH_BITS, 24);
s_GLFWInitialized = true; s_GLFWInitialized = true;
} }
@ -119,16 +121,37 @@ namespace Prism
glfwSetWindowCloseCallback(m_Window, [](GLFWwindow* window) glfwSetWindowCloseCallback(m_Window, [](GLFWwindow* window)
{ {
auto& data = *((WindowData*)glfwGetWindowUserPointer(window)); const auto& data = *((WindowData*)glfwGetWindowUserPointer(window));
WindowCloseEvent event; WindowCloseEvent event;
data.EventCallback(event); data.EventCallback(event);
}); });
glfwSetWindowFocusCallback(m_Window, [](GLFWwindow* window, const int focused) {
const auto& data = *((WindowData*)glfwGetWindowUserPointer(window));
if (focused)
{
WindowFocusEvent event;
data.EventCallback(event);
}
else
{
WindowLostFocusEvent event;
data.EventCallback(event);
}
});
glfwSetWindowPosCallback(m_Window, [](GLFWwindow* window, int xpos, int ypos) {
const auto& data = *((WindowData*)glfwGetWindowUserPointer(window));
WindowMovedEvent event(xpos, ypos);
data.EventCallback(event);
});
glfwSetKeyCallback(m_Window, [](GLFWwindow* window, int key, int scancode, int action, int mods) glfwSetKeyCallback(m_Window, [](GLFWwindow* window, int key, int scancode, int action, int mods)
{ {
auto& data = *((WindowData*)glfwGetWindowUserPointer(window)); const auto& data = *((WindowData*)glfwGetWindowUserPointer(window));
switch (action) switch (action)
{ {

View File

@ -27,8 +27,8 @@ namespace Prism
bool const IsVSync() const override { return m_Data.VSync; } bool const IsVSync() const override { return m_Data.VSync; }
void SetVSync(bool enable) override; void SetVSync(bool enable) override;
virtual std::pair<uint32_t, uint32_t> GetSize() const override { return { m_Data.Width, m_Data.Height }; } virtual glm::ivec2 GetSize() const override { return { m_Data.Width, m_Data.Height }; }
virtual std::pair<float, float> GetWindowPos() const override; virtual glm::vec2 GetWindowPos() const override;
virtual const std::string& GetTitle() const override { return m_Data.Title; } virtual const std::string& GetTitle() const override { return m_Data.Title; }
virtual void SetTitle(const std::string& title) override; virtual void SetTitle(const std::string& title) override;

View File

@ -78,6 +78,7 @@ namespace Prism
virtual void Resize(uint32_t width, uint32_t height, bool forceReCreate = false) = 0; virtual void Resize(uint32_t width, uint32_t height, bool forceReCreate = false) = 0;
virtual void BindTexture(uint32_t attachmentIndex = 0, uint32_t slot = 0) const = 0; virtual void BindTexture(uint32_t attachmentIndex = 0, uint32_t slot = 0) const = 0;
virtual void BindDepthTexture(uint32_t slot = 0) const = 0;
virtual uint32_t GetWidth() const = 0; virtual uint32_t GetWidth() const = 0;
virtual uint32_t GetHeight() const = 0; virtual uint32_t GetHeight() const = 0;

View File

@ -203,7 +203,10 @@ namespace Prism
Renderer::Submit([submesh, material]() { Renderer::Submit([submesh, material]() {
if (material->GetFlag(MaterialFlag::DepthTest)) if (material->GetFlag(MaterialFlag::DepthTest))
{
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
}
else else
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);

View File

@ -49,7 +49,7 @@ namespace Prism
bool EnableAutoExposure = true; bool EnableAutoExposure = true;
float Key = 0.3f; float Key = 0.3f;
Timer ExposureTimer; Timer ExposureTimer;
float MaxExposure = 5.0f; float MaxExposure = 1.5f;
float MinExposure = 0.01f; float MinExposure = 0.01f;
// 直方图模式参数 // 直方图模式参数
@ -153,7 +153,7 @@ namespace Prism
//////////////// GeoPass //////////////// //////////////// GeoPass ////////////////
{ {
FramebufferSpecification geoFramebufferSpec; FramebufferSpecification geoFramebufferSpec;
geoFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA16F, FramebufferTextureFormat::DEPTH24STENCIL8 }; geoFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA32F, FramebufferTextureFormat::DEPTH24STENCIL8 };
geoFramebufferSpec.Samples = 8; geoFramebufferSpec.Samples = 8;
geoFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f }; geoFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f };
@ -943,18 +943,17 @@ namespace Prism
return; return;
} }
uint32_t srcTex = s_Data.ResolvedHDRTexture->GetRendererID();
const int iterations = 5; // 模糊迭代次数,可调 const int iterations = 5; // 模糊迭代次数,可调
// 第一次:提取高光 + 水平模糊 // 第一次:提取高光 + 水平模糊
{ {
Renderer::BeginRenderPass(s_Data.BloomBlurPass[0]); Renderer::BeginRenderPass(s_Data.BloomBlurPass[0]);
s_Data.BloomBlurShader->Bind(); s_Data.BloomBlurShader->Bind();
s_Data.BloomBlurShader->SetInt("u_Texture", 0); s_Data.BloomBlurShader->SetInt("u_Texture", 0);
// s_Data.BloomBlurShader->SetBool("u_Horizontal", true);
s_Data.BloomBlurShader->SetBool("u_FirstPass", true); s_Data.BloomBlurShader->SetBool("u_FirstPass", true);
s_Data.BloomBlurShader->SetFloat("u_Threshold", s_Data.BloomThreshold); s_Data.BloomBlurShader->SetFloat("u_Threshold", s_Data.BloomThreshold);
Renderer::Submit([srcTex]() { glBindTextureUnit(0, srcTex); }); s_Data.ResolvedHDRTexture->Bind();
Renderer::SubmitFullscreenQuad(nullptr); Renderer::SubmitFullscreenQuad(nullptr);
Renderer::EndRenderPass(); Renderer::EndRenderPass();
} }
@ -962,18 +961,17 @@ namespace Prism
// 后续迭代 // 后续迭代
for (int i = 1; i < iterations; ++i) for (int i = 1; i < iterations; ++i)
{ {
bool horizontal = (i % 2 == 1); // 第二次垂直,第三次水平...
uint32_t inputTex = (i % 2 == 1) ?
s_Data.BloomBlurPass[0]->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID() :
s_Data.BloomBlurPass[1]->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID();
auto outputPass = (i % 2 == 1) ? s_Data.BloomBlurPass[1] : s_Data.BloomBlurPass[0]; auto outputPass = (i % 2 == 1) ? s_Data.BloomBlurPass[1] : s_Data.BloomBlurPass[0];
Renderer::BeginRenderPass(outputPass); Renderer::BeginRenderPass(outputPass);
s_Data.BloomBlurShader->Bind(); s_Data.BloomBlurShader->Bind();
s_Data.BloomBlurShader->SetInt("u_Texture", 0); s_Data.BloomBlurShader->SetInt("u_Texture", 0);
// s_Data.BloomBlurShader->SetBool("u_Horizontal", horizontal);
s_Data.BloomBlurShader->SetBool("u_FirstPass", false); s_Data.BloomBlurShader->SetBool("u_FirstPass", false);
Renderer::Submit([inputTex]() { glBindTextureUnit(0, inputTex); }); if (i%2 == 1)
s_Data.BloomBlurPass[0]->GetSpecification().TargetFramebuffer->BindTexture();
else
s_Data.BloomBlurPass[1]->GetSpecification().TargetFramebuffer->BindTexture();
Renderer::SubmitFullscreenQuad(nullptr); Renderer::SubmitFullscreenQuad(nullptr);
Renderer::EndRenderPass(); Renderer::EndRenderPass();
} }
@ -986,9 +984,12 @@ namespace Prism
Renderer::BeginRenderPass(s_Data.BloomBlendPass); Renderer::BeginRenderPass(s_Data.BloomBlendPass);
s_Data.BloomBlurShader->Bind(); s_Data.BloomBlurShader->Bind();
s_Data.BloomBlurShader->SetInt("u_Texture", 0); s_Data.BloomBlurShader->SetInt("u_Texture", 0);
// s_Data.BloomBlurShader->SetBool("u_Horizontal", false); if (iterations % 2 == 0)
s_Data.BloomBlurPass[1]->GetSpecification().TargetFramebuffer->BindTexture();
else
s_Data.BloomBlurPass[0]->GetSpecification().TargetFramebuffer->BindTexture();
s_Data.BloomBlurShader->SetBool("u_FirstPass", false); s_Data.BloomBlurShader->SetBool("u_FirstPass", false);
Renderer::Submit([finalBlurTex]() { glBindTextureUnit(0, finalBlurTex); });
Renderer::SubmitFullscreenQuad(nullptr); Renderer::SubmitFullscreenQuad(nullptr);
Renderer::EndRenderPass(); Renderer::EndRenderPass();
} }
@ -1023,6 +1024,23 @@ namespace Prism
Renderer::EndRenderPass(); Renderer::EndRenderPass();
} }
void CopyDepthBuffer(Ref<FrameBuffer> src, Ref<FrameBuffer> dst)
{
uint32_t srcID = src->GetRendererID(); // 假设 FrameBuffer 有此方法
uint32_t dstID = dst->GetRendererID();
int srcWidth = src->GetWidth();
int srcHeight = src->GetHeight();
int dstWidth = dst->GetWidth();
int dstHeight = dst->GetHeight();
glBindFramebuffer(GL_READ_FRAMEBUFFER, srcID);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstID);
glBlitFramebuffer(0, 0, srcWidth, srcHeight, 0, 0, dstWidth, dstHeight,
GL_DEPTH_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_FRAMEBUFFER, 0); // 可选恢复
}
void Renderer3D::CompositePass(const Ref<RenderPass>& outRenderPass) void Renderer3D::CompositePass(const Ref<RenderPass>& outRenderPass)
{ {
Renderer::BeginRenderPass(outRenderPass); Renderer::BeginRenderPass(outRenderPass);
@ -1041,13 +1059,9 @@ namespace Prism
glBindTextureUnit(1, s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID()); glBindTextureUnit(1, s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID());
}); });
// 新增:绑定 Bloom 纹理(如果启用)
if (s_Data.EnableBloom) if (s_Data.EnableBloom)
{ {
uint32_t bloomTex = s_Data.BloomBlendPass->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID(); s_Data.BloomBlendPass->GetSpecification().TargetFramebuffer->BindTexture(0, 2);
Renderer::Submit([bloomTex]() {
glBindTextureUnit(2, bloomTex); // 绑定到单元2
});
s_Data.CompositeShader->SetInt("u_BloomTexture", 2); // 告诉着色器使用单元2 s_Data.CompositeShader->SetInt("u_BloomTexture", 2); // 告诉着色器使用单元2
} }
@ -1057,182 +1071,6 @@ namespace Prism
} }
/*
void Renderer3D::CompositePass(const Ref<RenderPass>& outRenderPass)
{
Renderer::BeginRenderPass(outRenderPass);
s_Data.CompositeShader->Bind();
s_Data.BloomBlendShader->Bind();
s_Data.BloomBlendShader->SetBool("u_EnableBloom", s_Data.EnableBloom);
s_Data.AutoExposureData.ExposureSSBO->BindBase(2);
Renderer::Submit([]() {
glBindTextureUnit(0, s_Data.ResolvedHDRTexture->GetRendererID());
});
s_Data.BloomBlendShader->SetInt("u_SceneTexture", 0);
s_Data.CompositeShader->SetBool("u_EnableAutoExposure",s_Data.AutoExposureData.EnableAutoExposure);
s_Data.CompositeShader->SetFloat("u_ManualExposure", s_Data.SceneData.SceneCamera.Camera.GetExposure());
s_Data.CompositeShader->SetInt("u_TextureSamples", s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetSpecification().Samples);
s_Data.CompositeShader->SetFloat("u_EnableBloom", s_Data.EnableBloom);
if (s_Data.EnableBloom)
{
uint32_t bloomTex = s_Data.BloomBlendPass->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID();
Renderer::Submit([bloomTex]() {
glBindTextureUnit(1, bloomTex);
});
s_Data.BloomBlendShader->SetInt("u_BloomTexture", 1);
}
s_Data.GeoPass->GetSpecification().TargetFramebuffer->BindTexture();
Renderer::Submit([]()
{
glBindTextureUnit(1, s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID());
});
Renderer::SubmitFullscreenQuad(nullptr);
Renderer::EndRenderPass();
}
*/
/*
struct FrustumBounds
{
float r, l, b, t, f, n;
};
struct CascadeData
{
glm::mat4 ViewProj;
glm::mat4 View;
float SplitDepth;
};
static void CalculateCascades(CascadeData* cascades, const glm::vec3& lightDirection)
{
// FrustumBounds frustumBounds[3];
auto& sceneCamera = s_Data.SceneData.SceneCamera;
auto viewProjection = sceneCamera.Camera.GetProjectionMatrix() * sceneCamera.ViewMatrix;
constexpr int SHADOW_MAP_CASCADE_COUNT = 4;
float cascadeSplits[SHADOW_MAP_CASCADE_COUNT];
// TODO: less hard-coding!
float nearClip = 0.1f;
float farClip = 1000.0f;
float clipRange = farClip - nearClip;
float minZ = nearClip;
float maxZ = nearClip + clipRange;
float range = maxZ - minZ;
float ratio = maxZ / minZ;
// Calculate split depths based on view camera frustum
// Based on method presented in https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch10.html
for (uint32_t i = 0; i < SHADOW_MAP_CASCADE_COUNT; i++)
{
float p = (i + 1) / static_cast<float>(SHADOW_MAP_CASCADE_COUNT);
float log = minZ * std::pow(ratio, p);
float uniform = minZ + range * p;
float d = s_Data.CascadeSplitLambda * (log - uniform) + uniform;
cascadeSplits[i] = (d - nearClip) / clipRange;
}
// cascadeSplits[3] = 0.3f;
// Manually set cascades here
// cascadeSplits[0] = 0.05f;
// cascadeSplits[1] = 0.15f;
// cascadeSplits[2] = 0.3f;
// cascadeSplits[3] = 1.0f;
// Calculate orthographic projection matrix for each cascade
float lastSplitDist = 1.0;
for (uint32_t i = 0; i < SHADOW_MAP_CASCADE_COUNT; i++)
{
float splitDist = cascadeSplits[i];
glm::vec3 frustumCorners[8] =
{
glm::vec3(-1.0f, 1.0f, -1.0f),
glm::vec3( 1.0f, 1.0f, -1.0f),
glm::vec3( 1.0f, -1.0f, -1.0f),
glm::vec3(-1.0f, -1.0f, -1.0f),
glm::vec3(-1.0f, 1.0f, 1.0f),
glm::vec3( 1.0f, 1.0f, 1.0f),
glm::vec3( 1.0f, -1.0f, 1.0f),
glm::vec3(-1.0f, -1.0f, 1.0f),
};
// Project frustum corners into world space
glm::mat4 invCam = glm::inverse(viewProjection);
for (uint32_t i = 0; i < 8; i++)
{
glm::vec4 invCorner = invCam * glm::vec4(frustumCorners[i], 1.0f);
frustumCorners[i] = invCorner / invCorner.w;
}
for (uint32_t i = 0; i < 4; i++)
{
glm::vec3 dist = frustumCorners[i + 4] - frustumCorners[i];
frustumCorners[i + 4] = frustumCorners[i] + (dist * splitDist);
frustumCorners[i] = frustumCorners[i] + (dist * lastSplitDist);
}
// Get frustum center
glm::vec3 frustumCenter = glm::vec3(0.0f);
for (uint32_t i = 0; i < 8; i++)
frustumCenter += frustumCorners[i];
frustumCenter /= 8.0f;
//frustumCenter *= 0.01f;
float radius = 0.0f;
for (uint32_t i = 0; i < 8; i++)
{
float distance = glm::length(frustumCorners[i] - frustumCenter);
radius = glm::max(radius, distance);
}
radius = std::ceil(radius * 16.0f) / 16.0f;
glm::vec3 maxExtents = glm::vec3(radius);
glm::vec3 minExtents = -maxExtents;
glm::vec3 lightDir = -lightDirection;
glm::mat4 lightViewMatrix = glm::lookAt(frustumCenter - lightDir * -minExtents.z, frustumCenter, glm::vec3(0.0f, 0.0f, 1.0f));
glm::mat4 lightOrthoMatrix = glm::ortho(minExtents.x, maxExtents.x, minExtents.y, maxExtents.y, 0.0f + s_Data.CascadeNearPlaneOffset, maxExtents.z - minExtents.z + s_Data.CascadeFarPlaneOffset);
// Offset to texel space to avoid shimmering (from https://stackoverflow.com/questions/33499053/cascaded-shadow-map-shimmering)
glm::mat4 shadowMatrix = lightOrthoMatrix * lightViewMatrix;
constexpr float ShadowMapResolution = 4096.0f;
glm::vec4 shadowOrigin = (shadowMatrix * glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)) * ShadowMapResolution / 2.0f;
glm::vec4 roundedOrigin = glm::round(shadowOrigin);
glm::vec4 roundOffset = roundedOrigin - shadowOrigin;
roundOffset = roundOffset * 2.0f / ShadowMapResolution;
roundOffset.z = 0.0f;
roundOffset.w = 0.0f;
lightOrthoMatrix[3] += roundOffset;
// Store split distance and matrix in cascade
cascades[i].SplitDepth = (nearClip + splitDist * clipRange) * -1.0f;
cascades[i].ViewProj = lightOrthoMatrix * lightViewMatrix;
cascades[i].View = lightViewMatrix;
lastSplitDist = cascadeSplits[i];
}
}
*/
std::vector<glm::vec3> GetFrustumCornersWorldSpace(const SceneRendererCamera& sceneCamera) std::vector<glm::vec3> GetFrustumCornersWorldSpace(const SceneRendererCamera& sceneCamera)
{ {
std::vector<glm::vec3> corners(8); std::vector<glm::vec3> corners(8);
@ -1424,4 +1262,5 @@ namespace Prism
ImGui::End(); ImGui::End();
} }
} }

View File

@ -12,6 +12,7 @@
#include "Renderer3D.h" #include "Renderer3D.h"
#include "RenderPass.h" #include "RenderPass.h"
#include "glad/glad.h"
namespace Prism namespace Prism
@ -26,7 +27,7 @@ namespace Prism
void SceneRenderer::Init() void SceneRenderer::Init()
{ {
FramebufferSpecification finalFramebufferSpec; FramebufferSpecification finalFramebufferSpec;
finalFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA16F, FramebufferTextureFormat::Depth}; finalFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA32F, FramebufferTextureFormat::DEPTH24STENCIL8};
finalFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f }; finalFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f };
RenderPassSpecification finalRenderPassSpec; RenderPassSpecification finalRenderPassSpec;
@ -207,4 +208,24 @@ namespace Prism
{ {
return Renderer3D::GetOptions(); return Renderer3D::GetOptions();
} }
void SceneRenderer::FlushToScreen()
{
const auto fb = s_Data.FinalPass->GetSpecification().TargetFramebuffer;
const auto fbWidth = fb->GetWidth();
const auto fbHeight = fb->GetHeight();
Renderer::Submit([fb, fbWidth, fbHeight]()
{
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); // 过滤器
});
}
} }

View File

@ -15,7 +15,7 @@ namespace Prism
{ {
struct SceneRendererOptions struct SceneRendererOptions
{ {
bool ShowGrid = true; bool ShowGrid = false;
bool ShowBoundingBoxes = false; bool ShowBoundingBoxes = false;
}; };
@ -90,7 +90,9 @@ namespace Prism
static uint32_t GetFinalColorBufferRendererID(); static uint32_t GetFinalColorBufferRendererID();
static SceneRendererOptions& GetOptions(); static SceneRendererOptions& GetOptions();
static void OnImGuiRender(); static void OnImGuiRender();
private:
static void FlushToScreen();
}; };
} }

View File

@ -62,7 +62,7 @@ namespace Prism
virtual void Lock() = 0; virtual void Lock() = 0;
virtual void Unlock() = 0; virtual void Unlock() = 0;
virtual void SetData(const void* data, int count) = 0; virtual void SetData(const void* data, uint32_t count) = 0;
virtual void Resize(uint32_t width, uint32_t height) = 0; virtual void Resize(uint32_t width, uint32_t height) = 0;
virtual Buffer GetWriteableBuffer() = 0; virtual Buffer GetWriteableBuffer() = 0;

View File

@ -431,7 +431,7 @@ namespace Prism
bool ShowIcon = false; bool ShowIcon = false;
bool DynamicSky = false; bool DynamicSky = false;
glm::vec3 TurbidityAzimuthInclination = { 2.0, 0.0, 0.0 }; glm::vec3 TurbidityAzimuthInclination = { 2.0, 0.0, 1.0 };
SkyLightComponent(const Ref<Environment>& environment) SkyLightComponent(const Ref<Environment>& environment)
: SceneEnvironment(environment) : SceneEnvironment(environment)

View File

@ -32,12 +32,7 @@ namespace Prism
static uint32_t s_SceneIDCounter = 0; static uint32_t s_SceneIDCounter = 0;
Scene::Scene(const std::string& debugName, const bool isEditorScene, const bool runtime)
Scene::Scene(const std::string& debugName, const bool isEditorScene)
: m_SceneID(++s_SceneIDCounter), m_DebugName(debugName) : m_SceneID(++s_SceneIDCounter), m_DebugName(debugName)
{ {
m_Registry.on_construct<TransformComponent>().connect<&Physics2D::OnTransformConstruct>(); m_Registry.on_construct<TransformComponent>().connect<&Physics2D::OnTransformConstruct>();
@ -56,10 +51,11 @@ namespace Prism
Physics3D::CreateScene(); Physics3D::CreateScene();
} }
Init(); Init(runtime);
} }
Scene::~Scene() Scene::~Scene()
{ {
m_Registry.on_destroy<ScriptComponent>().disconnect(); m_Registry.on_destroy<ScriptComponent>().disconnect();
@ -68,20 +64,23 @@ namespace Prism
s_ActiveScenes.erase(m_SceneID); s_ActiveScenes.erase(m_SceneID);
} }
void Scene::Init() void Scene::Init(const bool runtime)
{ {
const auto skyboxShader = Shader::Create("assets/shaders/Skybox.glsl"); const auto skyboxShader = Shader::Create("assets/shaders/Skybox.glsl");
m_SkyboxMaterial = MaterialInstance::Create(Material::Create(skyboxShader)); m_SkyboxMaterial = MaterialInstance::Create(Material::Create(skyboxShader));
m_SkyboxMaterial->SetFlag(MaterialFlag::DepthTest, false); m_SkyboxMaterial->SetFlag(MaterialFlag::DepthTest, false);
m_CameraIcon = AssetsManager::GetAsset<Texture2D>("assets/editor/Camera.png"); if (!runtime)
m_LightIcon = AssetsManager::GetAsset<Texture2D>("assets/editor/light.png"); {
m_CameraIcon = AssetsManager::GetAsset<Texture2D>("assets/editor/Camera.png");
m_LightIcon = AssetsManager::GetAsset<Texture2D>("assets/editor/light.png");
}
} }
void Scene::OnShutdown() void Scene::OnShutdown()
{ {
b2DestroyWorld(m_Registry.get<Box2DWorldComponent>(m_SceneEntity).World); b2DestroyWorld(m_Registry.get<Box2DWorldComponent>(m_SceneEntity).World);
Physics3D::DestroyScene();
} }
void Scene::OnUpdate(TimeStep ts) void Scene::OnUpdate(TimeStep ts)
@ -224,7 +223,9 @@ namespace Prism
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
} }
SceneRenderer::FlushToScreen();
SceneRenderer::EndScene(); SceneRenderer::EndScene();
} }
void Scene::OnRenderEditor(const TimeStep ts, const EditorCamera& editorCamera) void Scene::OnRenderEditor(const TimeStep ts, const EditorCamera& editorCamera)
@ -431,6 +432,12 @@ namespace Prism
m_IsPlaying = false; m_IsPlaying = false;
} }
void Scene::SetViewportSize(const glm::ivec2& viewportSize)
{
m_ViewportWidth = viewportSize.x;
m_ViewportHeight = viewportSize.y;
}
void Scene::SetViewportSize(const uint32_t width, const uint32_t height) void Scene::SetViewportSize(const uint32_t width, const uint32_t height)
{ {
m_ViewportWidth = width; m_ViewportWidth = width;

View File

@ -74,10 +74,10 @@ namespace Prism
class PRISM_API Scene : public RefCounted class PRISM_API Scene : public RefCounted
{ {
public: public:
Scene(const std::string& debugName = "Scene", bool isEditorScene = false); Scene(const std::string& debugName = "Scene", bool isEditorScene = false, bool runtime = false);
~Scene(); ~Scene();
void Init(); void Init(bool runtime);
void OnShutdown(); void OnShutdown();
void OnUpdate(TimeStep ts); void OnUpdate(TimeStep ts);
@ -88,6 +88,7 @@ namespace Prism
void OnRuntimeStart(); void OnRuntimeStart();
void OnRuntimeStop(); void OnRuntimeStop();
void SetViewportSize(const glm::ivec2& viewportSize);
void SetViewportSize(uint32_t width, uint32_t height); void SetViewportSize(uint32_t width, uint32_t height);
const Ref<Environment>& GetEnvironment() const { return m_Environment; } const Ref<Environment>& GetEnvironment() const { return m_Environment; }

View File

@ -260,9 +260,15 @@ namespace Prism
const auto mesh = entity.GetComponent<MeshComponent>().Mesh; const auto mesh = entity.GetComponent<MeshComponent>().Mesh;
if (mesh) if (mesh)
{
out << YAML::Key << "AssetID" << YAML::Value << mesh->Handle; out << YAML::Key << "AssetID" << YAML::Value << mesh->Handle;
out << YAML::Key << "AssetPath" << YAML::Value << mesh->FilePath;
}
else else
{
out << YAML::Key << "AssetID" << YAML::Value << 0; out << YAML::Key << "AssetID" << YAML::Value << 0;
out << YAML::Key << "AssetPath" << YAML::Value << "";
}
out << YAML::EndMap; // MeshComponent out << YAML::EndMap; // MeshComponent
} }
@ -287,7 +293,16 @@ namespace Prism
out << YAML::BeginMap; // SkyLightComponent out << YAML::BeginMap; // SkyLightComponent
const auto& skyLightComponent = entity.GetComponent<SkyLightComponent>(); const auto& skyLightComponent = entity.GetComponent<SkyLightComponent>();
out << YAML::Key << "EnvironmentMap" << YAML::Value << skyLightComponent.SceneEnvironment->Handle; if (skyLightComponent.SceneEnvironment)
{
out << YAML::Key << "EnvironmentMap" << YAML::Value << skyLightComponent.SceneEnvironment->Handle;
out << YAML::Key << "EnvironmentAssetPath" << YAML::Value << skyLightComponent.SceneEnvironment->FilePath;
}
else
{
out << YAML::Key << "EnvironmentMap" << YAML::Value << 0;
out << YAML::Key << "EnvironmentAssetPath" << YAML::Value << "";
}
out << YAML::Key << "Intensity" << YAML::Value << skyLightComponent.Intensity; out << YAML::Key << "Intensity" << YAML::Value << skyLightComponent.Intensity;
out << YAML::Key << "Angle" << YAML::Value << skyLightComponent.Angle; out << YAML::Key << "Angle" << YAML::Value << skyLightComponent.Angle;
@ -518,9 +533,16 @@ namespace Prism
out << YAML::Key << "IsTrigger" << YAML::Value << boxColliderComponent.IsTrigger; out << YAML::Key << "IsTrigger" << YAML::Value << boxColliderComponent.IsTrigger;
if (boxColliderComponent.Material) if (boxColliderComponent.Material)
{
out << YAML::Key << "Material" << YAML::Value << boxColliderComponent.Material->Handle; out << YAML::Key << "Material" << YAML::Value << boxColliderComponent.Material->Handle;
out << YAML::Key << "MaterialPath" << YAML::Value << boxColliderComponent.Material->FilePath;
}
else else
{
out << YAML::Key << "Material" << YAML::Value << 0; out << YAML::Key << "Material" << YAML::Value << 0;
out << YAML::Key << "MaterialPath" << YAML::Value << "";
}
out << YAML::EndMap; // BoxColliderComponent out << YAML::EndMap; // BoxColliderComponent
} }
@ -535,9 +557,16 @@ namespace Prism
out << YAML::Key << "IsTrigger" << YAML::Value << sphereColliderComponent.IsTrigger; out << YAML::Key << "IsTrigger" << YAML::Value << sphereColliderComponent.IsTrigger;
if (sphereColliderComponent.Material) if (sphereColliderComponent.Material)
{
out << YAML::Key << "Material" << YAML::Value << sphereColliderComponent.Material->Handle; out << YAML::Key << "Material" << YAML::Value << sphereColliderComponent.Material->Handle;
out << YAML::Key << "MaterialPath" << YAML::Value << sphereColliderComponent.Material->FilePath;
}
else else
{
out << YAML::Key << "Material" << YAML::Value << 0; out << YAML::Key << "Material" << YAML::Value << 0;
out << YAML::Key << "MaterialPath" << YAML::Value << "";
}
out << YAML::EndMap; // SphereColliderComponent out << YAML::EndMap; // SphereColliderComponent
} }
@ -552,10 +581,18 @@ namespace Prism
out << YAML::Key << "Height" << YAML::Value << capsuleColliderComponent.Height; out << YAML::Key << "Height" << YAML::Value << capsuleColliderComponent.Height;
out << YAML::Key << "IsTrigger" << YAML::Value << capsuleColliderComponent.IsTrigger; out << YAML::Key << "IsTrigger" << YAML::Value << capsuleColliderComponent.IsTrigger;
if (capsuleColliderComponent.Material) if (capsuleColliderComponent.Material)
{
out << YAML::Key << "Material" << YAML::Value << capsuleColliderComponent.Material->Handle; out << YAML::Key << "Material" << YAML::Value << capsuleColliderComponent.Material->Handle;
out << YAML::Key << "MaterialPath" << YAML::Value << capsuleColliderComponent.Material->FilePath;
}
else else
{
out << YAML::Key << "Material" << YAML::Value << 0; out << YAML::Key << "Material" << YAML::Value << 0;
out << YAML::Key << "MaterialPath" << YAML::Value << "";
}
out << YAML::EndMap; // CapsuleColliderComponent out << YAML::EndMap; // CapsuleColliderComponent
} }
@ -566,18 +603,26 @@ namespace Prism
out << YAML::BeginMap; // MeshColliderComponent out << YAML::BeginMap; // MeshColliderComponent
auto meshColliderComponent = entity.GetComponent<MeshColliderComponent>(); auto meshColliderComponent = entity.GetComponent<MeshColliderComponent>();
if (meshColliderComponent.OverrideMesh && meshColliderComponent.CollisionMesh)
if (meshColliderComponent.OverrideMesh) {
out << YAML::Key << "AssetID" << YAML::Value << meshColliderComponent.CollisionMesh->Handle; out << YAML::Key << "AssetID" << YAML::Value << meshColliderComponent.CollisionMesh->Handle;
out << YAML::Key << "AssetPath" << YAML::Value << meshColliderComponent.CollisionMesh->FilePath;
}
out << YAML::Key << "IsConvex" << YAML::Value << meshColliderComponent.IsConvex; out << YAML::Key << "IsConvex" << YAML::Value << meshColliderComponent.IsConvex;
out << YAML::Key << "IsTrigger" << YAML::Value << meshColliderComponent.IsTrigger; out << YAML::Key << "IsTrigger" << YAML::Value << meshColliderComponent.IsTrigger;
out << YAML::Key << "OverrideMesh" << YAML::Value << meshColliderComponent.OverrideMesh; out << YAML::Key << "OverrideMesh" << YAML::Value << meshColliderComponent.OverrideMesh;
if (meshColliderComponent.Material) if (meshColliderComponent.Material)
{
out << YAML::Key << "Material" << YAML::Value << meshColliderComponent.Material->Handle; out << YAML::Key << "Material" << YAML::Value << meshColliderComponent.Material->Handle;
out << YAML::Key << "MaterialPath" << YAML::Value << meshColliderComponent.Material->FilePath;
}
else else
{
out << YAML::Key << "Material" << YAML::Value << 0; out << YAML::Key << "Material" << YAML::Value << 0;
out << YAML::Key << "MaterialPath" << YAML::Value << "";
}
out << YAML::EndMap; // MeshColliderComponent out << YAML::EndMap; // MeshColliderComponent
} }
@ -829,7 +874,7 @@ namespace Prism
if (meshComponent["AssetPath"]) if (meshComponent["AssetPath"])
{ {
const std::string assetFilePath = meshComponent["AssetPath"].as<std::string>(); const std::string assetFilePath = meshComponent["AssetPath"].as<std::string>();
assetID = AssetsManager::GetAssetHandleFromFilePath(filepath); assetID = AssetsManager::GetAssetHandleFromFilePath(assetFilePath);
} }
else else
{ {
@ -858,8 +903,8 @@ namespace Prism
AssetHandle assetHandle; AssetHandle assetHandle;
if (skyLightComponent["EnvironmentAssetPath"]) if (skyLightComponent["EnvironmentAssetPath"])
{ {
const auto filePath = skyLightComponent["EnvironmentAssetPath"].as<std::string>(); const auto assetFilePath = skyLightComponent["EnvironmentAssetPath"].as<std::string>();
assetHandle = AssetsManager::GetAssetHandleFromFilePath(filepath); assetHandle = AssetsManager::GetAssetHandleFromFilePath(assetFilePath);
} }
else else
{ {
@ -1055,8 +1100,16 @@ namespace Prism
if (material && AssetsManager::IsAssetHandleValid(material.as<uint64_t>())) if (material && AssetsManager::IsAssetHandleValid(material.as<uint64_t>()))
{ {
component.Material = AssetsManager::GetAsset<PhysicsMaterial>(material.as<uint64_t>()); component.Material = AssetsManager::GetAsset<PhysicsMaterial>(material.as<uint64_t>());
}else
{
const auto materialPath = boxColliderComponent["MaterialPath"].as<std::string>();
if (const auto assetId = AssetsManager::GetAssetHandleFromFilePath(materialPath); assetId != 0)
{
component.Material = AssetsManager::GetAsset<PhysicsMaterial>(assetId);
}
} }
component.DebugMesh = MeshFactory::CreateBox(component.Size); component.DebugMesh = MeshFactory::CreateBox(component.Size);
} }
@ -1068,7 +1121,17 @@ namespace Prism
auto material = sphereColliderComponent["Material"]; auto material = sphereColliderComponent["Material"];
if (material && AssetsManager::IsAssetHandleValid(material.as<uint64_t>())) if (material && AssetsManager::IsAssetHandleValid(material.as<uint64_t>()))
{
component.Material = AssetsManager::GetAsset<PhysicsMaterial>(material.as<uint64_t>()); component.Material = AssetsManager::GetAsset<PhysicsMaterial>(material.as<uint64_t>());
}else
{
const auto materialPath = sphereColliderComponent["MaterialPath"].as<std::string>();
if (const auto assetId = AssetsManager::GetAssetHandleFromFilePath(materialPath); assetId != 0)
{
component.Material = AssetsManager::GetAsset<PhysicsMaterial>(assetId);
}
}
component.DebugMesh = MeshFactory::CreateSphere(component.Radius); component.DebugMesh = MeshFactory::CreateSphere(component.Radius);
} }
@ -1082,7 +1145,16 @@ namespace Prism
auto material = capsuleColliderComponent["Material"]; auto material = capsuleColliderComponent["Material"];
if (material && AssetsManager::IsAssetHandleValid(material.as<uint64_t>())) if (material && AssetsManager::IsAssetHandleValid(material.as<uint64_t>()))
{
component.Material = AssetsManager::GetAsset<PhysicsMaterial>(material.as<uint64_t>()); component.Material = AssetsManager::GetAsset<PhysicsMaterial>(material.as<uint64_t>());
}else
{
const auto materialPath = capsuleColliderComponent["MaterialPath"].as<std::string>();
if (const auto assetId = AssetsManager::GetAssetHandleFromFilePath(materialPath); assetId != 0)
{
component.Material = AssetsManager::GetAsset<PhysicsMaterial>(assetId);
}
}
component.DebugMesh = MeshFactory::CreateCapsule(component.Radius, component.Height); component.DebugMesh = MeshFactory::CreateCapsule(component.Radius, component.Height);
} }
@ -1095,14 +1167,14 @@ namespace Prism
if (overrideMesh) if (overrideMesh)
{ {
UUID assetID; UUID assetID;
if (meshComponent["AssetPath"]) if (meshColliderComponent["AssetPath"])
{ {
const auto assetFilePath = meshComponent["AssetPath"].as<std::string>(); const auto assetFilePath = meshColliderComponent["AssetPath"].as<std::string>();
assetID = AssetsManager::GetAssetHandleFromFilePath(filepath); assetID = AssetsManager::GetAssetHandleFromFilePath(assetFilePath);
} }
else else
{ {
assetID = meshComponent["AssetID"].as<uint64_t>(); assetID = meshColliderComponent["AssetID"].as<uint64_t>();
} }
if (AssetsManager::IsAssetHandleValid(assetID)) if (AssetsManager::IsAssetHandleValid(assetID))
@ -1116,16 +1188,33 @@ namespace Prism
component.IsTrigger = meshColliderComponent["IsTrigger"] ? meshColliderComponent["IsTrigger"].as<bool>() : false; component.IsTrigger = meshColliderComponent["IsTrigger"] ? meshColliderComponent["IsTrigger"].as<bool>() : false;
component.OverrideMesh = overrideMesh; component.OverrideMesh = overrideMesh;
auto material = meshColliderComponent["Material"]; if (meshColliderComponent["Material"])
if (material && AssetsManager::IsAssetHandleValid(material.as<uint64_t>()))
{ {
component.Material = AssetsManager::GetAsset<PhysicsMaterial>(material.as<uint64_t>()); auto material = meshColliderComponent["Material"];
if (material && AssetsManager::IsAssetHandleValid(material.as<uint64_t>()))
{
component.Material = AssetsManager::GetAsset<PhysicsMaterial>(material.as<uint64_t>());
if (component.IsConvex) if (component.IsConvex)
PhysicsWrappers::CreateConvexMesh(component, deserializedEntity.Transform().Scale); PhysicsWrappers::CreateConvexMesh(component, deserializedEntity.Transform().Scale);
else else
PhysicsWrappers::CreateTriangleMesh(component, deserializedEntity.Transform().Scale); PhysicsWrappers::CreateTriangleMesh(component, deserializedEntity.Transform().Scale);
}else
{
const auto materialPath = meshColliderComponent["MaterialPath"].as<std::string>();
if (const auto assetId = AssetsManager::GetAssetHandleFromFilePath(materialPath); assetId != 0)
{
component.Material = AssetsManager::GetAsset<PhysicsMaterial>(assetId);
if (component.IsConvex)
PhysicsWrappers::CreateConvexMesh(component, deserializedEntity.Transform().Scale);
else
PhysicsWrappers::CreateTriangleMesh(component, deserializedEntity.Transform().Scale);
}
}
} }
} }
else else
{ {

View File

@ -3,6 +3,7 @@
// //
#include "ScriptEngine.h" #include "ScriptEngine.h"
#include <cstddef>
#include <filesystem> #include <filesystem>
@ -35,6 +36,10 @@ namespace Prism
MonoImage* s_AppAssemblyImage = nullptr; MonoImage* s_AppAssemblyImage = nullptr;
MonoImage* s_CoreAssemblyImage = nullptr; MonoImage* s_CoreAssemblyImage = nullptr;
std::vector<std::string> ScriptEngine::s_AvailableScripts;
#ifdef ENABLE_MONO_DEBUG #ifdef ENABLE_MONO_DEBUG
static bool s_EnableMonoPDBDebug = true; static bool s_EnableMonoPDBDebug = true;
#else #else
@ -87,6 +92,7 @@ namespace Prism
static std::unordered_map<std::string, EntityScriptClass> s_EntityClassMap; static std::unordered_map<std::string, EntityScriptClass> s_EntityClassMap;
MonoAssembly* LoadAssemblyFromFile(const char* filepath) MonoAssembly* LoadAssemblyFromFile(const char* filepath)
{ {
if (!filepath) { if (!filepath) {
@ -390,6 +396,12 @@ namespace Prism
void ScriptEngine::Init(const std::string& assemblyPath) void ScriptEngine::Init(const std::string& assemblyPath)
{ {
#ifdef _WIN32
_putenv("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1");
#else
setenv("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", "1", 1);
#endif
s_AssemblyPath = assemblyPath; s_AssemblyPath = assemblyPath;
InitMono(); InitMono();
@ -429,8 +441,8 @@ namespace Prism
s_CoreAssembly = LoadAssembly("assets/scripts/Prism-ScriptCore.dll"); s_CoreAssembly = LoadAssembly("assets/scripts/Prism-ScriptCore.dll");
s_CoreAssemblyImage = GetAssemblyImage(s_CoreAssembly); s_CoreAssemblyImage = GetAssemblyImage(s_CoreAssembly);
auto appAssembly = LoadAssembly(path); const auto appAssembly = LoadAssembly(path);
auto appAssemblyImage = GetAssemblyImage(appAssembly); const auto appAssemblyImage = GetAssemblyImage(appAssembly);
ScriptEngineRegistry::RegisterAll(); ScriptEngineRegistry::RegisterAll();
if (cleanup) if (cleanup)
@ -441,6 +453,8 @@ namespace Prism
s_AppAssembly = appAssembly; s_AppAssembly = appAssembly;
s_AppAssemblyImage = appAssemblyImage; s_AppAssemblyImage = appAssemblyImage;
RefreshAvailableScripts();
} }
void ScriptEngine::ReloadAssembly(const std::string& path) void ScriptEngine::ReloadAssembly(const std::string& path)
@ -845,6 +859,43 @@ namespace Prism
return entityIDMap.at(entityID); return entityIDMap.at(entityID);
} }
void ScriptEngine::RefreshAvailableScripts()
{
if (!s_AppAssemblyImage) return;
s_AvailableScripts.clear();
// 获取类型定义表
const MonoTableInfo *tableInfo = mono_image_get_table_info(s_AppAssemblyImage, MONO_TABLE_TYPEDEF);
int rows = mono_image_get_table_rows(s_AppAssemblyImage, MONO_TABLE_TYPEDEF);
for (int i = 0; i < rows; i++)
{
uint32_t cols[MONO_TYPEDEF_SIZE];
mono_metadata_decode_row(tableInfo, i, cols, MONO_TYPEDEF_SIZE);
// 获取类名和命名空间
const char* name = mono_metadata_string_heap(s_AppAssemblyImage, cols[MONO_TYPEDEF_NAME]);
const char* nameSpace = mono_metadata_string_heap(s_AppAssemblyImage, cols[MONO_TYPEDEF_NAMESPACE]);
if (!name || strlen(name) == 0) continue;
// 构建全名
std::string fullName;
if (nameSpace && strlen(nameSpace) > 0)
fullName = std::string(nameSpace) + "." + name;
else
fullName = name;
s_AvailableScripts.push_back(fullName);
PM_CORE_DEBUG("Script Class: {}", fullName);
}
}
const std::vector<std::string>& ScriptEngine::GetAvailableScripts()
{
return s_AvailableScripts;
}
void ScriptEngine::OnImGuiRender() void ScriptEngine::OnImGuiRender()
{ {
ImGui::Begin("Script Engine Debug"); ImGui::Begin("Script Engine Debug");

View File

@ -150,8 +150,15 @@ namespace Prism
static EntityInstanceMap& GetEntityInstanceMap(); static EntityInstanceMap& GetEntityInstanceMap();
static EntityInstanceData& GetEntityInstanceData(UUID sceneID, UUID entityID); static EntityInstanceData& GetEntityInstanceData(UUID sceneID, UUID entityID);
// GetAll Script Clas s
static const std::vector<std::string>& GetAvailableScripts();
static void RefreshAvailableScripts();
// Debug // Debug
static void OnImGuiRender(); static void OnImGuiRender();
private:
static std::vector<std::string> s_AvailableScripts;
}; };
} }

View File

@ -49,6 +49,8 @@ namespace Prism
{ {
InitComponentTypes(); InitComponentTypes();
mono_add_internal_call("Prism.Debug::Log_Native", (const void*)Prism::Script::Prism_Log_Native);
mono_add_internal_call("Prism.Noise::PerlinNoise_Native", (const void*)Prism::Script::Prism_Noise_PerlinNoise); mono_add_internal_call("Prism.Noise::PerlinNoise_Native", (const void*)Prism::Script::Prism_Noise_PerlinNoise);
mono_add_internal_call("Prism.Physics::Raycast_Native", (const void*)Prism::Script::Prism_Physics_Raycast); mono_add_internal_call("Prism.Physics::Raycast_Native", (const void*)Prism::Script::Prism_Physics_Raycast);

View File

@ -10,6 +10,7 @@
#include <mono/metadata/object.h> #include <mono/metadata/object.h>
#include <mono/metadata/reflection.h> #include <mono/metadata/reflection.h>
#include <mono/metadata/appdomain.h> #include <mono/metadata/appdomain.h>
#include <mono/utils/mono-publib.h>
#include "Prism/Core/Input.h" #include "Prism/Core/Input.h"
#include "Prism/Core/Math/Noise.h" #include "Prism/Core/Math/Noise.h"
@ -32,6 +33,24 @@ namespace Prism { namespace Script {
SpriteRenderer = 4 SpriteRenderer = 4
}; };
////////////////////////////////////////////////////////////////
// Debug ////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
void Prism_Log_Native(MonoString* message)
{
if (message)
{
char* utf8 = mono_string_to_utf8(message);
if (utf8)
{
PM_CLIENT_INFO("[c#]: {}", utf8);
mono_free(utf8);
}
}
}
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// Math //////////////////////////////////////////////////////// // Math ////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////

View File

@ -26,6 +26,9 @@ namespace Prism { namespace Script {
}; };
*/ */
// Debug
void Prism_Log_Native(MonoString* message);
// Math // Math
float Prism_Noise_PerlinNoise(float x, float y); float Prism_Noise_PerlinNoise(float x, float y);

View File

@ -0,0 +1,11 @@
project(PrismRuntime)
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)
add_executable(${PROJECT_NAME}-Console ${SRC_SOURCE})
target_link_libraries(${PROJECT_NAME}-Console PRIVATE Prism-static)

View File

@ -0,0 +1,63 @@
//
// Created by Atdunbg on 2026/3/23.
//
#include "PrismRuntime.h"
#include "Prism/Renderer/Renderer.h"
#include "Prism/Renderer/SceneRenderer.h"
#include "Prism/Scene/SceneSerializer.h"
void PrismRuntime::OnAttach()
{
PM_CLIENT_INFO("App init");
AppInstance = &Prism::Application::Get();
PM_CLIENT_INFO("Create Scene");
const Prism::Ref<Prism::Scene> newScene = Prism::Ref<Prism::Scene>::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);
m_CurrentScene = newScene;
const glm::ivec2 windowSize = AppInstance->GetWindow().GetSize();
if (m_CurrentScene && windowSize.x > 0 && windowSize.y > 0)
{
Prism::SceneRenderer::SetViewportSize(windowSize.x, windowSize.y);
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);
m_CurrentScene->OnRenderRuntime(deltaTime);
const glm::vec2 windowSize = AppInstance->GetWindow().GetSize();
if (m_CurrentScene && windowSize.x > 0 && windowSize.y > 0)
{
m_CurrentScene->SetViewportSize(windowSize);
}
}
void PrismRuntime::OnEvent(Prism::Event& e)
{
}
void PrismRuntime::OnImGuiRender()
{
}

View File

@ -0,0 +1,30 @@
//
// Created by Atdunbg on 2026/3/23.
//
#ifndef PRISM_PRISMRUNTIME_H
#define PRISM_PRISMRUNTIME_H
#include "Prism/Core/Application.h"
#include "Prism/Core/Layer.h"
#include "Prism/Scene/Scene.h"
class PrismRuntime : public Prism::Layer
{
public:
void OnAttach() override;
void OnDetach() override;
void OnUpdate(Prism::TimeStep deltaTime) override;
void OnEvent(Prism::Event& e) override;
void OnImGuiRender() override;
private:
Prism::Ref<Prism::Scene> m_CurrentScene;
Prism::Application* AppInstance = nullptr;
};
#endif //PRISM_PRISMRUNTIME_H

View File

@ -0,0 +1,25 @@
//
// Created by Atdunbg on 2026/3/23.
//
#include "Prism.h"
#include "PrismRuntime.h"
#include "Prism/Core/EntryPoint.h"
class PrismRuntimeApp : public Prism::Application
{
public:
explicit PrismRuntimeApp(const Prism::ApplicationProps& props)
: Application(props)
{
}
virtual void OnInit() override
{
PushLayer(new PrismRuntime());
}
};
Prism::Application* Prism::CreateApplication(const CommandArgs args)
{
return new PrismRuntimeApp({"Game", 1920, 1080, args});
}