From 55ab6e28224e1f56f21f8b86b41c1d2ac42f4b1e Mon Sep 17 00:00:00 2001 From: indigo Date: Tue, 26 Sep 2023 14:56:30 +0800 Subject: [PATCH] Init Repo --- FlipScope.sln | 28 + FlipScope.vcxproj | 216 +++ FlipScope.vcxproj.filters | 243 ++++ FlipScope.vcxproj.user | 13 + FlipScopeProperty.props | 17 + README.md | 19 + UsdPropertySheet.props | 16 + images/FlipScopeUI.png | Bin 0 -> 336665 bytes imgui.ini | 46 + src/FlipScope/Core/AppController.cpp | 144 ++ src/FlipScope/Core/AppController.h | 41 + src/FlipScope/Core/Application.cpp | 59 + src/FlipScope/Core/Application.h | 42 + src/FlipScope/Core/Core.h | 12 + src/FlipScope/Core/Log.cpp | 23 + src/FlipScope/Core/Log.h | 32 + src/FlipScope/Core/Window.cpp | 13 + src/FlipScope/Core/Window.h | 45 + src/FlipScope/Event/ApplicationEvent.h | 57 + src/FlipScope/Event/Event.h | 83 ++ src/FlipScope/ImGui/ImGuiBuild.cpp | 6 + src/FlipScope/ImGui/ImGuiLayer.cpp | 358 +++++ src/FlipScope/ImGui/ImGuiLayer.h | 69 + src/FlipScope/ImGui/imgui_impl_glfw.cpp | 1179 +++++++++++++++++ src/FlipScope/ImGui/imgui_impl_opengl3.cpp | 726 ++++++++++ src/FlipScope/Pipeline/Episode.cpp | 22 + src/FlipScope/Pipeline/Episode.h | 27 + src/FlipScope/Pipeline/Project.cpp | 155 +++ src/FlipScope/Pipeline/Project.h | 74 ++ src/FlipScope/Pipeline/ProjectInfo.cpp | 139 ++ src/FlipScope/Pipeline/ProjectInfo.h | 36 + src/FlipScope/Pipeline/Shot.cpp | 32 + src/FlipScope/Pipeline/Shot.h | 49 + src/FlipScope/Renderer/FrameBuffer.cpp | 24 + src/FlipScope/Renderer/FrameBuffer.h | 28 + src/FlipScope/Renderer/GraphicsContext.cpp | 21 + src/FlipScope/Renderer/GraphicsContext.h | 15 + src/FlipScope/Renderer/RenderCommand.cpp | 8 + src/FlipScope/Renderer/RenderCommand.h | 32 + src/FlipScope/Renderer/Renderer.cpp | 31 + src/FlipScope/Renderer/Renderer.h | 20 + src/FlipScope/Renderer/RendererAPI.cpp | 17 + src/FlipScope/Renderer/RendererAPI.h | 31 + src/FlipScope/Renderer/Texture.cpp | 46 + src/FlipScope/Renderer/Texture.h | 27 + src/FlipScope/Renderer/ViewportRenderer.cpp | 25 + src/FlipScope/Renderer/ViewportRenderer.h | 26 + src/FlipScope/Usd/FreeCamera.cpp | 300 +++++ src/FlipScope/Usd/FreeCamera.h | 82 ++ src/FlipScope/Usd/HdRenderer.cpp | 1 + src/FlipScope/Usd/HdRenderer.h | 61 + src/FlipScope/Usd/HydraRenderer.cpp | 488 +++++++ src/FlipScope/Usd/HydraRenderer.h | 96 ++ src/FlipScope/Usd/SelectionModel.cpp | 57 + src/FlipScope/Usd/SelectionModel.h | 35 + src/FlipScope/Usd/StageDataModel.cpp | 105 ++ src/FlipScope/Usd/StageDataModel.h | 72 + src/FlipScope/Usd/StageNoticeListener.cpp | 90 ++ src/FlipScope/Usd/StageNoticeListener.h | 45 + src/FlipScope/Usd/ViewSettings.cpp | 25 + src/FlipScope/Usd/ViewSettings.h | 69 + src/FlipScope/Widgets/ShotView.cpp | 177 +++ src/FlipScope/Widgets/ShotView.h | 13 + src/FlipScope/Widgets/StageView.cpp | 358 +++++ src/FlipScope/Widgets/StageView.h | 29 + src/FlipScope/Widgets/Viewport.cpp | 232 ++++ src/FlipScope/Widgets/Viewport.h | 38 + src/Platform/OpenGL/OpenGLContext.cpp | 42 + src/Platform/OpenGL/OpenGLContext.h | 20 + src/Platform/OpenGL/OpenGLFramebuffer.cpp | 77 ++ src/Platform/OpenGL/OpenGLFramebuffer.h | 30 + src/Platform/OpenGL/OpenGLRendererAPI.cpp | 33 + src/Platform/OpenGL/OpenGLRendererAPI.h | 18 + src/Platform/OpenGL/OpenGLTexture.cpp | 90 ++ src/Platform/OpenGL/OpenGLTexture.h | 38 + .../OpenGL/OpenGLViewportRenderer.cpp | 35 + src/Platform/OpenGL/OpenGLViewportRenderer.h | 28 + src/Platform/Windows/WindowsWindow.cpp | 145 ++ src/Platform/Windows/WindowsWindow.h | 93 ++ src/main.cpp | 11 + src/pch.cpp | 1 + src/pch.h | 19 + 82 files changed, 7425 insertions(+) create mode 100644 FlipScope.sln create mode 100644 FlipScope.vcxproj create mode 100644 FlipScope.vcxproj.filters create mode 100644 FlipScope.vcxproj.user create mode 100644 FlipScopeProperty.props create mode 100644 README.md create mode 100644 UsdPropertySheet.props create mode 100644 images/FlipScopeUI.png create mode 100644 imgui.ini create mode 100644 src/FlipScope/Core/AppController.cpp create mode 100644 src/FlipScope/Core/AppController.h create mode 100644 src/FlipScope/Core/Application.cpp create mode 100644 src/FlipScope/Core/Application.h create mode 100644 src/FlipScope/Core/Core.h create mode 100644 src/FlipScope/Core/Log.cpp create mode 100644 src/FlipScope/Core/Log.h create mode 100644 src/FlipScope/Core/Window.cpp create mode 100644 src/FlipScope/Core/Window.h create mode 100644 src/FlipScope/Event/ApplicationEvent.h create mode 100644 src/FlipScope/Event/Event.h create mode 100644 src/FlipScope/ImGui/ImGuiBuild.cpp create mode 100644 src/FlipScope/ImGui/ImGuiLayer.cpp create mode 100644 src/FlipScope/ImGui/ImGuiLayer.h create mode 100644 src/FlipScope/ImGui/imgui_impl_glfw.cpp create mode 100644 src/FlipScope/ImGui/imgui_impl_opengl3.cpp create mode 100644 src/FlipScope/Pipeline/Episode.cpp create mode 100644 src/FlipScope/Pipeline/Episode.h create mode 100644 src/FlipScope/Pipeline/Project.cpp create mode 100644 src/FlipScope/Pipeline/Project.h create mode 100644 src/FlipScope/Pipeline/ProjectInfo.cpp create mode 100644 src/FlipScope/Pipeline/ProjectInfo.h create mode 100644 src/FlipScope/Pipeline/Shot.cpp create mode 100644 src/FlipScope/Pipeline/Shot.h create mode 100644 src/FlipScope/Renderer/FrameBuffer.cpp create mode 100644 src/FlipScope/Renderer/FrameBuffer.h create mode 100644 src/FlipScope/Renderer/GraphicsContext.cpp create mode 100644 src/FlipScope/Renderer/GraphicsContext.h create mode 100644 src/FlipScope/Renderer/RenderCommand.cpp create mode 100644 src/FlipScope/Renderer/RenderCommand.h create mode 100644 src/FlipScope/Renderer/Renderer.cpp create mode 100644 src/FlipScope/Renderer/Renderer.h create mode 100644 src/FlipScope/Renderer/RendererAPI.cpp create mode 100644 src/FlipScope/Renderer/RendererAPI.h create mode 100644 src/FlipScope/Renderer/Texture.cpp create mode 100644 src/FlipScope/Renderer/Texture.h create mode 100644 src/FlipScope/Renderer/ViewportRenderer.cpp create mode 100644 src/FlipScope/Renderer/ViewportRenderer.h create mode 100644 src/FlipScope/Usd/FreeCamera.cpp create mode 100644 src/FlipScope/Usd/FreeCamera.h create mode 100644 src/FlipScope/Usd/HdRenderer.cpp create mode 100644 src/FlipScope/Usd/HdRenderer.h create mode 100644 src/FlipScope/Usd/HydraRenderer.cpp create mode 100644 src/FlipScope/Usd/HydraRenderer.h create mode 100644 src/FlipScope/Usd/SelectionModel.cpp create mode 100644 src/FlipScope/Usd/SelectionModel.h create mode 100644 src/FlipScope/Usd/StageDataModel.cpp create mode 100644 src/FlipScope/Usd/StageDataModel.h create mode 100644 src/FlipScope/Usd/StageNoticeListener.cpp create mode 100644 src/FlipScope/Usd/StageNoticeListener.h create mode 100644 src/FlipScope/Usd/ViewSettings.cpp create mode 100644 src/FlipScope/Usd/ViewSettings.h create mode 100644 src/FlipScope/Widgets/ShotView.cpp create mode 100644 src/FlipScope/Widgets/ShotView.h create mode 100644 src/FlipScope/Widgets/StageView.cpp create mode 100644 src/FlipScope/Widgets/StageView.h create mode 100644 src/FlipScope/Widgets/Viewport.cpp create mode 100644 src/FlipScope/Widgets/Viewport.h create mode 100644 src/Platform/OpenGL/OpenGLContext.cpp create mode 100644 src/Platform/OpenGL/OpenGLContext.h create mode 100644 src/Platform/OpenGL/OpenGLFramebuffer.cpp create mode 100644 src/Platform/OpenGL/OpenGLFramebuffer.h create mode 100644 src/Platform/OpenGL/OpenGLRendererAPI.cpp create mode 100644 src/Platform/OpenGL/OpenGLRendererAPI.h create mode 100644 src/Platform/OpenGL/OpenGLTexture.cpp create mode 100644 src/Platform/OpenGL/OpenGLTexture.h create mode 100644 src/Platform/OpenGL/OpenGLViewportRenderer.cpp create mode 100644 src/Platform/OpenGL/OpenGLViewportRenderer.h create mode 100644 src/Platform/Windows/WindowsWindow.cpp create mode 100644 src/Platform/Windows/WindowsWindow.h create mode 100644 src/main.cpp create mode 100644 src/pch.cpp create mode 100644 src/pch.h diff --git a/FlipScope.sln b/FlipScope.sln new file mode 100644 index 0000000..973d21d --- /dev/null +++ b/FlipScope.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FlipScope", "FlipScope.vcxproj", "{B88A50A3-94F6-4CDC-B92D-940418AD1F7C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B88A50A3-94F6-4CDC-B92D-940418AD1F7C}.Debug|x64.ActiveCfg = Debug|x64 + {B88A50A3-94F6-4CDC-B92D-940418AD1F7C}.Debug|x64.Build.0 = Debug|x64 + {B88A50A3-94F6-4CDC-B92D-940418AD1F7C}.Debug|x86.ActiveCfg = Debug|Win32 + {B88A50A3-94F6-4CDC-B92D-940418AD1F7C}.Debug|x86.Build.0 = Debug|Win32 + {B88A50A3-94F6-4CDC-B92D-940418AD1F7C}.Release|x64.ActiveCfg = Release|x64 + {B88A50A3-94F6-4CDC-B92D-940418AD1F7C}.Release|x64.Build.0 = Release|x64 + {B88A50A3-94F6-4CDC-B92D-940418AD1F7C}.Release|x86.ActiveCfg = Release|Win32 + {B88A50A3-94F6-4CDC-B92D-940418AD1F7C}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/FlipScope.vcxproj b/FlipScope.vcxproj new file mode 100644 index 0000000..37e88a2 --- /dev/null +++ b/FlipScope.vcxproj @@ -0,0 +1,216 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {B88A50A3-94F6-4CDC-B92D-940418AD1F7C} + FlipScope + 10.0.19041.0 + + + + Application + true + v143 + MultiByte + + + Application + false + v143 + true + MultiByte + + + Application + true + v143 + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + Level3 + Disabled + true + + + true + + + + + Level3 + Disabled + true + + + true + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + true + + + + + Level1 + Disabled + true + true + true + $(SolutionDir)src;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;NOMINMAX;%(PreprocessorDefinitions) + Use + pch.h + 4819 + true + + + true + true + true + + + copy $(TargetPath) $(SolutionDir)build\$(ProjectName) /Y/B + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FlipScope.vcxproj.filters b/FlipScope.vcxproj.filters new file mode 100644 index 0000000..b4a99df --- /dev/null +++ b/FlipScope.vcxproj.filters @@ -0,0 +1,243 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + + \ No newline at end of file diff --git a/FlipScope.vcxproj.user b/FlipScope.vcxproj.user new file mode 100644 index 0000000..ddaa0dd --- /dev/null +++ b/FlipScope.vcxproj.user @@ -0,0 +1,13 @@ + + + + true + + + $(SolutionDir)Build\$(ProjectName)\$(TargetName)$(TargetExt) + WindowsLocalDebugger + $(SolutionDir)Build\$(ProjectName) + PATH=%PATH%;$(SolutionDir)libs\usd\build\bin;$(SolutionDir)libs\usd\build\lib +$(LocalDebuggerEnvironment) + + \ No newline at end of file diff --git a/FlipScopeProperty.props b/FlipScopeProperty.props new file mode 100644 index 0000000..1c4dc47 --- /dev/null +++ b/FlipScopeProperty.props @@ -0,0 +1,17 @@ + + + + + + + + $(SolutionDir)libs\glfw\build\include;$(SolutionDir)libs\glad\build\include;$(SolutionDir)libs\spdlog\build\include;$(SolutionDir)libs\imgui\build\include;$(SolutionDir)libs\stb_image\build\include;$(SolutionDir)libs\jsoncpp\build\include;$(SolutionDir)libs\glm;$(SolutionDir)libs\stb;$(SolutionDir)libs\usd\build\include;$(SolutionDir)libs\ext;%(AdditionalIncludeDirectories) + GLEW_STATIC;%(PreprocessorDefinitions) + + + $(SolutionDir)libs\glfw\build\lib;$(SolutionDir)libs\glad\build\lib;$(SolutionDir)libs\spdlog\build\lib;$(SolutionDir)libs\imgui\build\lib;$(SolutionDir)libs\jsoncpp\build\lib;$(SolutionDir)libs\stb_image\build\lib;$(SolutionDir)libs\usd\build\lib;%(AdditionalLibraryDirectories) + glfw3.lib;glad.lib;spdlog.lib;imgui.lib;jsoncpp.lib;stb_image.lib;opengl32.lib;%(AdditionalDependencies) + + + + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..819fdf5 --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# FlipScope +Usd Layer Editor for lighing. Basic concept is create layer override like maya render layer. Prototype for now + +## Requirements +* Imgui +* glad +* glew +* jsoncpp +* spdlog +* stb_image +* USD 20.02 +* Visual Studio 2022 + +![FlipScope](images/FlipScopeUI.png) + +## To Do +* Outliner Editor +* Property Editor +* Layer Editor \ No newline at end of file diff --git a/UsdPropertySheet.props b/UsdPropertySheet.props new file mode 100644 index 0000000..f8ea6b5 --- /dev/null +++ b/UsdPropertySheet.props @@ -0,0 +1,16 @@ + + + + + + + + $(SolutionDir)libs\usd\build\include;$(SolutionDir)libs\usd\build\include\boost-1_61;C:\Python27\include;%(AdditionalIncludeDirectories) + + + $(SolutionDir)libs\usd\build\lib;C:\Python27\libs;%(AdditionalLibraryDirectories) + hgi.lib;hgiGL.lib;hio.lib;usd.lib;usdAppUtils.lib;usdGeom.lib;usdHydra.lib;usdImaging.lib;usdImagingGL.lib;usdLux.lib;usdMedia.lib;usdRender.lib;usdRi.lib;usdRiImaging.lib;usdShade.lib;usdSkel.lib;usdSkelImaging.lib;usdUI.lib;usdUtils.lib;usdviewq.lib;usdVol.lib;usdVolImaging.lib;vt.lib;work.lib;ar.lib;arch.lib;boost_atomic-vc140-mt-1_61.lib;boost_chrono-vc140-mt-1_61.lib;boost_date_time-vc140-mt-1_61.lib;boost_filesystem-vc140-mt-1_61.lib;boost_program_options-vc140-mt-1_61.lib;boost_python-vc140-mt-1_61.lib;boost_regex-vc140-mt-1_61.lib;boost_system-vc140-mt-1_61.lib;boost_thread-vc140-mt-1_61.lib;cameraUtil.lib;garch.lib;gf.lib;glf.lib;Half.lib;hd.lib;hdSt.lib;hdx.lib;hf.lib;sdf.lib;tf.lib;js.lib;python27.lib;%(AdditionalDependencies) + + + + \ No newline at end of file diff --git a/images/FlipScopeUI.png b/images/FlipScopeUI.png new file mode 100644 index 0000000000000000000000000000000000000000..36901d3dfe019d0663bfe5deedd60e5c4064f2fe GIT binary patch literal 336665 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%0D;W~ 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 z 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 +$S)K(|m|M48{~z)i!#2*Bkx_ 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 + +namespace FSV +{ + std::shared_ptr AppController::m_StageDataModel; + + bool AppController::m_StageChanged = false; + AppController::AppController() + { + m_StageDataModel = std::make_shared(); + NewStage(); + m_StageChanged = false; + } + + AppController::~AppController() + { + } + + void AppController::NewStage() + { + auto stageDataModel = GetStageDataModel(); + std::string tmpDir = getenv("TEMP"); + std::string stageFilePath = tmpDir + "/untitled.usd"; + m_StageDataModel->SetStage(UsdStage::CreateNew(stageFilePath)); + m_StageDataModel->SetStageFilePath(stageFilePath); + } + + void AppController::OpenStageDialog() + { + static std::vector filters = { + "USD Formats (*.usd, *.usdc, *.usda, *.usdz)", "*.usd; *.usda; *.usdc; *.usdz" + }; + + std::vector selection = pfd::open_file("Open USD Stage", "", filters, false).result(); + + if (!selection.size()) + { + FS_ERROR("OpenStageDialog() :: Nothing to open..."); + return; + } + + auto stageDataModel = GetStageDataModel(); + + if (stageDataModel->GetStageFilePath() == selection[0]) + { + FS_WARN("OpenStageDialog() :: Stage {} is aleady opened...", selection[0]); + return; + } + + stageDataModel->SetStage(UsdStage::Open(selection[0])); + stageDataModel->SetStageFilePath(selection[0]); + m_StageChanged = true; + FS_INFO("OpenStageDialog() :: Stage {} opened...", selection[0]); + } + + bool AppController::SaveStage() + { + auto stageDataModel = GetStageDataModel(); + std::string result = stageDataModel->GetStageFilePath(); + if (!stageDataModel->GetStage()->GetRootLayer()->Save()) + { + FS_ERROR("Stage not saved :: {}", result); + return false; + } + FS_INFO("SaveStage() : Stage saved :: {}", result); + return true; + } + + bool AppController::ExportStage(std::string filePath, bool composed = false) + { + auto stageDataModel = GetStageDataModel(); + if (composed) + { + if (!stageDataModel->GetStage()->Export(filePath)) + { + FS_ERROR("ExportStage() :: Stage (composed) not export"); + return false; + } + FS_INFO("ExportStage() :: Stage (composed) exported :: {}", filePath); + return true; + } + + if (!stageDataModel->GetStage()->GetRootLayer()->Export(filePath)) + { + FS_ERROR("ExportStage() :: Stage not exported :: {}", filePath); + return false; + } + FS_INFO("ExportStage() :: Stage exported :: {}", filePath); + return true; + } + + bool AppController::ExportDialog(bool composed = false) + { + static std::vector filters = { + "USDC (*.usdc)", "*.usdc", + "USDA (*.usda)", "*.usda", + "USDZ (*.usdz)", "*.usdz" + }; + std::string result = pfd::save_file("Export Stage as ...", "", filters, true).result(); + return ExportStage(result, composed); + } + + bool AppController::ExportComposedDialog() + { + return ExportDialog(true); + } + + bool AppController::CreatePrim(std::string path, std::string typeName) + { + auto stageDataModel = GetStageDataModel(); + UsdPrim prim = stageDataModel->GetStage()->DefinePrim(SdfPath(path), TfToken(typeName)); + if ( !prim || !prim.IsDefined()) + { + FS_WARN("Prim({}) : {} is not defined", typeName, path); + return false; + } + FS_INFO("Prim({}) : {} defined", typeName, path); + return true; + } + + bool AppController::CreateOverridePrim(std::string path) + { + auto stageDataModel = GetStageDataModel(); + UsdPrim prim = stageDataModel->GetStage()->OverridePrim(SdfPath(path)); + if ( !prim ) + { + FS_WARN("Override Prim : {} is not defined", path); + return false; + } + FS_INFO("Override Prim : {} defined", path); + return true; + } + +} \ No newline at end of file diff --git a/src/FlipScope/Core/AppController.h b/src/FlipScope/Core/AppController.h new file mode 100644 index 0000000..2d7e50e --- /dev/null +++ b/src/FlipScope/Core/AppController.h @@ -0,0 +1,41 @@ +#pragma once + +#include "pch.h" +#include "pxr/usd/usd/stage.h" +#include "pxr/usd/usd/stagePopulationMask.h" + +#include "FlipScope/Usd/StageDataModel.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +namespace FSV +{ + class AppController + { + public: + AppController(); + virtual ~AppController(); + + static void NewStage(); + static void OpenStageDialog(); + + static bool SaveStage(); + static bool ExportStage(std::string filePath, bool composed); + + bool IsStageChanged() { return m_StageChanged; } + void SetStageChanged(bool value) { m_StageChanged = value; } + + static bool ExportDialog(bool composed); + static bool ExportComposedDialog(); + + static bool CreatePrim(std::string path, std::string typeName); + static bool CreateOverridePrim(std::string path); + + static std::shared_ptr GetStageDataModel() { return m_StageDataModel; }; + + + private: + static std::shared_ptr m_StageDataModel; + static bool m_StageChanged; + }; +} diff --git a/src/FlipScope/Core/Application.cpp b/src/FlipScope/Core/Application.cpp new file mode 100644 index 0000000..88f4a2c --- /dev/null +++ b/src/FlipScope/Core/Application.cpp @@ -0,0 +1,59 @@ +#include "pch.h" + +#include "FlipScope/Core/Core.h" +#include "FlipScope/Core/Application.h" +#include "FlipScope/Core/Log.h" + +#include "FlipScope/Pipeline/ProjectInfo.h" +#include "FlipScope/Renderer/Renderer.h" +#include "FlipScope/Core/AppController.h" + +namespace FSV { + Application* Application::s_Instance = nullptr; + ProjectInfo* Application::s_ProjectInfo = nullptr; + AppController* Application::s_Controller = nullptr; + + Application::Application() + { + s_Instance = this; + s_ProjectInfo = new ProjectInfo(); + s_Controller = new AppController(); + m_Window = Window::Create(); + + Renderer::Init(); + + m_ImGuiLayer = new ImGuiLayer(); + m_ImGuiLayer->OnAttach(); + } + + Application::~Application() + { + Renderer::Shutdown(); + m_ImGuiLayer->OnDetach(); + } + + void Application::Run() { + FS_INFO("FlipScope Running..."); + while (!m_Window->Close()) + { + m_ImGuiLayer->OnUpdate(); + + glClearColor(0.45f, 0.55f, 0.6f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + + m_ImGuiLayer->Begin(); + m_ImGuiLayer->Render(); + m_ImGuiLayer->End(); + + m_Window->OnUpdate(); + + } + } + + Application * CreateApplication() { + Application *app = new Application(); + return app; + } +} \ No newline at end of file diff --git a/src/FlipScope/Core/Application.h b/src/FlipScope/Core/Application.h new file mode 100644 index 0000000..51dcef7 --- /dev/null +++ b/src/FlipScope/Core/Application.h @@ -0,0 +1,42 @@ +#pragma once + +#include "FlipScope/Core/Window.h" + +#include "FlipScope/Pipeline/ProjectInfo.h" +#include "FlipScope/ImGui/ImGuiLayer.h" +#include "FlipScope/Core/AppController.h" + +#include + +int main(int argc, char** argv); + +namespace FSV +{ + class Application + { + public: + Application(); + ~Application(); + + //void OnEvent() + Window& GetWindow(){ return *m_Window; } + static Application& Get() { return *s_Instance; } + static ProjectInfo& GetProjectInfo() { return *s_ProjectInfo; } + static AppController& GetController() { return *s_Controller; } + void Run(); + + private: + std::unique_ptr m_Window; + ImGuiLayer* m_ImGuiLayer; + bool m_Running = true; + bool m_Minimized = false; + + private: + static Application* s_Instance; + static ProjectInfo* s_ProjectInfo; + static AppController* s_Controller; + friend int ::main(int argc, char** argv); + }; + + Application* CreateApplication(); +} \ No newline at end of file diff --git a/src/FlipScope/Core/Core.h b/src/FlipScope/Core/Core.h new file mode 100644 index 0000000..dceafe8 --- /dev/null +++ b/src/FlipScope/Core/Core.h @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +#include +//#include +#include + +#define BIT(x) (1 << x) + +#define BIND_EVENT_FN(fn) std::bind(&fn, this, std::placeholders::_1) \ No newline at end of file diff --git a/src/FlipScope/Core/Log.cpp b/src/FlipScope/Core/Log.cpp new file mode 100644 index 0000000..8fd350a --- /dev/null +++ b/src/FlipScope/Core/Log.cpp @@ -0,0 +1,23 @@ +#include "pch.h" + +#include "FlipScope/Core/Log.h" + +#include +#include + +namespace FSV +{ + std::shared_ptr Log::s_Logger; + + void Log::Init() + { + std::vector logSinks; + logSinks.emplace_back(std::make_shared()); + logSinks[0]->set_pattern("%^[%T] %n: %v%$"); + s_Logger = std::make_shared("FlipScope", begin(logSinks), end(logSinks)); + + spdlog::register_logger(s_Logger); + s_Logger->set_level(spdlog::level::trace); + s_Logger->flush_on(spdlog::level::trace); + } +} \ No newline at end of file diff --git a/src/FlipScope/Core/Log.h b/src/FlipScope/Core/Log.h new file mode 100644 index 0000000..89ff8cc --- /dev/null +++ b/src/FlipScope/Core/Log.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include + +namespace FSV +{ + class Log + { + public: + static void Init(); + static std::shared_ptr GetLogger() { return s_Logger; } + + private: + static std::shared_ptr s_Logger; + }; + +} + +// Log macros +#define FS_TRACE(...) ::FSV::Log::GetLogger()->trace(__VA_ARGS__) +#define FS_INFO(...) ::FSV::Log::GetLogger()->info(__VA_ARGS__) +#define FS_WARN(...) ::FSV::Log::GetLogger()->warn(__VA_ARGS__) +#define FS_ERROR(...) ::FSV::Log::GetLogger()->error(__VA_ARGS__) +#define FS_CRITICAL(...) ::FSV::Log::GetLogger()->critical(__VA_ARGS__) + +#define FsTrace(...) ::FSV::Log::GetLogger()->trace(__VA_ARGS__) +#define fsInfo(...) ::FSV::Log::GetLogger()->info(__VA_ARGS__) +#define fsWarn(...) ::FSV::Log::GetLogger()->warn(__VA_ARGS__) +#define fsError(...) ::FSV::Log::GetLogger()->error(__VA_ARGS__) +#define fsCritical(...) ::FSV::Log::GetLogger()->critical(__VA_ARGS__) diff --git a/src/FlipScope/Core/Window.cpp b/src/FlipScope/Core/Window.cpp new file mode 100644 index 0000000..877f459 --- /dev/null +++ b/src/FlipScope/Core/Window.cpp @@ -0,0 +1,13 @@ +#include "pch.h" + +#include "Window.h" + +#include "Platform/Windows/WindowsWindow.h" + +namespace FSV +{ + std::unique_ptr Window::Create(const WindowProps& props) + { + return std::make_unique(props); + } +} \ No newline at end of file diff --git a/src/FlipScope/Core/Window.h b/src/FlipScope/Core/Window.h new file mode 100644 index 0000000..0cc7a25 --- /dev/null +++ b/src/FlipScope/Core/Window.h @@ -0,0 +1,45 @@ +#pragma once + +#include "FlipScope/Event/Event.h" + +#include +#include + +namespace FSV { + + struct WindowProps + { + std::string Title; + unsigned int Width; + unsigned int Height; + + WindowProps(const std::string& title="FlipScope Viewer", + unsigned int width=1280, + unsigned int height=720) + :Title(title), Width(width), Height(height) + { + } + }; + + class Window + { + public: + using EventCallbackFn = std::function; + + virtual ~Window() = default; + + virtual void OnUpdate() = 0; + + virtual unsigned int GetWidth() const = 0; + virtual unsigned int GetHeight() const = 0; + + virtual void SetVSync(bool enabled) = 0; + virtual bool IsVSync() const = 0; + virtual void SetEventCallback(const EventCallbackFn& callback) = 0; + + virtual bool Close() const = 0; + virtual void* GetNativeWindow() const = 0; + + static std::unique_ptr Create(const WindowProps& props = WindowProps()); + }; +} \ No newline at end of file diff --git a/src/FlipScope/Event/ApplicationEvent.h b/src/FlipScope/Event/ApplicationEvent.h new file mode 100644 index 0000000..91c9790 --- /dev/null +++ b/src/FlipScope/Event/ApplicationEvent.h @@ -0,0 +1,57 @@ +#pragma once + +#include "FlipScope/Event/Event.h" +#include +#include + +namespace FSV +{ + class WindowResizeEvent : public Event + { + public: + WindowResizeEvent(unsigned int width, unsigned int height) + : m_Width(width), m_Height(height) {} + + unsigned int GetWidth() const { return m_Width; } + unsigned int GetHeight() const { return m_Height; } + + static EventType GetStaticType() { return EventType::WindowResize; } + virtual EventType GetEventType() const override { return GetStaticType(); } + virtual const char* GetName() const override { return "WindowResize"; } + virtual int GetCategoryFlags() const override { return EventCategory::EventCategoryApplication; } + + private: + unsigned int m_Width, m_Height; + }; + + class WindowCloseEvent : public Event + { + public: + WindowCloseEvent() = default; + static EventType GetStaticType() { return EventType::WindowClose; } + virtual EventType GetEventType() const override { return GetStaticType(); } + virtual const char* GetName() const override { return "WindowClose"; } + virtual int GetCategoryFlags() const override { return EventCategory::EventCategoryApplication; } + }; + + class WindowFileDropEvent : public Event + { + public: + WindowFileDropEvent(unsigned int count, const char* paths[]) + : m_Count(count), m_Paths(paths) {} + + unsigned int GetCount() const { return m_Count; } + const char** GetPaths() const { return m_Paths; } + + static EventType GetStaticType() { return EventType::FileDroped; } + virtual EventType GetEventType() const override { return GetStaticType(); } + virtual const char* GetName() const override { return "FileDroped"; } + virtual int GetCategoryFlags() const override { return EventCategory::EventCategoryApplication; } + + private: + int m_Count; + const char** m_Paths; + }; + +} + diff --git a/src/FlipScope/Event/Event.h b/src/FlipScope/Event/Event.h new file mode 100644 index 0000000..2fb6e58 --- /dev/null +++ b/src/FlipScope/Event/Event.h @@ -0,0 +1,83 @@ +#pragma once + +#include "FlipScope/Core/Core.h" + +#include + +namespace FSV +{ + enum class EventType + { + None = 0, + WindowClose, WindowResize, WindowFocus, WindowLostFocus, WindowMove, FileDroped, + KeyPressed, KeyReleased, KeyTyped, + MouseButtonPressed, MouseButtonReleased, MouseMoved, MouseScrolled + }; + + enum EventCategory + { + None = 0, + EventCategoryApplication = BIT(0), + EventCategoryInput = BIT(1), + EventCategoryKeyboard = BIT(2), + EventCategoryMouse = BIT(3), + EventCategoryMouseButton = BIT(4) + }; + +/*#define EVENT_CLASS_TYPE(type) static EventType GetStaticType(){return EventType::type;}\ + virtual EventType GetEventType() const override { return GetStaticType(); }\ + virtual const char* GetName() const override { return #type; }*/ + + class Event + { + public: + bool Handled = false; + virtual EventType GetEventType() const = 0; + virtual const char* GetName() const = 0; + virtual int GetCategoryFlags() const = 0; + virtual std::string ToString() const { return GetName(); } + + bool IsInCategory(EventCategory category) + { + if (GetCategoryFlags() & category) + return true; + return false; + } + + template + inline std::string stringify(const T& x) { + std::ostringstream o; + o << x; + return o.str(); + } + + }; + + class EventDispatcher + { + public: + EventDispatcher(Event& event) + : m_Event(event) + { + } + + // F will be deduced by the compiler + template + bool Dispatch(const F& func) + { + if (m_Event.GetEventType() == T::GetStaticType()) + { + m_Event.Handled = func(static_cast(m_Event)); + return true; + } + return false; + } + private: + Event& m_Event; + }; + + inline std::ostream& operator<<(std::ostream& os, const Event& e) + { + return os << e.ToString(); + } +} diff --git a/src/FlipScope/ImGui/ImGuiBuild.cpp b/src/FlipScope/ImGui/ImGuiBuild.cpp new file mode 100644 index 0000000..2cca027 --- /dev/null +++ b/src/FlipScope/ImGui/ImGuiBuild.cpp @@ -0,0 +1,6 @@ +#include "pch.h" + +#define IMGUI_IMPL_OPENGL_LOADER_GLAD +//#define IMGUI_IMPL_OPENGL_LOADER_GLEW +#include "FlipScope/ImGui/imgui_impl_opengl3.cpp" +#include "FlipScope/ImGui/imgui_impl_glfw.cpp" \ No newline at end of file diff --git a/src/FlipScope/ImGui/ImGuiLayer.cpp b/src/FlipScope/ImGui/ImGuiLayer.cpp new file mode 100644 index 0000000..5009ab7 --- /dev/null +++ b/src/FlipScope/ImGui/ImGuiLayer.cpp @@ -0,0 +1,358 @@ +#include "pch.h" +#include "FlipScope/Core/Core.h" +#include "FlipScope/Core/AppController.h" +#include "FlipScope/ImGui/ImGuiLayer.h" +#include "FlipScope/Renderer/RenderCommand.h" + +#include +#include + +#include +#include + +#include + +#include "FlipScope/Core/Application.h" + + +namespace FSV +{ + static ImGuiDockNodeFlags opt_flags = ImGuiDockNodeFlags_PassthruCentralNode; + ImFont* ImGuiLayer::m_NormalFont; + ImFont* ImGuiLayer::m_SmallFont; + ImFont* ImGuiLayer::m_IconFont; + + //Project* ImGuiLayer::m_CurrentProject; + std::string ImGuiLayer::m_CurrentProjectName; + std::string ImGuiLayer::m_CurrentEpisodeName; + + static bool show_timeline = false; + static bool show_stageview = false; + static bool show_viewport = false; + static bool show_property = false; + static bool show_shotview = false; + + ImGuiLayer::ImGuiLayer() + { + } + + void ImGuiLayer::OnAttach() + { + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); (void)io; + io.ConfigDockingWithShift = true; + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows + ImFontConfig config; + config.FontDataOwnedByAtlas = false; + + m_NormalFont = io.Fonts->AddFontFromFileTTF("resources/fonts/Roboto-Regular.ttf", 16.0, &config); + config.MergeMode = true; + + static const ImWchar icon_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 }; + io.Fonts->AddFontFromFileTTF("resources/fonts/fa-solid-900.ttf", 14.0, &config, icon_ranges); + + m_SmallFont = io.Fonts->AddFontFromFileTTF("resources/fonts/Roboto-Regular.ttf", 14.0, &config); + + io.FontDefault = m_NormalFont; + + ImGui::StyleColorsDark(); + ImGuiStyle& style = ImGui::GetStyle(); + + Application& app = Application::Get(); + GLFWwindow* window = static_cast(app.GetWindow().GetNativeWindow()); + + ImGui_ImplGlfw_InitForOpenGL(window, true); + ImGui_ImplOpenGL3_Init("#version 410"); + + m_Texture = Texture::Create("C:/Test.png"); + + // Build framebuffer + //FramebufferSpecification fbspec; + //fbspec.Width = 1280; + //fbspec.Height = 720; + //m_Framebuffer = Framebuffer::Create(fbspec); + + // Initialize Renderer + //m_HydraRenderer = std::make_shared(1280, 720); + //m_HydraRenderer->Init(1280, 720); + + m_Viewport = std::make_shared(1280, 720); + m_StageView = std::make_shared(); + m_ShotView = std::make_shared(); + } + + void ImGuiLayer::OnUpdate() + { + Application& app = Application::Get(); + AppController& controller = app.GetController(); + + if (controller.IsStageChanged()) + { + m_Viewport->Update(); + controller.SetStageChanged(false); + } + //m_Framebuffer->Bind(); + // Renderer Draw Code + //RenderCommand::SetClearColor(glm::vec4(1.0f, 0.1f, 0.1f, 1)); + //RenderCommand::Clear(); + + //m_HydraRenderer->OnDraw(); + m_Viewport->GetRenderer()->OnRender(); + //m_HydraRenderer->OnRender(); + + //m_Framebuffer->Unbind(); + } + + void ImGuiLayer::OnDetach() + { + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplGlfw_Shutdown(); + ImGui::DestroyContext(); + } + + void ImGuiLayer::Begin() + { + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); + } + + /*void ImGuiLayer::BeginDockSpace() + { + static bool opt_fullscreen_persistant = true; + ImGuiViewport *viewport = ImGui::GetMainViewport(); + + if (ImGui::GetIO().DisplaySize.y > 0) + { + + bool opt_fullscreen = opt_fullscreen_persistant; + + // We are using the ImGuiWindowFlags_NoDocking flag to make the parent + // window not dockable into, because it would be confusing to have two + // docking targets within each others. + ImGuiWindowFlags window_flags = + ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking; + + if (opt_fullscreen) { + auto dockSpaceSize = viewport->Size; + dockSpaceSize.y -= m_StatusBarSize; // remove the status bar + ImGui::SetNextWindowPos(viewport->Pos); + ImGui::SetNextWindowSize(dockSpaceSize); + ImGui::SetNextWindowViewport(viewport->ID); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + + window_flags |= ImGuiWindowFlags_NoTitleBar | + ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | + ImGuiWindowFlags_NoMove; + window_flags |= + ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus; + } + + // When using ImGuiDockNodeFlags_PassthruCentralNode, DockSpace() will render + // our background and handle the pass-thru hole, so we ask Begin() to not + // render a background. + if (opt_flags & ImGuiDockNodeFlags_PassthruCentralNode) + window_flags |= ImGuiWindowFlags_NoBackground; + + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); + static bool alwaysOpened = true; + ImGui::Begin("DockSpace", &alwaysOpened, window_flags); + ImGui::PopStyleVar(); + + if (opt_fullscreen) ImGui::PopStyleVar(2); + + // Dockspace + ImGuiIO &io = ImGui::GetIO(); + if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) { + ImGuiID dockspace_id = ImGui::GetID("FsDockspace"); + ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), opt_flags); + } + else { + // TODO: emit a log message + } + + + } + ImGui::End(); + }*/ + void ImGuiLayer::BeginDockSpace() + { + static bool alwaysOpened = true; + static ImGuiDockNodeFlags dockFlags = ImGuiDockNodeFlags_PassthruCentralNode; + static ImGuiWindowFlags windowFlags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking; + windowFlags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove; + windowFlags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus; + windowFlags |= ImGuiWindowFlags_NoBackground; + ImGuiViewport* viewport = ImGui::GetMainViewport(); + ImGui::SetNextWindowPos(viewport->Pos); + ImGui::SetNextWindowSize(viewport->Size); + ImGui::SetNextWindowViewport(viewport->ID); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); + ImGui::Begin("DockSpace", &alwaysOpened, windowFlags); + ImGui::PopStyleVar(3); + + ImGuiID dockspaceid = ImGui::GetID("dockspace"); + ImGui::DockSpace(dockspaceid, ImVec2(0.0f, 0.0f), dockFlags); + + EndDockSpace(); + } + + void ImGuiLayer::EndDockSpace() + { + ImGui::End(); + } + + float ImGuiLayer::DrawMenuBar() + { + auto menu_height = 0.0f; + if (ImGui::BeginMainMenuBar()) + { + if (ImGui::BeginMenu("File")) + { + ImGui::MenuItem("New", "Ctrl+N", nullptr); + if (ImGui::MenuItem("Open", "Ctrl+O", nullptr)) + { + AppController::OpenStageDialog(); + } + ImGui::MenuItem("Close", "Ctrl+W", nullptr); + ImGui::Separator(); + if (ImGui::MenuItem("Save", "Ctrl+S", nullptr)) + { + AppController::SaveStage(); + } + ImGui::Separator(); + ImGui::MenuItem("Export", "Ctrl+E", nullptr); + ImGui::Separator(); + if (ImGui::MenuItem("Exit", "Ctrl+Q", nullptr)) + { + Application& app = Application::Get(); + app.GetWindow().Close(); + } + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("View")) + { + ImGui::MenuItem("Shots", "Alt+P", &show_shotview); + ImGui::MenuItem("Timeline", "Alt+T", &show_timeline); + ImGui::MenuItem("Stage", "Alt+O", &show_stageview); + ImGui::MenuItem("Viewport", "Alt+V", &show_viewport); + ImGui::MenuItem("Property", "Alt+P", &show_property); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Help")) + { + ImGui::MenuItem("About", "", nullptr); + ImGui::EndMenu(); + } + menu_height = ImGui::GetWindowSize().y; + ImGui::EndMainMenuBar(); + } + + return menu_height; + } + + void ImGuiLayer::DrawStatusBar() + { + ImGuiContext& g = *ImGui::GetCurrentContext(); + ImGuiViewport *viewport = ImGui::GetMainViewport(); + + // Draw status bar(no docking) + ImGui::SetNextWindowSize(ImVec2(viewport->Size.x, m_StatusBarSize)); + ImGui::SetNextWindowPos(ImVec2(viewport->Pos.x, viewport->Pos.y + viewport->Size.y - m_StatusBarSize)); + //ImGui::SetNextWindowPos(ImVec2(0.0f, g.IO.DisplaySize.y - mFooterHeight)); + //ImGui::SetNextWindowSize(ImVec2(g.IO.DisplaySize.x, mFooterHeight)); + + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0.0f, 20.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(2.0f, 2.0f)); + ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoDocking; + + if (!ImGui::Begin("##statusbar", nullptr, window_flags)) + { + ImGui::End(); + return; + } + + ImGui::PopStyleVar(); + ImGui::PopStyleVar(); + ImGui::PopStyleVar(); + ImGui::PopStyleVar(); + // Draw the common stuff + ImGui::SameLine(viewport->Size.x - 100.f); + ImFont *font = ImGui::GetFont(); + font->Scale = 0.875; + ImGui::PushFont(font); + ImGuiIO& io = ImGui::GetIO(); + ImGui::Text("FPS: (%.1f FPS)", io.Framerate); + font->Scale = 1.0; + ImGui::PopFont(); + + ImGui::End(); + } + + void ImGuiLayer::Render() + { + static bool show = true; + auto menu_height = DrawMenuBar(); + BeginDockSpace(); + DrawStatusBar(); + ImGui::ShowDemoWindow(&show); + if (show_timeline) ShowTimeline(&show_timeline); + if (show_property) ShowProperty(&show_property); + if (show_shotview) m_ShotView->Show(&show_shotview); + if (show_viewport) m_Viewport->Show(&show_viewport); + if (show_stageview) m_StageView->Show(&show_stageview); + } + + void ImGuiLayer::ShowTimeline(bool* p_open) + { + ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + if (!ImGui::Begin("Timeline", p_open)) + { + ImGui::End(); + return; + } + ImGui::PopStyleVar(); + ImGui::End(); + } + + void ImGuiLayer::ShowProperty(bool* p_open) + { + ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + if (!ImGui::Begin("Property", p_open)) + { + ImGui::End(); + return; + } + ImGui::PopStyleVar(); + ImGui::End(); + } + + + void ImGuiLayer::End() + { + ImGuiIO& io = ImGui::GetIO(); + Application& app = Application::Get(); + io.DisplaySize = ImVec2((float)app.GetWindow().GetWidth(), (float)app.GetWindow().GetHeight()); + + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + GLFWwindow* backup_current_context = glfwGetCurrentContext(); + ImGui::UpdatePlatformWindows(); + ImGui::RenderPlatformWindowsDefault(); + glfwMakeContextCurrent(backup_current_context); + } + } +} \ No newline at end of file diff --git a/src/FlipScope/ImGui/ImGuiLayer.h b/src/FlipScope/ImGui/ImGuiLayer.h new file mode 100644 index 0000000..8811be2 --- /dev/null +++ b/src/FlipScope/ImGui/ImGuiLayer.h @@ -0,0 +1,69 @@ +#pragma once + +#include "FlipScope/Pipeline/Project.h" + +#include "FlipScope/Renderer/FrameBuffer.h" +#include "FlipScope/Renderer/Texture.h" + +//#include "FlipScope/Usd/HydraRenderer.h" +#include "FlipScope/Widgets/Viewport.h" +#include "FlipScope/Widgets/StageView.h" +#include "FlipScope/Widgets/ShotView.h" + +#include + +namespace FSV +{ + class ImGuiLayer + { + public: + ImGuiLayer(); + ~ImGuiLayer() = default; + void OnAttach(); + void OnDetach(); + + void OnUpdate(); + + void Render(); + void Begin(); + void End(); + public: + void BeginDockSpace(); + void EndDockSpace(); + float DrawMenuBar(); + void DrawStatusBar(); + void ShowViewport(bool *p_open); + void ShowShotList(bool *p_open); + void ShowTimeline(bool *p_open); + void ShowProperty(bool *p_open); + + ImFont* GetNormalFont() { return m_NormalFont; } + ImFont* GetSmallFont() { return m_SmallFont; } + ImFont* GetIconFont() { return m_IconFont; } + + private: + float m_Time = 0.0f; + float m_StatusBarSize = 20.0f; + + glm::vec2 m_ViewportSize = { 0.0f, 0.0f }; + + std::shared_ptr m_Texture; + std::shared_ptr m_Framebuffer; + + //std::shared_ptr m_HydraRenderer; + + static ImFont* m_NormalFont; + static ImFont* m_SmallFont; + static ImFont* m_IconFont; + + static std::string m_CurrentProjectName; + static std::string m_CurrentEpisodeName; + + static bool m_IsViewportFocused; + static bool m_IsViewportHovered; + + std::shared_ptr m_Viewport; + std::shared_ptr m_StageView; + std::shared_ptr m_ShotView; + }; +} diff --git a/src/FlipScope/ImGui/imgui_impl_glfw.cpp b/src/FlipScope/ImGui/imgui_impl_glfw.cpp new file mode 100644 index 0000000..2889373 --- /dev/null +++ b/src/FlipScope/ImGui/imgui_impl_glfw.cpp @@ -0,0 +1,1179 @@ +// dear imgui: Platform Backend for GLFW +// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..) +// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) +// (Requires: GLFW 3.1+. Prefer GLFW 3.3+ for full feature support.) + +// Implemented features: +// [X] Platform: Clipboard support. +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+). +// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. + +// Issues: +// [ ] Platform: Multi-viewport support: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor). + +// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. +// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. +// Read online: https://github.com/ocornut/imgui/tree/master/docs + +// CHANGELOG +// (minor and older changes stripped away, please see git history for details) +// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2022-09-01: Inputs: Honor GLFW_CURSOR_DISABLED by not setting mouse position. +// 2022-04-30: Inputs: Fixed ImGui_ImplGlfw_TranslateUntranslatedKey() for lower case letters on OSX. +// 2022-03-23: Inputs: Fixed a regression in 1.87 which resulted in keyboard modifiers events being reported incorrectly on Linux/X11. +// 2022-02-07: Added ImGui_ImplGlfw_InstallCallbacks()/ImGui_ImplGlfw_RestoreCallbacks() helpers to facilitate user installing callbacks after initializing backend. +// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago)with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion. +// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[]. +// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+). +// 2022-01-17: Inputs: always update key mods next and before key event (not in NewFrame) to fix input queue with very low framerates. +// 2022-01-12: *BREAKING CHANGE*: Now using glfwSetCursorPosCallback(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetCursorPosCallback() and forward it to the backend via ImGui_ImplGlfw_CursorPosCallback(). +// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range. +// 2022-01-05: Inputs: Converting GLFW untranslated keycodes back to translated keycodes (in the ImGui_ImplGlfw_KeyCallback() function) in order to match the behavior of every other backend, and facilitate the use of GLFW with lettered-shortcuts API. +// 2021-08-17: *BREAKING CHANGE*: Now using glfwSetWindowFocusCallback() to calling io.AddFocusEvent(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() and forward it to the backend via ImGui_ImplGlfw_WindowFocusCallback(). +// 2021-07-29: *BREAKING CHANGE*: Now using glfwSetCursorEnterCallback(). MousePos is correctly reported when the host platform window is hovered but not focused. If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() callback and forward it to the backend via ImGui_ImplGlfw_CursorEnterCallback(). +// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). +// 2020-01-17: Inputs: Disable error callback while assigning mouse cursors because some X11 setup don't have them and it generates errors. +// 2019-12-05: Inputs: Added support for new mouse cursors added in GLFW 3.4+ (resizing cursors, not allowed cursor). +// 2019-10-18: Misc: Previously installed user callbacks are now restored on shutdown. +// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter. +// 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter(). +// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized. +// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window. +// 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them. +// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls. +// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor. +// 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples. +// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag. +// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value, passed to glfwSetCursor()). +// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. +// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space. +// 2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set. +// 2018-01-25: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set). +// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support. +// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert. +// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1). +// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers. + +#include "imgui.h" +#include "imgui_impl_glfw.h" + +// Clang warnings with -Weverything +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif +#endif + +// GLFW +#include + +#ifdef _WIN32 +#undef APIENTRY +#define GLFW_EXPOSE_NATIVE_WIN32 +#include // for glfwGetWin32Window() +#endif +#ifdef __APPLE__ +#define GLFW_EXPOSE_NATIVE_COCOA +#include // for glfwGetCocoaWindow() +#endif + +#define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ GLFW_FLOATING +#define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_HOVERED +#define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwSetWindowOpacity +#define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorContentScale +#define GLFW_HAS_VULKAN (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwCreateWindowSurface +#define GLFW_HAS_FOCUS_WINDOW (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwFocusWindow +#define GLFW_HAS_FOCUS_ON_SHOW (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_FOCUS_ON_SHOW +#define GLFW_HAS_MONITOR_WORK_AREA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorWorkarea +#define GLFW_HAS_OSX_WINDOW_POS_FIX (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 + GLFW_VERSION_REVISION * 10 >= 3310) // 3.3.1+ Fixed: Resizing window repositions it on MacOS #1553 +#ifdef GLFW_RESIZE_NESW_CURSOR // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released? +#define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR +#else +#define GLFW_HAS_NEW_CURSORS (0) +#endif +#ifdef GLFW_MOUSE_PASSTHROUGH // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2020-07-17 (passthrough) +#define GLFW_HAS_MOUSE_PASSTHROUGH (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_MOUSE_PASSTHROUGH +#else +#define GLFW_HAS_MOUSE_PASSTHROUGH (0) +#endif +#define GLFW_HAS_GAMEPAD_API (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetGamepadState() new api +#define GLFW_HAS_GET_KEY_NAME (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwGetKeyName() + +// GLFW data +enum GlfwClientApi +{ + GlfwClientApi_Unknown, + GlfwClientApi_OpenGL, + GlfwClientApi_Vulkan +}; + +struct ImGui_ImplGlfw_Data +{ + GLFWwindow* Window; + GlfwClientApi ClientApi; + double Time; + GLFWwindow* MouseWindow; + GLFWcursor* MouseCursors[ImGuiMouseCursor_COUNT]; + ImVec2 LastValidMousePos; + GLFWwindow* KeyOwnerWindows[GLFW_KEY_LAST]; + bool InstalledCallbacks; + bool WantUpdateMonitors; +#ifdef _WIN32 + WNDPROC GlfwWndProc; +#endif + + // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. + GLFWwindowfocusfun PrevUserCallbackWindowFocus; + GLFWcursorposfun PrevUserCallbackCursorPos; + GLFWcursorenterfun PrevUserCallbackCursorEnter; + GLFWmousebuttonfun PrevUserCallbackMousebutton; + GLFWscrollfun PrevUserCallbackScroll; + GLFWkeyfun PrevUserCallbackKey; + GLFWcharfun PrevUserCallbackChar; + GLFWmonitorfun PrevUserCallbackMonitor; + + ImGui_ImplGlfw_Data() { memset((void*)this, 0, sizeof(*this)); } +}; + +// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts +// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. +// FIXME: multi-context support is not well tested and probably dysfunctional in this backend. +// - Because glfwPollEvents() process all windows and some events may be called outside of it, you will need to register your own callbacks +// (passing install_callbacks=false in ImGui_ImplGlfw_InitXXX functions), set the current dear imgui context and then call our callbacks. +// - Otherwise we may need to store a GLFWWindow* -> ImGuiContext* map and handle this in the backend, adding a little bit of extra complexity to it. +// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context. +static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData() +{ + return ImGui::GetCurrentContext() ? (ImGui_ImplGlfw_Data*)ImGui::GetIO().BackendPlatformUserData : NULL; +} + +// Forward Declarations +static void ImGui_ImplGlfw_UpdateMonitors(); +static void ImGui_ImplGlfw_InitPlatformInterface(); +static void ImGui_ImplGlfw_ShutdownPlatformInterface(); + +// Functions +static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data) +{ + return glfwGetClipboardString((GLFWwindow*)user_data); +} + +static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text) +{ + glfwSetClipboardString((GLFWwindow*)user_data, text); +} + +static ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int key) +{ + switch (key) + { + case GLFW_KEY_TAB: return ImGuiKey_Tab; + case GLFW_KEY_LEFT: return ImGuiKey_LeftArrow; + case GLFW_KEY_RIGHT: return ImGuiKey_RightArrow; + case GLFW_KEY_UP: return ImGuiKey_UpArrow; + case GLFW_KEY_DOWN: return ImGuiKey_DownArrow; + case GLFW_KEY_PAGE_UP: return ImGuiKey_PageUp; + case GLFW_KEY_PAGE_DOWN: return ImGuiKey_PageDown; + case GLFW_KEY_HOME: return ImGuiKey_Home; + case GLFW_KEY_END: return ImGuiKey_End; + case GLFW_KEY_INSERT: return ImGuiKey_Insert; + case GLFW_KEY_DELETE: return ImGuiKey_Delete; + case GLFW_KEY_BACKSPACE: return ImGuiKey_Backspace; + case GLFW_KEY_SPACE: return ImGuiKey_Space; + case GLFW_KEY_ENTER: return ImGuiKey_Enter; + case GLFW_KEY_ESCAPE: return ImGuiKey_Escape; + case GLFW_KEY_APOSTROPHE: return ImGuiKey_Apostrophe; + case GLFW_KEY_COMMA: return ImGuiKey_Comma; + case GLFW_KEY_MINUS: return ImGuiKey_Minus; + case GLFW_KEY_PERIOD: return ImGuiKey_Period; + case GLFW_KEY_SLASH: return ImGuiKey_Slash; + case GLFW_KEY_SEMICOLON: return ImGuiKey_Semicolon; + case GLFW_KEY_EQUAL: return ImGuiKey_Equal; + case GLFW_KEY_LEFT_BRACKET: return ImGuiKey_LeftBracket; + case GLFW_KEY_BACKSLASH: return ImGuiKey_Backslash; + case GLFW_KEY_RIGHT_BRACKET: return ImGuiKey_RightBracket; + case GLFW_KEY_GRAVE_ACCENT: return ImGuiKey_GraveAccent; + case GLFW_KEY_CAPS_LOCK: return ImGuiKey_CapsLock; + case GLFW_KEY_SCROLL_LOCK: return ImGuiKey_ScrollLock; + case GLFW_KEY_NUM_LOCK: return ImGuiKey_NumLock; + case GLFW_KEY_PRINT_SCREEN: return ImGuiKey_PrintScreen; + case GLFW_KEY_PAUSE: return ImGuiKey_Pause; + case GLFW_KEY_KP_0: return ImGuiKey_Keypad0; + case GLFW_KEY_KP_1: return ImGuiKey_Keypad1; + case GLFW_KEY_KP_2: return ImGuiKey_Keypad2; + case GLFW_KEY_KP_3: return ImGuiKey_Keypad3; + case GLFW_KEY_KP_4: return ImGuiKey_Keypad4; + case GLFW_KEY_KP_5: return ImGuiKey_Keypad5; + case GLFW_KEY_KP_6: return ImGuiKey_Keypad6; + case GLFW_KEY_KP_7: return ImGuiKey_Keypad7; + case GLFW_KEY_KP_8: return ImGuiKey_Keypad8; + case GLFW_KEY_KP_9: return ImGuiKey_Keypad9; + case GLFW_KEY_KP_DECIMAL: return ImGuiKey_KeypadDecimal; + case GLFW_KEY_KP_DIVIDE: return ImGuiKey_KeypadDivide; + case GLFW_KEY_KP_MULTIPLY: return ImGuiKey_KeypadMultiply; + case GLFW_KEY_KP_SUBTRACT: return ImGuiKey_KeypadSubtract; + case GLFW_KEY_KP_ADD: return ImGuiKey_KeypadAdd; + case GLFW_KEY_KP_ENTER: return ImGuiKey_KeypadEnter; + case GLFW_KEY_KP_EQUAL: return ImGuiKey_KeypadEqual; + case GLFW_KEY_LEFT_SHIFT: return ImGuiKey_LeftShift; + case GLFW_KEY_LEFT_CONTROL: return ImGuiKey_LeftCtrl; + case GLFW_KEY_LEFT_ALT: return ImGuiKey_LeftAlt; + case GLFW_KEY_LEFT_SUPER: return ImGuiKey_LeftSuper; + case GLFW_KEY_RIGHT_SHIFT: return ImGuiKey_RightShift; + case GLFW_KEY_RIGHT_CONTROL: return ImGuiKey_RightCtrl; + case GLFW_KEY_RIGHT_ALT: return ImGuiKey_RightAlt; + case GLFW_KEY_RIGHT_SUPER: return ImGuiKey_RightSuper; + case GLFW_KEY_MENU: return ImGuiKey_Menu; + case GLFW_KEY_0: return ImGuiKey_0; + case GLFW_KEY_1: return ImGuiKey_1; + case GLFW_KEY_2: return ImGuiKey_2; + case GLFW_KEY_3: return ImGuiKey_3; + case GLFW_KEY_4: return ImGuiKey_4; + case GLFW_KEY_5: return ImGuiKey_5; + case GLFW_KEY_6: return ImGuiKey_6; + case GLFW_KEY_7: return ImGuiKey_7; + case GLFW_KEY_8: return ImGuiKey_8; + case GLFW_KEY_9: return ImGuiKey_9; + case GLFW_KEY_A: return ImGuiKey_A; + case GLFW_KEY_B: return ImGuiKey_B; + case GLFW_KEY_C: return ImGuiKey_C; + case GLFW_KEY_D: return ImGuiKey_D; + case GLFW_KEY_E: return ImGuiKey_E; + case GLFW_KEY_F: return ImGuiKey_F; + case GLFW_KEY_G: return ImGuiKey_G; + case GLFW_KEY_H: return ImGuiKey_H; + case GLFW_KEY_I: return ImGuiKey_I; + case GLFW_KEY_J: return ImGuiKey_J; + case GLFW_KEY_K: return ImGuiKey_K; + case GLFW_KEY_L: return ImGuiKey_L; + case GLFW_KEY_M: return ImGuiKey_M; + case GLFW_KEY_N: return ImGuiKey_N; + case GLFW_KEY_O: return ImGuiKey_O; + case GLFW_KEY_P: return ImGuiKey_P; + case GLFW_KEY_Q: return ImGuiKey_Q; + case GLFW_KEY_R: return ImGuiKey_R; + case GLFW_KEY_S: return ImGuiKey_S; + case GLFW_KEY_T: return ImGuiKey_T; + case GLFW_KEY_U: return ImGuiKey_U; + case GLFW_KEY_V: return ImGuiKey_V; + case GLFW_KEY_W: return ImGuiKey_W; + case GLFW_KEY_X: return ImGuiKey_X; + case GLFW_KEY_Y: return ImGuiKey_Y; + case GLFW_KEY_Z: return ImGuiKey_Z; + case GLFW_KEY_F1: return ImGuiKey_F1; + case GLFW_KEY_F2: return ImGuiKey_F2; + case GLFW_KEY_F3: return ImGuiKey_F3; + case GLFW_KEY_F4: return ImGuiKey_F4; + case GLFW_KEY_F5: return ImGuiKey_F5; + case GLFW_KEY_F6: return ImGuiKey_F6; + case GLFW_KEY_F7: return ImGuiKey_F7; + case GLFW_KEY_F8: return ImGuiKey_F8; + case GLFW_KEY_F9: return ImGuiKey_F9; + case GLFW_KEY_F10: return ImGuiKey_F10; + case GLFW_KEY_F11: return ImGuiKey_F11; + case GLFW_KEY_F12: return ImGuiKey_F12; + default: return ImGuiKey_None; + } +} + +static int ImGui_ImplGlfw_KeyToModifier(int key) +{ + if (key == GLFW_KEY_LEFT_CONTROL || key == GLFW_KEY_RIGHT_CONTROL) + return GLFW_MOD_CONTROL; + if (key == GLFW_KEY_LEFT_SHIFT || key == GLFW_KEY_RIGHT_SHIFT) + return GLFW_MOD_SHIFT; + if (key == GLFW_KEY_LEFT_ALT || key == GLFW_KEY_RIGHT_ALT) + return GLFW_MOD_ALT; + if (key == GLFW_KEY_LEFT_SUPER || key == GLFW_KEY_RIGHT_SUPER) + return GLFW_MOD_SUPER; + return 0; +} + +static void ImGui_ImplGlfw_UpdateKeyModifiers(int mods) +{ + ImGuiIO& io = ImGui::GetIO(); + io.AddKeyEvent(ImGuiKey_ModCtrl, (mods & GLFW_MOD_CONTROL) != 0); + io.AddKeyEvent(ImGuiKey_ModShift, (mods & GLFW_MOD_SHIFT) != 0); + io.AddKeyEvent(ImGuiKey_ModAlt, (mods & GLFW_MOD_ALT) != 0); + io.AddKeyEvent(ImGuiKey_ModSuper, (mods & GLFW_MOD_SUPER) != 0); +} + +void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + if (bd->PrevUserCallbackMousebutton != NULL && window == bd->Window) + bd->PrevUserCallbackMousebutton(window, button, action, mods); + + ImGui_ImplGlfw_UpdateKeyModifiers(mods); + + ImGuiIO& io = ImGui::GetIO(); + if (button >= 0 && button < ImGuiMouseButton_COUNT) + io.AddMouseButtonEvent(button, action == GLFW_PRESS); +} + +void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + if (bd->PrevUserCallbackScroll != NULL && window == bd->Window) + bd->PrevUserCallbackScroll(window, xoffset, yoffset); + + ImGuiIO& io = ImGui::GetIO(); + io.AddMouseWheelEvent((float)xoffset, (float)yoffset); +} + +static int ImGui_ImplGlfw_TranslateUntranslatedKey(int key, int scancode) +{ +#if GLFW_HAS_GET_KEY_NAME && !defined(__EMSCRIPTEN__) + // GLFW 3.1+ attempts to "untranslate" keys, which goes the opposite of what every other framework does, making using lettered shortcuts difficult. + // (It had reasons to do so: namely GLFW is/was more likely to be used for WASD-type game controls rather than lettered shortcuts, but IHMO the 3.1 change could have been done differently) + // See https://github.com/glfw/glfw/issues/1502 for details. + // Adding a workaround to undo this (so our keys are translated->untranslated->translated, likely a lossy process). + // This won't cover edge cases but this is at least going to cover common cases. + if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_EQUAL) + return key; + const char* key_name = glfwGetKeyName(key, scancode); + if (key_name && key_name[0] != 0 && key_name[1] == 0) + { + const char char_names[] = "`-=[]\\,;\'./"; + const int char_keys[] = { GLFW_KEY_GRAVE_ACCENT, GLFW_KEY_MINUS, GLFW_KEY_EQUAL, GLFW_KEY_LEFT_BRACKET, GLFW_KEY_RIGHT_BRACKET, GLFW_KEY_BACKSLASH, GLFW_KEY_COMMA, GLFW_KEY_SEMICOLON, GLFW_KEY_APOSTROPHE, GLFW_KEY_PERIOD, GLFW_KEY_SLASH, 0 }; + IM_ASSERT(IM_ARRAYSIZE(char_names) == IM_ARRAYSIZE(char_keys)); + if (key_name[0] >= '0' && key_name[0] <= '9') { key = GLFW_KEY_0 + (key_name[0] - '0'); } + else if (key_name[0] >= 'A' && key_name[0] <= 'Z') { key = GLFW_KEY_A + (key_name[0] - 'A'); } + else if (key_name[0] >= 'a' && key_name[0] <= 'z') { key = GLFW_KEY_A + (key_name[0] - 'a'); } + else if (const char* p = strchr(char_names, key_name[0])) { key = char_keys[p - char_names]; } + } + // if (action == GLFW_PRESS) printf("key %d scancode %d name '%s'\n", key, scancode, key_name); +#else + IM_UNUSED(scancode); +#endif + return key; +} + +void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, int action, int mods) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + if (bd->PrevUserCallbackKey != NULL && window == bd->Window) + bd->PrevUserCallbackKey(window, keycode, scancode, action, mods); + + if (action != GLFW_PRESS && action != GLFW_RELEASE) + return; + + // Workaround: X11 does not include current pressed/released modifier key in 'mods' flags. https://github.com/glfw/glfw/issues/1630 + if (int keycode_to_mod = ImGui_ImplGlfw_KeyToModifier(keycode)) + mods = (action == GLFW_PRESS) ? (mods | keycode_to_mod) : (mods & ~keycode_to_mod); + ImGui_ImplGlfw_UpdateKeyModifiers(mods); + + if (keycode >= 0 && keycode < IM_ARRAYSIZE(bd->KeyOwnerWindows)) + bd->KeyOwnerWindows[keycode] = (action == GLFW_PRESS) ? window : NULL; + + keycode = ImGui_ImplGlfw_TranslateUntranslatedKey(keycode, scancode); + + ImGuiIO& io = ImGui::GetIO(); + ImGuiKey imgui_key = ImGui_ImplGlfw_KeyToImGuiKey(keycode); + io.AddKeyEvent(imgui_key, (action == GLFW_PRESS)); + io.SetKeyEventNativeData(imgui_key, keycode, scancode); // To support legacy indexing (<1.87 user code) +} + +void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + if (bd->PrevUserCallbackWindowFocus != NULL && window == bd->Window) + bd->PrevUserCallbackWindowFocus(window, focused); + + ImGuiIO& io = ImGui::GetIO(); + io.AddFocusEvent(focused != 0); +} + +void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + if (bd->PrevUserCallbackCursorPos != NULL && window == bd->Window) + bd->PrevUserCallbackCursorPos(window, x, y); + if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) + return; + + ImGuiIO& io = ImGui::GetIO(); + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + int window_x, window_y; + glfwGetWindowPos(window, &window_x, &window_y); + x += window_x; + y += window_y; + } + io.AddMousePosEvent((float)x, (float)y); + bd->LastValidMousePos = ImVec2((float)x, (float)y); +} + +// Workaround: X11 seems to send spurious Leave/Enter events which would make us lose our position, +// so we back it up and restore on Leave/Enter (see https://github.com/ocornut/imgui/issues/4984) +void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + if (bd->PrevUserCallbackCursorEnter != NULL && window == bd->Window) + bd->PrevUserCallbackCursorEnter(window, entered); + if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) + return; + + ImGuiIO& io = ImGui::GetIO(); + if (entered) + { + bd->MouseWindow = window; + io.AddMousePosEvent(bd->LastValidMousePos.x, bd->LastValidMousePos.y); + } + else if (!entered && bd->MouseWindow == window) + { + bd->LastValidMousePos = io.MousePos; + bd->MouseWindow = NULL; + io.AddMousePosEvent(-FLT_MAX, -FLT_MAX); + } +} + +void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + if (bd->PrevUserCallbackChar != NULL && window == bd->Window) + bd->PrevUserCallbackChar(window, c); + + ImGuiIO& io = ImGui::GetIO(); + io.AddInputCharacter(c); +} + +void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + bd->WantUpdateMonitors = true; +} + +void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + IM_ASSERT(bd->InstalledCallbacks == false && "Callbacks already installed!"); + IM_ASSERT(bd->Window == window); + + bd->PrevUserCallbackWindowFocus = glfwSetWindowFocusCallback(window, ImGui_ImplGlfw_WindowFocusCallback); + bd->PrevUserCallbackCursorEnter = glfwSetCursorEnterCallback(window, ImGui_ImplGlfw_CursorEnterCallback); + bd->PrevUserCallbackCursorPos = glfwSetCursorPosCallback(window, ImGui_ImplGlfw_CursorPosCallback); + bd->PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback); + bd->PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback); + bd->PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback); + bd->PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback); + bd->PrevUserCallbackMonitor = glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback); + bd->InstalledCallbacks = true; +} + +void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + IM_ASSERT(bd->InstalledCallbacks == true && "Callbacks not installed!"); + IM_ASSERT(bd->Window == window); + + glfwSetWindowFocusCallback(window, bd->PrevUserCallbackWindowFocus); + glfwSetCursorEnterCallback(window, bd->PrevUserCallbackCursorEnter); + glfwSetCursorPosCallback(window, bd->PrevUserCallbackCursorPos); + glfwSetMouseButtonCallback(window, bd->PrevUserCallbackMousebutton); + glfwSetScrollCallback(window, bd->PrevUserCallbackScroll); + glfwSetKeyCallback(window, bd->PrevUserCallbackKey); + glfwSetCharCallback(window, bd->PrevUserCallbackChar); + glfwSetMonitorCallback(bd->PrevUserCallbackMonitor); + bd->InstalledCallbacks = false; + bd->PrevUserCallbackWindowFocus = NULL; + bd->PrevUserCallbackCursorEnter = NULL; + bd->PrevUserCallbackCursorPos = NULL; + bd->PrevUserCallbackMousebutton = NULL; + bd->PrevUserCallbackScroll = NULL; + bd->PrevUserCallbackKey = NULL; + bd->PrevUserCallbackChar = NULL; + bd->PrevUserCallbackMonitor = NULL; +} + +static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api) +{ + ImGuiIO& io = ImGui::GetIO(); + IM_ASSERT(io.BackendPlatformUserData == NULL && "Already initialized a platform backend!"); + + // Setup backend capabilities flags + ImGui_ImplGlfw_Data* bd = IM_NEW(ImGui_ImplGlfw_Data)(); + io.BackendPlatformUserData = (void*)bd; + io.BackendPlatformName = "imgui_impl_glfw"; + io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) + io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) + io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional) +#if GLFW_HAS_MOUSE_PASSTHROUGH || (GLFW_HAS_WINDOW_HOVERED && defined(_WIN32)) + io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional) +#endif + + bd->Window = window; + bd->Time = 0.0; + bd->WantUpdateMonitors = true; + + io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText; + io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText; + io.ClipboardUserData = bd->Window; + + // Create mouse cursors + // (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist, + // GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting. + // Missing cursors will return NULL and our _UpdateMouseCursor() function will use the Arrow cursor instead.) + GLFWerrorfun prev_error_callback = glfwSetErrorCallback(NULL); + bd->MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); + bd->MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR); + bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR); + bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR); + bd->MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR); +#if GLFW_HAS_NEW_CURSORS + bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR); + bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR); + bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR); + bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR); +#else + bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); + bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); + bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); + bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); +#endif + glfwSetErrorCallback(prev_error_callback); + + // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. + if (install_callbacks) + ImGui_ImplGlfw_InstallCallbacks(window); + + // Update monitors the first time (note: monitor callback are broken in GLFW 3.2 and earlier, see github.com/glfw/glfw/issues/784) + ImGui_ImplGlfw_UpdateMonitors(); + glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback); + + // Our mouse update function expect PlatformHandle to be filled for the main viewport + ImGuiViewport* main_viewport = ImGui::GetMainViewport(); + main_viewport->PlatformHandle = (void*)bd->Window; +#ifdef _WIN32 + main_viewport->PlatformHandleRaw = glfwGetWin32Window(bd->Window); +#elif defined(__APPLE__) + main_viewport->PlatformHandleRaw = (void*)glfwGetCocoaWindow(bd->Window); +#endif + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + ImGui_ImplGlfw_InitPlatformInterface(); + + bd->ClientApi = client_api; + return true; +} + +bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks) +{ + return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL); +} + +bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks) +{ + return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan); +} + +bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks) +{ + return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Unknown); +} + +void ImGui_ImplGlfw_Shutdown() +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + IM_ASSERT(bd != NULL && "No platform backend to shutdown, or already shutdown?"); + ImGuiIO& io = ImGui::GetIO(); + + ImGui_ImplGlfw_ShutdownPlatformInterface(); + + if (bd->InstalledCallbacks) + ImGui_ImplGlfw_RestoreCallbacks(bd->Window); + + for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++) + glfwDestroyCursor(bd->MouseCursors[cursor_n]); + + io.BackendPlatformName = NULL; + io.BackendPlatformUserData = NULL; + IM_DELETE(bd); +} + +static void ImGui_ImplGlfw_UpdateMouseData() +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + + if (glfwGetInputMode(bd->Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) + { + io.AddMousePosEvent(-FLT_MAX, -FLT_MAX); + return; + } + + ImGuiID mouse_viewport_id = 0; + const ImVec2 mouse_pos_prev = io.MousePos; + for (int n = 0; n < platform_io.Viewports.Size; n++) + { + ImGuiViewport* viewport = platform_io.Viewports[n]; + GLFWwindow* window = (GLFWwindow*)viewport->PlatformHandle; + +#ifdef __EMSCRIPTEN__ + const bool is_window_focused = true; +#else + const bool is_window_focused = glfwGetWindowAttrib(window, GLFW_FOCUSED) != 0; +#endif + if (is_window_focused) + { + // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) + // When multi-viewports are enabled, all Dear ImGui positions are same as OS positions. + if (io.WantSetMousePos) + glfwSetCursorPos(window, (double)(mouse_pos_prev.x - viewport->Pos.x), (double)(mouse_pos_prev.y - viewport->Pos.y)); + + // (Optional) Fallback to provide mouse position when focused (ImGui_ImplGlfw_CursorPosCallback already provides this when hovered or captured) + if (bd->MouseWindow == NULL) + { + double mouse_x, mouse_y; + glfwGetCursorPos(window, &mouse_x, &mouse_y); + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + // Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) + // Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor) + int window_x, window_y; + glfwGetWindowPos(window, &window_x, &window_y); + mouse_x += window_x; + mouse_y += window_y; + } + bd->LastValidMousePos = ImVec2((float)mouse_x, (float)mouse_y); + io.AddMousePosEvent((float)mouse_x, (float)mouse_y); + } + } + + // (Optional) When using multiple viewports: call io.AddMouseViewportEvent() with the viewport the OS mouse cursor is hovering. + // If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, Dear imGui will ignore this field and infer the information using its flawed heuristic. + // - [X] GLFW >= 3.3 backend ON WINDOWS ONLY does correctly ignore viewports with the _NoInputs flag. + // - [!] GLFW <= 3.2 backend CANNOT correctly ignore viewports with the _NoInputs flag, and CANNOT reported Hovered Viewport because of mouse capture. + // Some backend are not able to handle that correctly. If a backend report an hovered viewport that has the _NoInputs flag (e.g. when dragging a window + // for docking, the viewport has the _NoInputs flag in order to allow us to find the viewport under), then Dear ImGui is forced to ignore the value reported + // by the backend, and use its flawed heuristic to guess the viewport behind. + // - [X] GLFW backend correctly reports this regardless of another viewport behind focused and dragged from (we need this to find a useful drag and drop target). + // FIXME: This is currently only correct on Win32. See what we do below with the WM_NCHITTEST, missing an equivalent for other systems. + // See https://github.com/glfw/glfw/issues/1236 if you want to help in making this a GLFW feature. +#if GLFW_HAS_MOUSE_PASSTHROUGH || (GLFW_HAS_WINDOW_HOVERED && defined(_WIN32)) + const bool window_no_input = (viewport->Flags & ImGuiViewportFlags_NoInputs) != 0; +#if GLFW_HAS_MOUSE_PASSTHROUGH + glfwSetWindowAttrib(window, GLFW_MOUSE_PASSTHROUGH, window_no_input); +#endif + if (glfwGetWindowAttrib(window, GLFW_HOVERED) && !window_no_input) + mouse_viewport_id = viewport->ID; +#else + // We cannot use bd->MouseWindow maintained from CursorEnter/Leave callbacks, because it is locked to the window capturing mouse. +#endif + } + + if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport) + io.AddMouseViewportEvent(mouse_viewport_id); +} + +static void ImGui_ImplGlfw_UpdateMouseCursor() +{ + ImGuiIO& io = ImGui::GetIO(); + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(bd->Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) + return; + + ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + for (int n = 0; n < platform_io.Viewports.Size; n++) + { + GLFWwindow* window = (GLFWwindow*)platform_io.Viewports[n]->PlatformHandle; + if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor) + { + // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); + } + else + { + // Show OS mouse cursor + // FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here. + glfwSetCursor(window, bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]); + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + } + } +} + +// Update gamepad inputs +static inline float Saturate(float v) { return v < 0.0f ? 0.0f : v > 1.0f ? 1.0f : v; } +static void ImGui_ImplGlfw_UpdateGamepads() +{ + ImGuiIO& io = ImGui::GetIO(); + if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. + return; + + io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; +#if GLFW_HAS_GAMEPAD_API + GLFWgamepadstate gamepad; + if (!glfwGetGamepadState(GLFW_JOYSTICK_1, &gamepad)) + return; + #define MAP_BUTTON(KEY_NO, BUTTON_NO, _UNUSED) do { io.AddKeyEvent(KEY_NO, gamepad.buttons[BUTTON_NO] != 0); } while (0) + #define MAP_ANALOG(KEY_NO, AXIS_NO, _UNUSED, V0, V1) do { float v = gamepad.axes[AXIS_NO]; v = (v - V0) / (V1 - V0); io.AddKeyAnalogEvent(KEY_NO, v > 0.10f, Saturate(v)); } while (0) +#else + int axes_count = 0, buttons_count = 0; + const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count); + const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count); + if (axes_count == 0 || buttons_count == 0) + return; + #define MAP_BUTTON(KEY_NO, _UNUSED, BUTTON_NO) do { io.AddKeyEvent(KEY_NO, (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS)); } while (0) + #define MAP_ANALOG(KEY_NO, _UNUSED, AXIS_NO, V0, V1) do { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); io.AddKeyAnalogEvent(KEY_NO, v > 0.10f, Saturate(v)); } while (0) +#endif + io.BackendFlags |= ImGuiBackendFlags_HasGamepad; + MAP_BUTTON(ImGuiKey_GamepadStart, GLFW_GAMEPAD_BUTTON_START, 7); + MAP_BUTTON(ImGuiKey_GamepadBack, GLFW_GAMEPAD_BUTTON_BACK, 6); + MAP_BUTTON(ImGuiKey_GamepadFaceLeft, GLFW_GAMEPAD_BUTTON_X, 2); // Xbox X, PS Square + MAP_BUTTON(ImGuiKey_GamepadFaceRight, GLFW_GAMEPAD_BUTTON_B, 1); // Xbox B, PS Circle + MAP_BUTTON(ImGuiKey_GamepadFaceUp, GLFW_GAMEPAD_BUTTON_Y, 3); // Xbox Y, PS Triangle + MAP_BUTTON(ImGuiKey_GamepadFaceDown, GLFW_GAMEPAD_BUTTON_A, 0); // Xbox A, PS Cross + MAP_BUTTON(ImGuiKey_GamepadDpadLeft, GLFW_GAMEPAD_BUTTON_DPAD_LEFT, 13); + MAP_BUTTON(ImGuiKey_GamepadDpadRight, GLFW_GAMEPAD_BUTTON_DPAD_RIGHT, 11); + MAP_BUTTON(ImGuiKey_GamepadDpadUp, GLFW_GAMEPAD_BUTTON_DPAD_UP, 10); + MAP_BUTTON(ImGuiKey_GamepadDpadDown, GLFW_GAMEPAD_BUTTON_DPAD_DOWN, 12); + MAP_BUTTON(ImGuiKey_GamepadL1, GLFW_GAMEPAD_BUTTON_LEFT_BUMPER, 4); + MAP_BUTTON(ImGuiKey_GamepadR1, GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER, 5); + MAP_ANALOG(ImGuiKey_GamepadL2, GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, 4, -0.75f, +1.0f); + MAP_ANALOG(ImGuiKey_GamepadR2, GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, 5, -0.75f, +1.0f); + MAP_BUTTON(ImGuiKey_GamepadL3, GLFW_GAMEPAD_BUTTON_LEFT_THUMB, 8); + MAP_BUTTON(ImGuiKey_GamepadR3, GLFW_GAMEPAD_BUTTON_RIGHT_THUMB, 9); + MAP_ANALOG(ImGuiKey_GamepadLStickLeft, GLFW_GAMEPAD_AXIS_LEFT_X, 0, -0.25f, -1.0f); + MAP_ANALOG(ImGuiKey_GamepadLStickRight, GLFW_GAMEPAD_AXIS_LEFT_X, 0, +0.25f, +1.0f); + MAP_ANALOG(ImGuiKey_GamepadLStickUp, GLFW_GAMEPAD_AXIS_LEFT_Y, 1, -0.25f, -1.0f); + MAP_ANALOG(ImGuiKey_GamepadLStickDown, GLFW_GAMEPAD_AXIS_LEFT_Y, 1, +0.25f, +1.0f); + MAP_ANALOG(ImGuiKey_GamepadRStickLeft, GLFW_GAMEPAD_AXIS_RIGHT_X, 2, -0.25f, -1.0f); + MAP_ANALOG(ImGuiKey_GamepadRStickRight, GLFW_GAMEPAD_AXIS_RIGHT_X, 2, +0.25f, +1.0f); + MAP_ANALOG(ImGuiKey_GamepadRStickUp, GLFW_GAMEPAD_AXIS_RIGHT_Y, 3, -0.25f, -1.0f); + MAP_ANALOG(ImGuiKey_GamepadRStickDown, GLFW_GAMEPAD_AXIS_RIGHT_Y, 3, +0.25f, +1.0f); + #undef MAP_BUTTON + #undef MAP_ANALOG +} + +static void ImGui_ImplGlfw_UpdateMonitors() +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + int monitors_count = 0; + GLFWmonitor** glfw_monitors = glfwGetMonitors(&monitors_count); + platform_io.Monitors.resize(0); + for (int n = 0; n < monitors_count; n++) + { + ImGuiPlatformMonitor monitor; + int x, y; + glfwGetMonitorPos(glfw_monitors[n], &x, &y); + const GLFWvidmode* vid_mode = glfwGetVideoMode(glfw_monitors[n]); + monitor.MainPos = monitor.WorkPos = ImVec2((float)x, (float)y); + monitor.MainSize = monitor.WorkSize = ImVec2((float)vid_mode->width, (float)vid_mode->height); +#if GLFW_HAS_MONITOR_WORK_AREA + int w, h; + glfwGetMonitorWorkarea(glfw_monitors[n], &x, &y, &w, &h); + if (w > 0 && h > 0) // Workaround a small GLFW issue reporting zero on monitor changes: https://github.com/glfw/glfw/pull/1761 + { + monitor.WorkPos = ImVec2((float)x, (float)y); + monitor.WorkSize = ImVec2((float)w, (float)h); + } +#endif +#if GLFW_HAS_PER_MONITOR_DPI + // Warning: the validity of monitor DPI information on Windows depends on the application DPI awareness settings, which generally needs to be set in the manifest or at runtime. + float x_scale, y_scale; + glfwGetMonitorContentScale(glfw_monitors[n], &x_scale, &y_scale); + monitor.DpiScale = x_scale; +#endif + platform_io.Monitors.push_back(monitor); + } + bd->WantUpdateMonitors = false; +} + +void ImGui_ImplGlfw_NewFrame() +{ + ImGuiIO& io = ImGui::GetIO(); + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + IM_ASSERT(bd != NULL && "Did you call ImGui_ImplGlfw_InitForXXX()?"); + + // Setup display size (every frame to accommodate for window resizing) + int w, h; + int display_w, display_h; + glfwGetWindowSize(bd->Window, &w, &h); + glfwGetFramebufferSize(bd->Window, &display_w, &display_h); + io.DisplaySize = ImVec2((float)w, (float)h); + if (w > 0 && h > 0) + io.DisplayFramebufferScale = ImVec2((float)display_w / (float)w, (float)display_h / (float)h); + if (bd->WantUpdateMonitors) + ImGui_ImplGlfw_UpdateMonitors(); + + // Setup time step + double current_time = glfwGetTime(); + io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f); + bd->Time = current_time; + + ImGui_ImplGlfw_UpdateMouseData(); + ImGui_ImplGlfw_UpdateMouseCursor(); + + // Update game controllers (if enabled and available) + ImGui_ImplGlfw_UpdateGamepads(); +} + +//-------------------------------------------------------------------------------------------------------- +// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT +// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously. +// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first.. +//-------------------------------------------------------------------------------------------------------- + +// Helper structure we store in the void* RenderUserData field of each ImGuiViewport to easily retrieve our backend data. +struct ImGui_ImplGlfw_ViewportData +{ + GLFWwindow* Window; + bool WindowOwned; + int IgnoreWindowPosEventFrame; + int IgnoreWindowSizeEventFrame; + + ImGui_ImplGlfw_ViewportData() { Window = NULL; WindowOwned = false; IgnoreWindowSizeEventFrame = IgnoreWindowPosEventFrame = -1; } + ~ImGui_ImplGlfw_ViewportData() { IM_ASSERT(Window == NULL); } +}; + +static void ImGui_ImplGlfw_WindowCloseCallback(GLFWwindow* window) +{ + if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window)) + viewport->PlatformRequestClose = true; +} + +// GLFW may dispatch window pos/size events after calling glfwSetWindowPos()/glfwSetWindowSize(). +// However: depending on the platform the callback may be invoked at different time: +// - on Windows it appears to be called within the glfwSetWindowPos()/glfwSetWindowSize() call +// - on Linux it is queued and invoked during glfwPollEvents() +// Because the event doesn't always fire on glfwSetWindowXXX() we use a frame counter tag to only +// ignore recent glfwSetWindowXXX() calls. +static void ImGui_ImplGlfw_WindowPosCallback(GLFWwindow* window, int, int) +{ + if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window)) + { + if (ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData) + { + bool ignore_event = (ImGui::GetFrameCount() <= vd->IgnoreWindowPosEventFrame + 1); + //data->IgnoreWindowPosEventFrame = -1; + if (ignore_event) + return; + } + viewport->PlatformRequestMove = true; + } +} + +static void ImGui_ImplGlfw_WindowSizeCallback(GLFWwindow* window, int, int) +{ + if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window)) + { + if (ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData) + { + bool ignore_event = (ImGui::GetFrameCount() <= vd->IgnoreWindowSizeEventFrame + 1); + //data->IgnoreWindowSizeEventFrame = -1; + if (ignore_event) + return; + } + viewport->PlatformRequestResize = true; + } +} + +static void ImGui_ImplGlfw_CreateWindow(ImGuiViewport* viewport) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + ImGui_ImplGlfw_ViewportData* vd = IM_NEW(ImGui_ImplGlfw_ViewportData)(); + viewport->PlatformUserData = vd; + + // GLFW 3.2 unfortunately always set focus on glfwCreateWindow() if GLFW_VISIBLE is set, regardless of GLFW_FOCUSED + // With GLFW 3.3, the hint GLFW_FOCUS_ON_SHOW fixes this problem + glfwWindowHint(GLFW_VISIBLE, false); + glfwWindowHint(GLFW_FOCUSED, false); +#if GLFW_HAS_FOCUS_ON_SHOW + glfwWindowHint(GLFW_FOCUS_ON_SHOW, false); + #endif + glfwWindowHint(GLFW_DECORATED, (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? false : true); +#if GLFW_HAS_WINDOW_TOPMOST + glfwWindowHint(GLFW_FLOATING, (viewport->Flags & ImGuiViewportFlags_TopMost) ? true : false); +#endif + GLFWwindow* share_window = (bd->ClientApi == GlfwClientApi_OpenGL) ? bd->Window : NULL; + vd->Window = glfwCreateWindow((int)viewport->Size.x, (int)viewport->Size.y, "No Title Yet", NULL, share_window); + vd->WindowOwned = true; + viewport->PlatformHandle = (void*)vd->Window; +#ifdef _WIN32 + viewport->PlatformHandleRaw = glfwGetWin32Window(vd->Window); +#elif defined(__APPLE__) + viewport->PlatformHandleRaw = (void*)glfwGetCocoaWindow(vd->Window); +#endif + glfwSetWindowPos(vd->Window, (int)viewport->Pos.x, (int)viewport->Pos.y); + + // Install GLFW callbacks for secondary viewports + glfwSetWindowFocusCallback(vd->Window, ImGui_ImplGlfw_WindowFocusCallback); + glfwSetCursorEnterCallback(vd->Window, ImGui_ImplGlfw_CursorEnterCallback); + glfwSetCursorPosCallback(vd->Window, ImGui_ImplGlfw_CursorPosCallback); + glfwSetMouseButtonCallback(vd->Window, ImGui_ImplGlfw_MouseButtonCallback); + glfwSetScrollCallback(vd->Window, ImGui_ImplGlfw_ScrollCallback); + glfwSetKeyCallback(vd->Window, ImGui_ImplGlfw_KeyCallback); + glfwSetCharCallback(vd->Window, ImGui_ImplGlfw_CharCallback); + glfwSetWindowCloseCallback(vd->Window, ImGui_ImplGlfw_WindowCloseCallback); + glfwSetWindowPosCallback(vd->Window, ImGui_ImplGlfw_WindowPosCallback); + glfwSetWindowSizeCallback(vd->Window, ImGui_ImplGlfw_WindowSizeCallback); + if (bd->ClientApi == GlfwClientApi_OpenGL) + { + glfwMakeContextCurrent(vd->Window); + glfwSwapInterval(0); + } +} + +static void ImGui_ImplGlfw_DestroyWindow(ImGuiViewport* viewport) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + if (ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData) + { + if (vd->WindowOwned) + { +#if !GLFW_HAS_MOUSE_PASSTHROUGH && GLFW_HAS_WINDOW_HOVERED && defined(_WIN32) + HWND hwnd = (HWND)viewport->PlatformHandleRaw; + ::RemovePropA(hwnd, "IMGUI_VIEWPORT"); +#endif + + // Release any keys that were pressed in the window being destroyed and are still held down, + // because we will not receive any release events after window is destroyed. + for (int i = 0; i < IM_ARRAYSIZE(bd->KeyOwnerWindows); i++) + if (bd->KeyOwnerWindows[i] == vd->Window) + ImGui_ImplGlfw_KeyCallback(vd->Window, i, 0, GLFW_RELEASE, 0); // Later params are only used for main viewport, on which this function is never called. + + glfwDestroyWindow(vd->Window); + } + vd->Window = NULL; + IM_DELETE(vd); + } + viewport->PlatformUserData = viewport->PlatformHandle = NULL; +} + +// We have submitted https://github.com/glfw/glfw/pull/1568 to allow GLFW to support "transparent inputs". +// In the meanwhile we implement custom per-platform workarounds here (FIXME-VIEWPORT: Implement same work-around for Linux/OSX!) +#if !GLFW_HAS_MOUSE_PASSTHROUGH && GLFW_HAS_WINDOW_HOVERED && defined(_WIN32) +static LRESULT CALLBACK WndProcNoInputs(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + if (msg == WM_NCHITTEST) + { + // Let mouse pass-through the window. This will allow the backend to call io.AddMouseViewportEvent() properly (which is OPTIONAL). + // The ImGuiViewportFlags_NoInputs flag is set while dragging a viewport, as want to detect the window behind the one we are dragging. + // If you cannot easily access those viewport flags from your windowing/event code: you may manually synchronize its state e.g. in + // your main loop after calling UpdatePlatformWindows(). Iterate all viewports/platform windows and pass the flag to your windowing system. + ImGuiViewport* viewport = (ImGuiViewport*)::GetPropA(hWnd, "IMGUI_VIEWPORT"); + if (viewport->Flags & ImGuiViewportFlags_NoInputs) + return HTTRANSPARENT; + } + return ::CallWindowProc(bd->GlfwWndProc, hWnd, msg, wParam, lParam); +} +#endif + +static void ImGui_ImplGlfw_ShowWindow(ImGuiViewport* viewport) +{ + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; + +#if defined(_WIN32) + // GLFW hack: Hide icon from task bar + HWND hwnd = (HWND)viewport->PlatformHandleRaw; + if (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon) + { + LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE); + ex_style &= ~WS_EX_APPWINDOW; + ex_style |= WS_EX_TOOLWINDOW; + ::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style); + } + + // GLFW hack: install hook for WM_NCHITTEST message handler +#if !GLFW_HAS_MOUSE_PASSTHROUGH && GLFW_HAS_WINDOW_HOVERED && defined(_WIN32) + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + ::SetPropA(hwnd, "IMGUI_VIEWPORT", viewport); + if (bd->GlfwWndProc == NULL) + bd->GlfwWndProc = (WNDPROC)::GetWindowLongPtr(hwnd, GWLP_WNDPROC); + ::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)WndProcNoInputs); +#endif + +#if !GLFW_HAS_FOCUS_ON_SHOW + // GLFW hack: GLFW 3.2 has a bug where glfwShowWindow() also activates/focus the window. + // The fix was pushed to GLFW repository on 2018/01/09 and should be included in GLFW 3.3 via a GLFW_FOCUS_ON_SHOW window attribute. + // See https://github.com/glfw/glfw/issues/1189 + // FIXME-VIEWPORT: Implement same work-around for Linux/OSX in the meanwhile. + if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing) + { + ::ShowWindow(hwnd, SW_SHOWNA); + return; + } +#endif +#endif + + glfwShowWindow(vd->Window); +} + +static ImVec2 ImGui_ImplGlfw_GetWindowPos(ImGuiViewport* viewport) +{ + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; + int x = 0, y = 0; + glfwGetWindowPos(vd->Window, &x, &y); + return ImVec2((float)x, (float)y); +} + +static void ImGui_ImplGlfw_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos) +{ + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; + vd->IgnoreWindowPosEventFrame = ImGui::GetFrameCount(); + glfwSetWindowPos(vd->Window, (int)pos.x, (int)pos.y); +} + +static ImVec2 ImGui_ImplGlfw_GetWindowSize(ImGuiViewport* viewport) +{ + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; + int w = 0, h = 0; + glfwGetWindowSize(vd->Window, &w, &h); + return ImVec2((float)w, (float)h); +} + +static void ImGui_ImplGlfw_SetWindowSize(ImGuiViewport* viewport, ImVec2 size) +{ + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; +#if __APPLE__ && !GLFW_HAS_OSX_WINDOW_POS_FIX + // Native OS windows are positioned from the bottom-left corner on macOS, whereas on other platforms they are + // positioned from the upper-left corner. GLFW makes an effort to convert macOS style coordinates, however it + // doesn't handle it when changing size. We are manually moving the window in order for changes of size to be based + // on the upper-left corner. + int x, y, width, height; + glfwGetWindowPos(vd->Window, &x, &y); + glfwGetWindowSize(vd->Window, &width, &height); + glfwSetWindowPos(vd->Window, x, y - height + size.y); +#endif + vd->IgnoreWindowSizeEventFrame = ImGui::GetFrameCount(); + glfwSetWindowSize(vd->Window, (int)size.x, (int)size.y); +} + +static void ImGui_ImplGlfw_SetWindowTitle(ImGuiViewport* viewport, const char* title) +{ + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; + glfwSetWindowTitle(vd->Window, title); +} + +static void ImGui_ImplGlfw_SetWindowFocus(ImGuiViewport* viewport) +{ +#if GLFW_HAS_FOCUS_WINDOW + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; + glfwFocusWindow(vd->Window); +#else + // FIXME: What are the effect of not having this function? At the moment imgui doesn't actually call SetWindowFocus - we set that up ahead, will answer that question later. + (void)viewport; +#endif +} + +static bool ImGui_ImplGlfw_GetWindowFocus(ImGuiViewport* viewport) +{ + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; + return glfwGetWindowAttrib(vd->Window, GLFW_FOCUSED) != 0; +} + +static bool ImGui_ImplGlfw_GetWindowMinimized(ImGuiViewport* viewport) +{ + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; + return glfwGetWindowAttrib(vd->Window, GLFW_ICONIFIED) != 0; +} + +#if GLFW_HAS_WINDOW_ALPHA +static void ImGui_ImplGlfw_SetWindowAlpha(ImGuiViewport* viewport, float alpha) +{ + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; + glfwSetWindowOpacity(vd->Window, alpha); +} +#endif + +static void ImGui_ImplGlfw_RenderWindow(ImGuiViewport* viewport, void*) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; + if (bd->ClientApi == GlfwClientApi_OpenGL) + glfwMakeContextCurrent(vd->Window); +} + +static void ImGui_ImplGlfw_SwapBuffers(ImGuiViewport* viewport, void*) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; + if (bd->ClientApi == GlfwClientApi_OpenGL) + { + glfwMakeContextCurrent(vd->Window); + glfwSwapBuffers(vd->Window); + } +} + +//-------------------------------------------------------------------------------------------------------- +// Vulkan support (the Vulkan renderer needs to call a platform-side support function to create the surface) +//-------------------------------------------------------------------------------------------------------- + +// Avoid including so we can build without it +#if GLFW_HAS_VULKAN +#ifndef VULKAN_H_ +#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; +#if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) +#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; +#else +#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; +#endif +VK_DEFINE_HANDLE(VkInstance) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) +struct VkAllocationCallbacks; +enum VkResult { VK_RESULT_MAX_ENUM = 0x7FFFFFFF }; +#endif // VULKAN_H_ +extern "C" { extern GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); } +static int ImGui_ImplGlfw_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_instance, const void* vk_allocator, ImU64* out_vk_surface) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; + IM_UNUSED(bd); + IM_ASSERT(bd->ClientApi == GlfwClientApi_Vulkan); + VkResult err = glfwCreateWindowSurface((VkInstance)vk_instance, vd->Window, (const VkAllocationCallbacks*)vk_allocator, (VkSurfaceKHR*)out_vk_surface); + return (int)err; +} +#endif // GLFW_HAS_VULKAN + +static void ImGui_ImplGlfw_InitPlatformInterface() +{ + // Register platform interface (will be coupled with a renderer interface) + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + platform_io.Platform_CreateWindow = ImGui_ImplGlfw_CreateWindow; + platform_io.Platform_DestroyWindow = ImGui_ImplGlfw_DestroyWindow; + platform_io.Platform_ShowWindow = ImGui_ImplGlfw_ShowWindow; + platform_io.Platform_SetWindowPos = ImGui_ImplGlfw_SetWindowPos; + platform_io.Platform_GetWindowPos = ImGui_ImplGlfw_GetWindowPos; + platform_io.Platform_SetWindowSize = ImGui_ImplGlfw_SetWindowSize; + platform_io.Platform_GetWindowSize = ImGui_ImplGlfw_GetWindowSize; + platform_io.Platform_SetWindowFocus = ImGui_ImplGlfw_SetWindowFocus; + platform_io.Platform_GetWindowFocus = ImGui_ImplGlfw_GetWindowFocus; + platform_io.Platform_GetWindowMinimized = ImGui_ImplGlfw_GetWindowMinimized; + platform_io.Platform_SetWindowTitle = ImGui_ImplGlfw_SetWindowTitle; + platform_io.Platform_RenderWindow = ImGui_ImplGlfw_RenderWindow; + platform_io.Platform_SwapBuffers = ImGui_ImplGlfw_SwapBuffers; +#if GLFW_HAS_WINDOW_ALPHA + platform_io.Platform_SetWindowAlpha = ImGui_ImplGlfw_SetWindowAlpha; +#endif +#if GLFW_HAS_VULKAN + platform_io.Platform_CreateVkSurface = ImGui_ImplGlfw_CreateVkSurface; +#endif + + // Register main window handle (which is owned by the main application, not by us) + // This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports. + ImGuiViewport* main_viewport = ImGui::GetMainViewport(); + ImGui_ImplGlfw_ViewportData* vd = IM_NEW(ImGui_ImplGlfw_ViewportData)(); + vd->Window = bd->Window; + vd->WindowOwned = false; + main_viewport->PlatformUserData = vd; + main_viewport->PlatformHandle = (void*)bd->Window; +} + +static void ImGui_ImplGlfw_ShutdownPlatformInterface() +{ + ImGui::DestroyPlatformWindows(); +} + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif diff --git a/src/FlipScope/ImGui/imgui_impl_opengl3.cpp b/src/FlipScope/ImGui/imgui_impl_opengl3.cpp new file mode 100644 index 0000000..f7d7b95 --- /dev/null +++ b/src/FlipScope/ImGui/imgui_impl_opengl3.cpp @@ -0,0 +1,726 @@ +// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline +// - Desktop GL: 2.x 3.x 4.x +// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0) +// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..) + +// Implemented features: +// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: Multi-viewport support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. +// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices. + +// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. +// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. +// https://github.com/ocornut/imgui + +// CHANGELOG +// (minor and older changes stripped away, please see git history for details) +// 2020-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2020-03-24: OpenGL: Added support for glbinding 2.x OpenGL loader. +// 2020-01-07: OpenGL: Added support for glbinding 3.x OpenGL loader. +// 2019-10-25: OpenGL: Using a combination of GL define and runtime GL version to decide whether to use glDrawElementsBaseVertex(). Fix building with pre-3.2 GL loaders. +// 2019-09-22: OpenGL: Detect default GL loader using __has_include compiler facility. +// 2019-09-16: OpenGL: Tweak initialization code to allow application calling ImGui_ImplOpenGL3_CreateFontsTexture() before the first NewFrame() call. +// 2019-05-29: OpenGL: Desktop GL only: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag. +// 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. +// 2019-03-29: OpenGL: Not calling glBindBuffer more than necessary in the render loop. +// 2019-03-15: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early. +// 2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0). +// 2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader. +// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display. +// 2019-02-01: OpenGL: Using GLSL 410 shaders for any version over 410 (e.g. 430, 450). +// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. +// 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT) / GL_CLIP_ORIGIN. +// 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used. +// 2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to "#version 300 ES". +// 2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation. +// 2018-07-10: OpenGL: Support for more GLSL versions (based on the GLSL version string). Added error output when shaders fail to compile/link. +// 2018-06-08: Misc: Extracted imgui_impl_opengl3.cpp/.h away from the old combined GLFW/SDL+OpenGL3 examples. +// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle. +// 2018-05-25: OpenGL: Removed unnecessary backup/restore of GL_ELEMENT_ARRAY_BUFFER_BINDING since this is part of the VAO state. +// 2018-05-14: OpenGL: Making the call to glBindSampler() optional so 3.2 context won't fail if the function is a NULL pointer. +// 2018-03-06: OpenGL: Added const char* glsl_version parameter to ImGui_ImplOpenGL3_Init() so user can override the GLSL version e.g. "#version 150". +// 2018-02-23: OpenGL: Create the VAO in the render function so the setup can more easily be used with multiple shared GL context. +// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplSdlGL3_RenderDrawData() in the .h file so you can call it yourself. +// 2018-01-07: OpenGL: Changed GLSL shader version from 330 to 150. +// 2017-09-01: OpenGL: Save and restore current bound sampler. Save and restore current polygon mode. +// 2017-05-01: OpenGL: Fixed save and restore of current blend func state. +// 2017-05-01: OpenGL: Fixed save and restore of current GL_ACTIVE_TEXTURE. +// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle. +// 2016-07-29: OpenGL: Explicitly setting GL_UNPACK_ROW_LENGTH to reduce issues because SDL changes it. (#752) + +//---------------------------------------- +// OpenGL GLSL GLSL +// version version string +//---------------------------------------- +// 2.0 110 "#version 110" +// 2.1 120 "#version 120" +// 3.0 130 "#version 130" +// 3.1 140 "#version 140" +// 3.2 150 "#version 150" +// 3.3 330 "#version 330 core" +// 4.0 400 "#version 400 core" +// 4.1 410 "#version 410 core" +// 4.2 420 "#version 410 core" +// 4.3 430 "#version 430 core" +// ES 2.0 100 "#version 100" = WebGL 1.0 +// ES 3.0 300 "#version 300 es" = WebGL 2.0 +//---------------------------------------- + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "imgui.h" +#include "imgui_impl_opengl3.h" +#include +#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier +#include // intptr_t +#else +#include // intptr_t +#endif +#if defined(__APPLE__) +#include "TargetConditionals.h" +#endif + +// Auto-enable GLES on matching platforms +#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) +#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__)) +#define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es" +#elif defined(__EMSCRIPTEN__) +#define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100" +#endif +#endif + +#if defined(IMGUI_IMPL_OPENGL_ES2) || defined(IMGUI_IMPL_OPENGL_ES3) +#undef IMGUI_IMPL_OPENGL_LOADER_GL3W +#undef IMGUI_IMPL_OPENGL_LOADER_GLEW +#undef IMGUI_IMPL_OPENGL_LOADER_GLAD +#undef IMGUI_IMPL_OPENGL_LOADER_GLBINDING2 +#undef IMGUI_IMPL_OPENGL_LOADER_GLBINDING3 +#undef IMGUI_IMPL_OPENGL_LOADER_CUSTOM +#endif + +// GL includes +#if defined(IMGUI_IMPL_OPENGL_ES2) +#include +#elif defined(IMGUI_IMPL_OPENGL_ES3) +#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) +#include // Use GL ES 3 +#else +#include // Use GL ES 3 +#endif +#else +// About Desktop OpenGL function loaders: +// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers. +// Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad). +// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own. +#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) +#include // Needs to be initialized with gl3wInit() in user's code +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) +#include // Needs to be initialized with glewInit() in user's code. +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) +#include // Needs to be initialized with gladLoadGL() in user's code. +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) +#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors. +#include // Needs to be initialized with glbinding::Binding::initialize() in user's code. +#include +using namespace gl; +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) +#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors. +#include // Needs to be initialized with glbinding::initialize() in user's code. +#include +using namespace gl; +#else +#include IMGUI_IMPL_OPENGL_LOADER_CUSTOM +#endif +#endif + +// Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have. +#if defined(IMGUI_IMPL_OPENGL_ES2) || defined(IMGUI_IMPL_OPENGL_ES3) || !defined(GL_VERSION_3_2) +#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET 0 +#else +#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET 1 +#endif + +// OpenGL Data +static GLuint g_GlVersion = 0; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries. +static char g_GlslVersionString[32] = ""; // Specified by user or detected based on compile time GL settings. +static GLuint g_FontTexture = 0; +static GLuint g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0; +static int g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; // Uniforms location +static int g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0, g_AttribLocationVtxColor = 0; // Vertex attributes location +static unsigned int g_VboHandle = 0, g_ElementsHandle = 0; + +// Forward Declarations +static void ImGui_ImplOpenGL3_InitPlatformInterface(); +static void ImGui_ImplOpenGL3_ShutdownPlatformInterface(); + +// Functions +bool ImGui_ImplOpenGL3_Init(const char* glsl_version) +{ + // Query for GL version +#if !defined(IMGUI_IMPL_OPENGL_ES2) + GLint major, minor; + glGetIntegerv(GL_MAJOR_VERSION, &major); + glGetIntegerv(GL_MINOR_VERSION, &minor); + g_GlVersion = major * 1000 + minor; +#else + g_GlVersion = 2000; // GLES 2 +#endif + + // Setup back-end capabilities flags + ImGuiIO& io = ImGui::GetIO(); + io.BackendRendererName = "imgui_impl_opengl3"; +#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET + if (g_GlVersion >= 3200) + io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. +#endif + io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional) + + // Store GLSL version string so we can refer to it later in case we recreate shaders. + // Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure. +#if defined(IMGUI_IMPL_OPENGL_ES2) + if (glsl_version == NULL) + glsl_version = "#version 100"; +#elif defined(IMGUI_IMPL_OPENGL_ES3) + if (glsl_version == NULL) + glsl_version = "#version 300 es"; +#else + if (glsl_version == NULL) + glsl_version = "#version 130"; +#endif + IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString)); + strcpy(g_GlslVersionString, glsl_version); + strcat(g_GlslVersionString, "\n"); + + // Dummy construct to make it easily visible in the IDE and debugger which GL loader has been selected. + // The code actually never uses the 'gl_loader' variable! It is only here so you can read it! + // If auto-detection fails or doesn't select the same GL loader file as used by your application, + // you are likely to get a crash below. + // You can explicitly select a loader by using '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line. + const char* gl_loader = "Unknown"; + IM_UNUSED(gl_loader); +#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) + gl_loader = "GL3W"; +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) + gl_loader = "GLEW"; +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) + gl_loader = "GLAD"; +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) + gl_loader = "glbinding2"; +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) + gl_loader = "glbinding3"; +#elif defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM) + gl_loader = "custom"; +#else + gl_loader = "none"; +#endif + + // Make a dummy GL call (we don't actually need the result) + // IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code. + // Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above. + GLint current_texture; + glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture); + + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + ImGui_ImplOpenGL3_InitPlatformInterface(); + + return true; +} + +void ImGui_ImplOpenGL3_Shutdown() +{ + ImGui_ImplOpenGL3_ShutdownPlatformInterface(); + ImGui_ImplOpenGL3_DestroyDeviceObjects(); +} + +void ImGui_ImplOpenGL3_NewFrame() +{ + if (!g_ShaderHandle) + ImGui_ImplOpenGL3_CreateDeviceObjects(); +} + +static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object) +{ + // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glEnable(GL_SCISSOR_TEST); +#ifdef GL_POLYGON_MODE + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +#endif + + // Setup viewport, orthographic projection matrix + // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. + glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height); + float L = draw_data->DisplayPos.x; + float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; + float T = draw_data->DisplayPos.y; + float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; + const float ortho_projection[4][4] = + { + { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, + { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, + { 0.0f, 0.0f, -1.0f, 0.0f }, + { (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f }, + }; + glUseProgram(g_ShaderHandle); + glUniform1i(g_AttribLocationTex, 0); + glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); +#ifdef GL_SAMPLER_BINDING + glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise. +#endif + + (void)vertex_array_object; +#ifndef IMGUI_IMPL_OPENGL_ES2 + glBindVertexArray(vertex_array_object); +#endif + + // Bind vertex/index buffers and setup attributes for ImDrawVert + glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle); + glEnableVertexAttribArray(g_AttribLocationVtxPos); + glEnableVertexAttribArray(g_AttribLocationVtxUV); + glEnableVertexAttribArray(g_AttribLocationVtxColor); + glVertexAttribPointer(g_AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos)); + glVertexAttribPointer(g_AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv)); + glVertexAttribPointer(g_AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col)); +} + +// OpenGL3 Render function. +// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop) +// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so. +void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) +{ + // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + if (fb_width <= 0 || fb_height <= 0) + return; + + // Backup GL state + GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture); + glActiveTexture(GL_TEXTURE0); + GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); + GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); +#ifdef GL_SAMPLER_BINDING + GLint last_sampler; glGetIntegerv(GL_SAMPLER_BINDING, &last_sampler); +#endif + GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); +#ifndef IMGUI_IMPL_OPENGL_ES2 + GLint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array_object); +#endif +#ifdef GL_POLYGON_MODE + GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode); +#endif + GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport); + GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box); + GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb); + GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb); + GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha); + GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha); + GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb); + GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha); + GLboolean last_enable_blend = glIsEnabled(GL_BLEND); + GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE); + GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); + GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST); + bool clip_origin_lower_left = true; +#if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__) + GLenum last_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&last_clip_origin); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT) + if (last_clip_origin == GL_UPPER_LEFT) + clip_origin_lower_left = false; +#endif + + // Setup desired GL state + // Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts) + // The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound. + GLuint vertex_array_object = 0; +#ifndef IMGUI_IMPL_OPENGL_ES2 + glGenVertexArrays(1, &vertex_array_object); +#endif + ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); + + // Will project scissor/clipping rectangles into framebuffer space + ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports + ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) + + // Render command lists + for (int n = 0; n < draw_data->CmdListsCount; n++) + { + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + + // Upload vertex/index buffers + glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW); + + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + { + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; + if (pcmd->UserCallback != NULL) + { + // User callback, registered via ImDrawList::AddCallback() + // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) + if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) + ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); + else + pcmd->UserCallback(cmd_list, pcmd); + } + else + { + // Project scissor/clipping rectangles into framebuffer space + ImVec4 clip_rect; + clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x; + clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y; + clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x; + clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y; + + if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) + { + // Apply scissor/clipping rectangle + if (clip_origin_lower_left) + glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y)); + else + glScissor((int)clip_rect.x, (int)clip_rect.y, (int)clip_rect.z, (int)clip_rect.w); // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT) + + // Bind texture, Draw + glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId); +#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET + if (g_GlVersion >= 3200) + glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset); + else +#endif + glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx))); + } + } + } + } + + // Destroy the temporary VAO +#ifndef IMGUI_IMPL_OPENGL_ES2 + glDeleteVertexArrays(1, &vertex_array_object); +#endif + + // Restore modified GL state + glUseProgram(last_program); + glBindTexture(GL_TEXTURE_2D, last_texture); +#ifdef GL_SAMPLER_BINDING + glBindSampler(0, last_sampler); +#endif + glActiveTexture(last_active_texture); +#ifndef IMGUI_IMPL_OPENGL_ES2 + glBindVertexArray(last_vertex_array_object); +#endif + glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); + glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha); + glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha); + if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND); + if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); + if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); + if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); +#ifdef GL_POLYGON_MODE + glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]); +#endif + glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); + glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); +} + +bool ImGui_ImplOpenGL3_CreateFontsTexture() +{ + // Build texture atlas + ImGuiIO& io = ImGui::GetIO(); + unsigned char* pixels; + int width, height; + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. + + // Upload texture to graphics system + GLint last_texture; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); + glGenTextures(1, &g_FontTexture); + glBindTexture(GL_TEXTURE_2D, g_FontTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +#ifdef GL_UNPACK_ROW_LENGTH + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); +#endif + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + // Store our identifier + io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontTexture; + + // Restore state + glBindTexture(GL_TEXTURE_2D, last_texture); + + return true; +} + +void ImGui_ImplOpenGL3_DestroyFontsTexture() +{ + if (g_FontTexture) + { + ImGuiIO& io = ImGui::GetIO(); + glDeleteTextures(1, &g_FontTexture); + io.Fonts->TexID = 0; + g_FontTexture = 0; + } +} + +// If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file. +static bool CheckShader(GLuint handle, const char* desc) +{ + GLint status = 0, log_length = 0; + glGetShaderiv(handle, GL_COMPILE_STATUS, &status); + glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length); + if ((GLboolean)status == GL_FALSE) + fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc); + if (log_length > 1) + { + ImVector buf; + buf.resize((int)(log_length + 1)); + glGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin()); + fprintf(stderr, "%s\n", buf.begin()); + } + return (GLboolean)status == GL_TRUE; +} + +// If you get an error please report on GitHub. You may try different GL context version or GLSL version. +static bool CheckProgram(GLuint handle, const char* desc) +{ + GLint status = 0, log_length = 0; + glGetProgramiv(handle, GL_LINK_STATUS, &status); + glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length); + if ((GLboolean)status == GL_FALSE) + fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\n", desc, g_GlslVersionString); + if (log_length > 1) + { + ImVector buf; + buf.resize((int)(log_length + 1)); + glGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin()); + fprintf(stderr, "%s\n", buf.begin()); + } + return (GLboolean)status == GL_TRUE; +} + +bool ImGui_ImplOpenGL3_CreateDeviceObjects() +{ + // Backup GL state + GLint last_texture, last_array_buffer; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); + glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); +#ifndef IMGUI_IMPL_OPENGL_ES2 + GLint last_vertex_array; + glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); +#endif + + // Parse GLSL version string + int glsl_version = 130; + sscanf(g_GlslVersionString, "#version %d", &glsl_version); + + const GLchar* vertex_shader_glsl_120 = + "uniform mat4 ProjMtx;\n" + "attribute vec2 Position;\n" + "attribute vec2 UV;\n" + "attribute vec4 Color;\n" + "varying vec2 Frag_UV;\n" + "varying vec4 Frag_Color;\n" + "void main()\n" + "{\n" + " Frag_UV = UV;\n" + " Frag_Color = Color;\n" + " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" + "}\n"; + + const GLchar* vertex_shader_glsl_130 = + "uniform mat4 ProjMtx;\n" + "in vec2 Position;\n" + "in vec2 UV;\n" + "in vec4 Color;\n" + "out vec2 Frag_UV;\n" + "out vec4 Frag_Color;\n" + "void main()\n" + "{\n" + " Frag_UV = UV;\n" + " Frag_Color = Color;\n" + " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" + "}\n"; + + const GLchar* vertex_shader_glsl_300_es = + "precision mediump float;\n" + "layout (location = 0) in vec2 Position;\n" + "layout (location = 1) in vec2 UV;\n" + "layout (location = 2) in vec4 Color;\n" + "uniform mat4 ProjMtx;\n" + "out vec2 Frag_UV;\n" + "out vec4 Frag_Color;\n" + "void main()\n" + "{\n" + " Frag_UV = UV;\n" + " Frag_Color = Color;\n" + " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" + "}\n"; + + const GLchar* vertex_shader_glsl_410_core = + "layout (location = 0) in vec2 Position;\n" + "layout (location = 1) in vec2 UV;\n" + "layout (location = 2) in vec4 Color;\n" + "uniform mat4 ProjMtx;\n" + "out vec2 Frag_UV;\n" + "out vec4 Frag_Color;\n" + "void main()\n" + "{\n" + " Frag_UV = UV;\n" + " Frag_Color = Color;\n" + " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" + "}\n"; + + const GLchar* fragment_shader_glsl_120 = + "#ifdef GL_ES\n" + " precision mediump float;\n" + "#endif\n" + "uniform sampler2D Texture;\n" + "varying vec2 Frag_UV;\n" + "varying vec4 Frag_Color;\n" + "void main()\n" + "{\n" + " gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\n" + "}\n"; + + const GLchar* fragment_shader_glsl_130 = + "uniform sampler2D Texture;\n" + "in vec2 Frag_UV;\n" + "in vec4 Frag_Color;\n" + "out vec4 Out_Color;\n" + "void main()\n" + "{\n" + " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" + "}\n"; + + const GLchar* fragment_shader_glsl_300_es = + "precision mediump float;\n" + "uniform sampler2D Texture;\n" + "in vec2 Frag_UV;\n" + "in vec4 Frag_Color;\n" + "layout (location = 0) out vec4 Out_Color;\n" + "void main()\n" + "{\n" + " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" + "}\n"; + + const GLchar* fragment_shader_glsl_410_core = + "in vec2 Frag_UV;\n" + "in vec4 Frag_Color;\n" + "uniform sampler2D Texture;\n" + "layout (location = 0) out vec4 Out_Color;\n" + "void main()\n" + "{\n" + " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" + "}\n"; + + // Select shaders matching our GLSL versions + const GLchar* vertex_shader = NULL; + const GLchar* fragment_shader = NULL; + if (glsl_version < 130) + { + vertex_shader = vertex_shader_glsl_120; + fragment_shader = fragment_shader_glsl_120; + } + else if (glsl_version >= 410) + { + vertex_shader = vertex_shader_glsl_410_core; + fragment_shader = fragment_shader_glsl_410_core; + } + else if (glsl_version == 300) + { + vertex_shader = vertex_shader_glsl_300_es; + fragment_shader = fragment_shader_glsl_300_es; + } + else + { + vertex_shader = vertex_shader_glsl_130; + fragment_shader = fragment_shader_glsl_130; + } + + // Create shaders + const GLchar* vertex_shader_with_version[2] = { g_GlslVersionString, vertex_shader }; + g_VertHandle = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(g_VertHandle, 2, vertex_shader_with_version, NULL); + glCompileShader(g_VertHandle); + CheckShader(g_VertHandle, "vertex shader"); + + const GLchar* fragment_shader_with_version[2] = { g_GlslVersionString, fragment_shader }; + g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(g_FragHandle, 2, fragment_shader_with_version, NULL); + glCompileShader(g_FragHandle); + CheckShader(g_FragHandle, "fragment shader"); + + g_ShaderHandle = glCreateProgram(); + glAttachShader(g_ShaderHandle, g_VertHandle); + glAttachShader(g_ShaderHandle, g_FragHandle); + glLinkProgram(g_ShaderHandle); + CheckProgram(g_ShaderHandle, "shader program"); + + g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture"); + g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx"); + g_AttribLocationVtxPos = glGetAttribLocation(g_ShaderHandle, "Position"); + g_AttribLocationVtxUV = glGetAttribLocation(g_ShaderHandle, "UV"); + g_AttribLocationVtxColor = glGetAttribLocation(g_ShaderHandle, "Color"); + + // Create buffers + glGenBuffers(1, &g_VboHandle); + glGenBuffers(1, &g_ElementsHandle); + + ImGui_ImplOpenGL3_CreateFontsTexture(); + + // Restore modified GL state + glBindTexture(GL_TEXTURE_2D, last_texture); + glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); +#ifndef IMGUI_IMPL_OPENGL_ES2 + glBindVertexArray(last_vertex_array); +#endif + + return true; +} + +void ImGui_ImplOpenGL3_DestroyDeviceObjects() +{ + if (g_VboHandle) { glDeleteBuffers(1, &g_VboHandle); g_VboHandle = 0; } + if (g_ElementsHandle) { glDeleteBuffers(1, &g_ElementsHandle); g_ElementsHandle = 0; } + if (g_ShaderHandle && g_VertHandle) { glDetachShader(g_ShaderHandle, g_VertHandle); } + if (g_ShaderHandle && g_FragHandle) { glDetachShader(g_ShaderHandle, g_FragHandle); } + if (g_VertHandle) { glDeleteShader(g_VertHandle); g_VertHandle = 0; } + if (g_FragHandle) { glDeleteShader(g_FragHandle); g_FragHandle = 0; } + if (g_ShaderHandle) { glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; } + + ImGui_ImplOpenGL3_DestroyFontsTexture(); +} + +//-------------------------------------------------------------------------------------------------------- +// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT +// This is an _advanced_ and _optional_ feature, allowing the back-end to create and handle multiple viewports simultaneously. +// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first.. +//-------------------------------------------------------------------------------------------------------- + +static void ImGui_ImplOpenGL3_RenderWindow(ImGuiViewport* viewport, void*) +{ + if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear)) + { + ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); + glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w); + glClear(GL_COLOR_BUFFER_BIT); + } + ImGui_ImplOpenGL3_RenderDrawData(viewport->DrawData); +} + +static void ImGui_ImplOpenGL3_InitPlatformInterface() +{ + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + platform_io.Renderer_RenderWindow = ImGui_ImplOpenGL3_RenderWindow; +} + +static void ImGui_ImplOpenGL3_ShutdownPlatformInterface() +{ + ImGui::DestroyPlatformWindows(); +} diff --git a/src/FlipScope/Pipeline/Episode.cpp b/src/FlipScope/Pipeline/Episode.cpp new file mode 100644 index 0000000..7f91ed3 --- /dev/null +++ b/src/FlipScope/Pipeline/Episode.cpp @@ -0,0 +1,22 @@ +#include "pch.h" + +#include "FlipScope/Pipeline/Episode.h" + +namespace FSV +{ + Episode::Episode(Project *project, std::string name) + : m_Project(project), + m_Name(name) + { + } + + Episode::~Episode() + { + + } + + void Episode::AddShot(Shot &shot) + { + m_ShotList.push_back(shot); + } +} \ No newline at end of file diff --git a/src/FlipScope/Pipeline/Episode.h b/src/FlipScope/Pipeline/Episode.h new file mode 100644 index 0000000..1f16e28 --- /dev/null +++ b/src/FlipScope/Pipeline/Episode.h @@ -0,0 +1,27 @@ +#pragma once + +#include "FlipScope/Pipeline/Project.h" +#include "FlipScope/Pipeline/Shot.h" + +#include +#include + +namespace FSV +{ + class Episode + { + public: + Episode(Project *project, const std::string name); + ~Episode(); + + std::string GetName() { return m_Name; } + ShotList GetShotList() { return m_ShotList; } + + void AddShot(Shot &shot); + + private: + std::string m_Name; + Project* m_Project; + ShotList m_ShotList; + }; +} diff --git a/src/FlipScope/Pipeline/Project.cpp b/src/FlipScope/Pipeline/Project.cpp new file mode 100644 index 0000000..31f4249 --- /dev/null +++ b/src/FlipScope/Pipeline/Project.cpp @@ -0,0 +1,155 @@ +#include "pch.h" + +#include "FlipScope/Pipeline/Project.h" +#include "FlipScope/Pipeline/Episode.h" +#include "FlipScope/Pipeline/Shot.h" +#include "FlipScope/Core/Log.h" + +namespace FSV +{ + + Project::Project(const std::string name, + const std::string aliasname, + const std::string type, + const std::string location, + const std::string ntPath, + const std::string unixPath, + const StringList users) : + m_Name(name), + m_AliasName(aliasname), + m_Type(type), + m_Location(location), + m_NtPath(ntPath), + m_UnixPath(unixPath), + m_Users(users) + { + FS_INFO("Init ProjectData : {0}", aliasname); + const std::string ddtProjectDataRoot = "//ren/render/WEB/ddt2/" + aliasname; + + m_ShotLastReviewConfigPath = ddtProjectDataRoot + "/" + "shot_lastest_review_file.tbs"; + m_ShotInfomationConfigPath = ddtProjectDataRoot + "/" + "shot_information.tbs"; + m_ShotTaskReviewConfigPath = ddtProjectDataRoot + "/" + "shottask_information.tbs"; + + } + + Project::~Project() + { + m_Users.clear(); + } + + void Project::ShotLastReviewConfigInit() + { + if (!m_ShotLastReviewConfigRoot.isNull()) + { + return; + } + + std::ifstream config_doc(m_ShotLastReviewConfigPath, std::ifstream::binary); + Json::CharReaderBuilder rbuilder; + std::string errs; + + if (!Json::parseFromStream(rbuilder, config_doc, &m_ShotLastReviewConfigRoot, &errs)) + { + FS_ERROR(errs); + return; + } + + // Initialize Episode List + if (m_EpisodeNameList.size() == 0) + { + for (auto &info : m_ShotLastReviewConfigRoot) + { + std::string episodeName = info["name"].asString(); + m_EpisodeNameList.push_back(episodeName); + FS_INFO("GetEpisodeList() : {0} : {1}", m_AliasName, info["name"].asString()); + } + } + } + + void Project::ShotInfomationConfigInit() + { + if (!m_ShotInfomationConfigRoot.isNull()) + { + return; + } + + std::ifstream config_doc(m_ShotInfomationConfigPath, std::ifstream::binary); + Json::CharReaderBuilder rbuilder; + std::string errs; + + if (!Json::parseFromStream(rbuilder, config_doc, &m_ShotInfomationConfigRoot, &errs)) + { + FS_ERROR(errs); + return; + } + + for (auto &info : m_ShotInfomationConfigRoot) + { + for (unsigned int n = 1; n < info["table"].size(); n++) + { + std::string name = info["table"][n][2].asString(); + std::string act = info["table"][n][3].asString(); + std::string sequence = info["table"][n][4].asString(); + int frameStart = info["table"][n][5].asInt(); + int frameEnd = info["table"][n][6].asInt(); + int duration = info["table"][n][7].asInt(); + int handleLeft = info["table"][n][8].asInt(); + int handleRight = info["table"][n][9].asInt(); + std::string shotType = info["table"][n][11].asString(); + std::string episodeName = info["table"][n][12].asString(); + Shot shot(name, act, sequence, + frameStart, frameEnd, duration, handleLeft, handleRight, + shotType, m_AliasName, episodeName); + m_ShotList.push_back(shot); + } + + FS_INFO("Init {0} Shots", info["table"].size()); + } + } + + bool Project::IsProjectUser(std::string userName) + { + for (auto &user : m_Users) + { + if (user == userName) + { + return true; + } + } + return false; + } + + StringList Project::GetEpisodeNameList() + { + ShotLastReviewConfigInit(); + + if (m_EpisodeNameList.size() == 0) + { + for (auto &info : m_ShotLastReviewConfigRoot) + { + std::string episodeName = info["name"].asString(); + m_EpisodeNameList.push_back(episodeName); + FS_INFO("GetEpisodeList() : {0} : {1}", m_AliasName, info["name"].asString()); + } + } + return m_EpisodeNameList; + } + + ShotList Project::GetShotListByEpisode(std::string episodeName) + { + ShotInfomationConfigInit(); + + ShotList shotList; + if (m_ShotList.size() == 0) + return shotList; + + for (auto &shot : m_ShotList) + { + if (shot.GetEpisodeName() == episodeName) + { + shotList.push_back(shot); + } + } + return shotList; + } +} diff --git a/src/FlipScope/Pipeline/Project.h b/src/FlipScope/Pipeline/Project.h new file mode 100644 index 0000000..3d1bf6d --- /dev/null +++ b/src/FlipScope/Pipeline/Project.h @@ -0,0 +1,74 @@ +#pragma once + +#include +#include +#include + +#include "FlipScope/Pipeline/Shot.h" + +namespace FSV +{ + typedef std::vector StringList; + //typedef std::vector EpisodeList; + typedef std::vector ShotList; + + class Project + { + public: + Project(const std::string name, + const std::string aliasname, + const std::string type, + const std::string location, + const std::string ntPath, + const std::string unixPath, + const StringList users = StringList()); + ~Project(); + + public: + bool IsEmpty() { return m_Name.length() <= 0; } + std::string GetName() { return m_Name; } + std::string GetAliasName() { return m_AliasName; } + std::string GetType() { return m_AliasName; } + std::string GetLocation() { return m_Location; } + std::string GetNtPath() { return m_NtPath; } + std::string GetUnixPath() { return m_UnixPath; } + StringList GetUsers() { return m_Users; } + + public: + bool IsProjectUser(std::string userName); + + void ShotLastReviewConfigInit(); + void ShotInfomationConfigInit(); + + std::string GetShotLastReviewConfigPath() { return m_ShotLastReviewConfigPath; } + std::string GetShotInfomationConfigPath() { return m_ShotInfomationConfigPath; } + std::string GetShotTaskReviewConfigPath() { return m_ShotTaskReviewConfigPath; } + + StringList GetEpisodeNameList(); + //EpisodeList GetEpisodeList() { return m_EpisodeList; } + ShotList GetShotList() { return m_ShotList; } + ShotList GetShotListByEpisode(std::string episodeName); + + private: + std::string m_Name; + std::string m_AliasName; + std::string m_Type; + std::string m_Location; + std::string m_NtPath; + std::string m_UnixPath; + + StringList m_Users; + + std::string m_ShotLastReviewConfigPath; + std::string m_ShotInfomationConfigPath; + std::string m_ShotTaskReviewConfigPath; + + Json::Value m_ShotLastReviewConfigRoot; + Json::Value m_ShotInfomationConfigRoot; + Json::Value m_ShotTaskReviewConfigRoot; + + StringList m_EpisodeNameList; + //EpisodeList m_EpisodeList; + ShotList m_ShotList; + }; +} diff --git a/src/FlipScope/Pipeline/ProjectInfo.cpp b/src/FlipScope/Pipeline/ProjectInfo.cpp new file mode 100644 index 0000000..192b50d --- /dev/null +++ b/src/FlipScope/Pipeline/ProjectInfo.cpp @@ -0,0 +1,139 @@ +#include "pch.h" + +#include "FlipScope/Pipeline/ProjectInfo.h" +#include "FlipScope/Core/Log.h" + +namespace FSV +{ + const char* projectConfigPath = "//ren/render/spider/project.json"; + + ProjectInfo::ProjectInfo() + { + //if(!m_Initialized) + // Init(); + } + + ProjectInfo::~ProjectInfo() + { + Shutdown(); + } + + std::string ProjectInfo::GetCurrentLocation() + { + const char* domain = getenv("USERDOMAIN"); + if (strcmp(domain, "CG") == 0) + return "cgtp"; + if (strcmp(domain, "CGCG") == 0) + return "cgks"; + if (strcmp(domain, "CGXM") == 0) + return "cgxm"; + if (strcmp(domain, "GLOWINGSTUDIOS") == 0) + return "bgs"; + return "unknown"; + } + + std::string ProjectInfo::GetCurrentUser() + { + return getenv("USERNAME"); + } + + Project ProjectInfo::GetCurrentProjectByName(std::string projectName) + { + for (auto &p : m_UserProjectList) + { + if (p.GetAliasName() == projectName) + { + return p; + } + } + return Project("", "", "", "", "", ""); + } + + ProjectList ProjectInfo::GetUserProjects() + { + Init(); + return m_UserProjectList; + } + + void ProjectInfo::Reload() + { + m_UserProjectList.clear(); + m_Initialized = false; + Init(); + } + + void ProjectInfo::Init() + { + if (m_Initialized) + return; + + std::ifstream config_doc(projectConfigPath, std::ifstream::binary); + Json::CharReaderBuilder rbuilder; + + std::string errs; + Json::Value root; + + if (!Json::parseFromStream(rbuilder, config_doc, &root, &errs)) + { + FS_ERROR("{0}", errs.c_str()); + return; + } + + std::string currentUser = GetCurrentUser(); + auto projectNames = root.getMemberNames(); + + std::sort(projectNames.begin(), projectNames.end()); + + for(auto &name: projectNames) + { + std::string type = root[name]["Type"].asString(); + + if (type == "data") + { + std::string aliasName = root[name]["AliasName"].asString(); + std::string location = root[name]["Location"].asString(); + std::string ntPath = root[name]["NT"].asString(); + std::string unixPath = root[name]["UNIX"].asString(); + StringList users; + bool isProjectMember = false; + if (!root[name]["USER"].isNull()) + { + for (auto& user : root[name]["USER"]) + { + users.push_back(user.asString()); + } + } + std::string currentLocation = GetCurrentLocation(); + if (currentLocation == location) + { + // Current User Name in Project Users + if (std::find(users.begin(), users.end(), currentUser) != users.end()) + { + Project p(name, aliasName, type, location, ntPath, unixPath, users); + m_UserProjectList.push_back(p); + FS_INFO("Project :{0}", name); + } + } + } + } + + // For debug only + /*for (auto &p : m_CurrentProjectList) + { + FS_INFO("Check {0}", p.GetName()); + ProjectData data = p.GetProjectData(); + FS_INFO("Check {0}", data.GetShotLastReviewConfigPath()); + for (auto&e : p.GetProjectData().GetEpisodeList()) + { + FS_INFO("{0}", e.c_str()); + } + }*/ + + //std::sort(m_ProjectNames.begin(), m_ProjectNames.end()); + } + + void ProjectInfo::Shutdown() + { + m_UserProjectList.clear(); + } +} \ No newline at end of file diff --git a/src/FlipScope/Pipeline/ProjectInfo.h b/src/FlipScope/Pipeline/ProjectInfo.h new file mode 100644 index 0000000..405126b --- /dev/null +++ b/src/FlipScope/Pipeline/ProjectInfo.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include + +#include "FlipScope/Core/Log.h" +#include "FlipScope/Pipeline/Project.h" + +namespace FSV +{ + typedef std::vector ProjectList; + + class ProjectInfo + { + public: + + ProjectInfo(); + ~ProjectInfo(); + + void Init(); + void Reload(); + void Shutdown(); + + public: + static std::string GetCurrentLocation(); + static std::string GetCurrentUser(); + + Project GetCurrentProjectByName(std::string projectName); + ProjectList GetUserProjects(); + + private: + bool m_Initialized = false; + ProjectList m_UserProjectList; + }; +} diff --git a/src/FlipScope/Pipeline/Shot.cpp b/src/FlipScope/Pipeline/Shot.cpp new file mode 100644 index 0000000..b2da380 --- /dev/null +++ b/src/FlipScope/Pipeline/Shot.cpp @@ -0,0 +1,32 @@ +#include "pch.h" + +#include "FlipScope/Pipeline/Shot.h" + +namespace FSV +{ + Shot::Shot( const std::string name, + const std::string act, + const std::string sequence, + const int frameStart, + const int frameEnd, + const int duration, + const int handleLeft, + const int handleRight, + const std::string shotType, + const std::string projectName, + const std::string episodeName) + : m_Name(name), + m_Act(act), + m_Sequence(sequence), + m_FrameStart(frameStart), + m_FrameEnd(frameEnd), + m_Duration(duration), + m_HandleLeft(handleLeft), + m_HandleRight(handleRight), + m_ShotType(shotType), + m_ProjectName(projectName), + m_EpisodeName(episodeName) + { + } + +} \ No newline at end of file diff --git a/src/FlipScope/Pipeline/Shot.h b/src/FlipScope/Pipeline/Shot.h new file mode 100644 index 0000000..457d158 --- /dev/null +++ b/src/FlipScope/Pipeline/Shot.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include + +namespace FSV +{ + + class Shot + { + public: + + Shot( const std::string name, + const std::string act, + const std::string sequence, + const int frameStart, + const int frameEnd, + const int duration, + const int handleLeft, + const int handleRight, + const std::string shotType, + const std::string projectName, + const std::string episodeName); + ~Shot(){}; + + std::string GetName() { return m_Name; } + std::string GetAct() { return m_Act; } + std::string GetSequence() { return m_Sequence; } + int GetFrameStart() { return m_FrameStart; } + int GetFrameEnd() { return m_FrameEnd; } + std::string GetProjectName() { return m_ProjectName; } + std::string GetEpisodeName() { return m_EpisodeName; } + + private: + std::string m_Name; + std::string m_Act; + std::string m_Sequence; + int m_FrameStart = 0; + int m_FrameEnd = 0; + int m_Duration = 0; + int m_HandleLeft = 0; + int m_HandleRight = 0; + std::string m_ShotType; + + std::string m_ProjectName; + std::string m_EpisodeName; + + }; +} diff --git a/src/FlipScope/Renderer/FrameBuffer.cpp b/src/FlipScope/Renderer/FrameBuffer.cpp new file mode 100644 index 0000000..8dd8dc8 --- /dev/null +++ b/src/FlipScope/Renderer/FrameBuffer.cpp @@ -0,0 +1,24 @@ +#include "pch.h" + +#include "FlipScope/Renderer/FrameBuffer.h" +#include "FlipScope/Renderer/Renderer.h" +#include "FlipScope/Core/Log.h" +#include "Platform/OpenGL/OpenGLFramebuffer.h" + +namespace FSV +{ + std::shared_ptr Framebuffer::Create(const FramebufferSpecification& spec) + { + switch (Renderer::GetAPI()) + { + case RendererAPI::API::None: + return nullptr; + case RendererAPI::API::OpenGL: + return std::make_shared(spec); + } + + FS_ERROR("Unknown RendererAPI!"); + + return nullptr; + } +} \ No newline at end of file diff --git a/src/FlipScope/Renderer/FrameBuffer.h b/src/FlipScope/Renderer/FrameBuffer.h new file mode 100644 index 0000000..f2664e2 --- /dev/null +++ b/src/FlipScope/Renderer/FrameBuffer.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +namespace FSV +{ + struct FramebufferSpecification + { + uint32_t Width, Height; + uint32_t Sample = 1; + bool SwapChainTarget = false; + }; + + class Framebuffer + { + public: + virtual void Bind() = 0; + virtual void Unbind() = 0; + + virtual void Resize(uint32_t width, uint32_t height) = 0; + + virtual uint32_t GetColorAttachmentRendererID() const = 0; + + virtual const FramebufferSpecification& GetSpecification() const = 0; + + static std::shared_ptr Create(const FramebufferSpecification& spec); + }; +} \ No newline at end of file diff --git a/src/FlipScope/Renderer/GraphicsContext.cpp b/src/FlipScope/Renderer/GraphicsContext.cpp new file mode 100644 index 0000000..6b71983 --- /dev/null +++ b/src/FlipScope/Renderer/GraphicsContext.cpp @@ -0,0 +1,21 @@ +#include "pch.h" + +#include "FlipScope/Renderer/GraphicsContext.h" + +#include "FlipScope/Renderer/Renderer.h" +#include "Platform/OpenGL/OpenGLContext.h" + +namespace FSV +{ + std::unique_ptr GraphicsContext::Create(void* window) + { + switch (Renderer::GetAPI()) + { + case RendererAPI::API::None: + return nullptr; + case RendererAPI::API::OpenGL: + return std::make_unique(static_cast(window)); + } + return nullptr; + } +} \ No newline at end of file diff --git a/src/FlipScope/Renderer/GraphicsContext.h b/src/FlipScope/Renderer/GraphicsContext.h new file mode 100644 index 0000000..881dce0 --- /dev/null +++ b/src/FlipScope/Renderer/GraphicsContext.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +namespace FSV +{ + class GraphicsContext + { + public: + virtual void Init() = 0; + virtual void SwapBuffers() = 0; + + static std::unique_ptr Create(void* window); + }; +} diff --git a/src/FlipScope/Renderer/RenderCommand.cpp b/src/FlipScope/Renderer/RenderCommand.cpp new file mode 100644 index 0000000..541e55d --- /dev/null +++ b/src/FlipScope/Renderer/RenderCommand.cpp @@ -0,0 +1,8 @@ +#include "pch.h" + +#include "FlipScope/Renderer/RenderCommand.h" + +namespace FSV +{ + std::unique_ptr RenderCommand::s_RendererAPI = RendererAPI::Create(); +} \ No newline at end of file diff --git a/src/FlipScope/Renderer/RenderCommand.h b/src/FlipScope/Renderer/RenderCommand.h new file mode 100644 index 0000000..27c1c40 --- /dev/null +++ b/src/FlipScope/Renderer/RenderCommand.h @@ -0,0 +1,32 @@ +#pragma once + +#include "FlipScope/Renderer/RendererAPI.h" + +namespace FSV +{ + class RenderCommand + { + public: + static void Init() + { + s_RendererAPI->Init(); + } + + static void SetViewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height) + { + s_RendererAPI->SetViewport(x, y, width, height); + } + + static void SetClearColor(glm::vec4& color) + { + s_RendererAPI->SetClearColor(color); + } + static void Clear() + { + s_RendererAPI->Clear(); + } + + private: + static std::unique_ptr s_RendererAPI; + }; +} diff --git a/src/FlipScope/Renderer/Renderer.cpp b/src/FlipScope/Renderer/Renderer.cpp new file mode 100644 index 0000000..43860d1 --- /dev/null +++ b/src/FlipScope/Renderer/Renderer.cpp @@ -0,0 +1,31 @@ +#include "pch.h" + +#include "FlipScope/Renderer/Renderer.h" + +namespace FSV +{ + void Renderer::Init() + { + RenderCommand::Init(); + } + + void Renderer::BeginScene() + { + + } + + void Renderer::EndScene() + { + + } + + void Renderer::OnWindowResize(uint32_t width, uint32_t height) + { + RenderCommand::SetViewport(0, 0, width, height); + } + + void Renderer::Shutdown() + { + + } +} \ No newline at end of file diff --git a/src/FlipScope/Renderer/Renderer.h b/src/FlipScope/Renderer/Renderer.h new file mode 100644 index 0000000..55e7e0c --- /dev/null +++ b/src/FlipScope/Renderer/Renderer.h @@ -0,0 +1,20 @@ +#pragma once +#include "FlipScope/Renderer/RenderCommand.h" +#include "FlipScope/Renderer/RendererAPI.h" + +namespace FSV +{ + class Renderer + { + public: + static void Init(); + static void Shutdown(); + + static void OnWindowResize(uint32_t width, uint32_t height); + + static void BeginScene(); + static void EndScene(); + + inline static RendererAPI::API GetAPI() { return RendererAPI::GetAPI(); } + }; +} diff --git a/src/FlipScope/Renderer/RendererAPI.cpp b/src/FlipScope/Renderer/RendererAPI.cpp new file mode 100644 index 0000000..4c7d1ae --- /dev/null +++ b/src/FlipScope/Renderer/RendererAPI.cpp @@ -0,0 +1,17 @@ +#include "pch.h" + +#include "FlipScope/Renderer/RendererAPI.h" +#include "Platform/OpenGL/OpenGLRendererAPI.h" + +namespace FSV +{ + RendererAPI::API RendererAPI::s_API = RendererAPI::API::OpenGL; + std::unique_ptr RendererAPI::Create() + { + switch (s_API) + { + case RendererAPI::API::OpenGL: return std::make_unique(); + } + return nullptr; + } +} \ No newline at end of file diff --git a/src/FlipScope/Renderer/RendererAPI.h b/src/FlipScope/Renderer/RendererAPI.h new file mode 100644 index 0000000..3026b17 --- /dev/null +++ b/src/FlipScope/Renderer/RendererAPI.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +#include + +namespace FSV +{ + class RendererAPI + { + public: + enum class API + { + None = 0, OpenGL = 1 + }; + + public: + virtual void Init() = 0; + virtual void SetViewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height) = 0; + virtual void SetClearColor(const glm::vec4& color) = 0; + + virtual void Clear() = 0; + + inline static API GetAPI() { return s_API; } + + static std::unique_ptr Create(); + + private: + static API s_API; + }; +} diff --git a/src/FlipScope/Renderer/Texture.cpp b/src/FlipScope/Renderer/Texture.cpp new file mode 100644 index 0000000..b1d0d57 --- /dev/null +++ b/src/FlipScope/Renderer/Texture.cpp @@ -0,0 +1,46 @@ +#include "pch.h" + +#include "FlipScope/Renderer/Texture.h" +#include "FlipScope/Renderer/Renderer.h" +#include "FlipScope/Core/Log.h" + +#include "Platform/OpenGL/OpenGLTexture.h" + +namespace FSV +{ + std::shared_ptr Texture::Create(uint32_t width, uint32_t height) + { + switch (Renderer::GetAPI()) + { + case RendererAPI::API::None: + { + FS_ERROR("RendererAPI::None is currently not supported!"); + return nullptr; + } + case RendererAPI::API::OpenGL: + return std::make_shared(width, height); + } + + FS_ERROR("Unknown RendererAPI"); + + return nullptr; + } + + std::shared_ptr Texture::Create(const std::string& path) + { + switch (Renderer::GetAPI()) + { + case RendererAPI::API::None: + { + FS_ERROR("RendererAPI::None is currently not supported!"); + return nullptr; + } + case RendererAPI::API::OpenGL: + return std::make_shared(path); + } + + FS_ERROR("Unknown RendererAPI"); + + return nullptr; + } +} \ No newline at end of file diff --git a/src/FlipScope/Renderer/Texture.h b/src/FlipScope/Renderer/Texture.h new file mode 100644 index 0000000..4b3ee9e --- /dev/null +++ b/src/FlipScope/Renderer/Texture.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +namespace FSV +{ + class Texture + { + public: + ~Texture() = default; + + virtual uint32_t GetWidth() const = 0; + virtual uint32_t GetHeight() const = 0; + virtual uint32_t GetRendererID() const = 0; + + virtual void SetData(void* data, uint32_t size) const = 0; + + + virtual void Bind(uint32_t slot = 0) const = 0; + virtual bool operator==(const Texture& other) const = 0; + + static std::shared_ptr Create(uint32_t width, uint32_t height); + static std::shared_ptr Create(const std::string& path); + + }; +} diff --git a/src/FlipScope/Renderer/ViewportRenderer.cpp b/src/FlipScope/Renderer/ViewportRenderer.cpp new file mode 100644 index 0000000..2bdf3f7 --- /dev/null +++ b/src/FlipScope/Renderer/ViewportRenderer.cpp @@ -0,0 +1,25 @@ +#include "pch.h" + +#include "FlipScope/Renderer/ViewportRenderer.h" +#include "FlipScope/Renderer/Renderer.h" +#include "FlipScope/Core/Log.h" + +#include "Platform/OpenGL/OpenGLViewportRenderer.h" + +namespace FSV +{ + std::shared_ptr ViewportRenderer::Create() + { + switch (Renderer::GetAPI()) + { + case RendererAPI::API::None: + return nullptr; + case RendererAPI::API::OpenGL: + return std::make_shared(); + } + + FS_ERROR("Unknown RendererAPI"); + + return nullptr; + } +} \ No newline at end of file diff --git a/src/FlipScope/Renderer/ViewportRenderer.h b/src/FlipScope/Renderer/ViewportRenderer.h new file mode 100644 index 0000000..a19dba2 --- /dev/null +++ b/src/FlipScope/Renderer/ViewportRenderer.h @@ -0,0 +1,26 @@ +#pragma once +#include "FlipScope/Renderer/Renderer.h" + +namespace FSV +{ + class ViewportRenderer + { + public: + ViewportRenderer() = default; + ~ViewportRenderer() = default; + + static std::shared_ptr Create(); + + virtual void Init() = 0; + virtual void Shutdown() = 0; + + virtual uint32_t GetWidth() const = 0; + virtual uint32_t GetHeight() const = 0; + + virtual void OnWindowResize(uint32_t width, uint32_t height) = 0; + + virtual void OnRender() = 0; + + inline static RendererAPI::API GetAPI() { return RendererAPI::GetAPI(); } + }; +} diff --git a/src/FlipScope/Usd/FreeCamera.cpp b/src/FlipScope/Usd/FreeCamera.cpp new file mode 100644 index 0000000..773d64f --- /dev/null +++ b/src/FlipScope/Usd/FreeCamera.cpp @@ -0,0 +1,300 @@ +#include "pch.h" + +#include "FlipScope/Usd/FreeCamera.h" + + +namespace FSV +{ + FreeCamera::FreeCamera(CameraOptions option, bool isZUp, float fov=60.0) + : m_Options(option) + { + m_Camera = GfCamera(); + m_Camera.SetPerspectiveFromAspectRatioAndFieldOfView(1.0, fov, GfCamera::FOVVertical); + + ResetClipingPlanes(); + + m_IsZUp = isZUp; + m_CameraTransformDirty = true; + + m_RotTheta = 0; + m_RotPhi = 0; + m_RotPsi = 0; + m_Center = GfVec3d(0, 0, 0); + m_Dist = 100; + m_Camera.SetFocusDistance(m_Dist); + m_SelSize = 10; + + if (isZUp) + { + m_YZUpMatrix = GfMatrix4d().SetRotate(GfRotation(GfVec3d().XAxis(), -90)); + m_YZUpInvMatrix = m_YZUpMatrix.GetInverse(); + } + else + { + m_YZUpMatrix = GfMatrix4d(1.0); + m_YZUpInvMatrix = GfMatrix4d(1.0); + } + } + + FreeCamera::~FreeCamera() + { + } + + float FreeCamera::GetFov() + { + // The vertical field of view, in degrees, for perspective cameras. + // For orthographic cameras fov is the height of the view frustum, in + // world units. + // + if (m_Camera.GetProjection() == GfCamera::Projection::Perspective) + { + return m_Camera.GetFieldOfView(GfCamera::FOVVertical); + } + else + { + return m_Camera.GetVerticalAperture() * GfCamera::APERTURE_UNIT; + } + } + + void FreeCamera::SetFov(float value) + { + if (m_Camera.GetProjection() == GfCamera::Projection::Perspective) + { + m_Camera.SetPerspectiveFromAspectRatioAndFieldOfView( + m_Camera.GetAspectRatio(), value, GfCamera::FOVVertical); + } + else + { + m_Camera.SetOrthographicFromAspectRatioAndSize( + m_Camera.GetAspectRatio(), value, GfCamera::FOVVertical); + } + } + + float FreeCamera::GetNearClip() + { + return m_Camera.GetClippingRange().GetMin(); + } + + float FreeCamera::GetFarClip() + { + return m_Camera.GetClippingRange().GetMax(); + } + + void FreeCamera::ResetClipingPlanes() + { + double _near = m_OverrideNear || m_Options.DefaultNear; + double _far = m_OverrideFar || m_Options.DefaultFar; + m_Camera.SetClippingRange(GfRange1f(_near, _far)); + } + + void FreeCamera::FrameSelection(GfBBox3d selBBox, float frameFit) + { + m_ClosestVisibleDist = -1; + m_Center = selBBox.ComputeCentroid(); + GfRange3d selRange = selBBox.ComputeAlignedRange(); + GfVec3d selSize = selRange.GetSize(); + m_SelSize = std::max(std::max(selSize[0], selSize[1]), selSize[2]); + if (IsOrthographic()) + { + //m_Fov = m_SelSize * frameFit; + SetFov(m_SelSize * frameFit); + m_Dist = m_SelSize + m_Options.DefaultNear; + } + else + { + float fov = GetFov(); + float halfFov = fov * 0.5 || 0.5; + float lengthToFit = m_SelSize * frameFit * 0.5; + m_Dist = lengthToFit / atan(((halfFov * M_PI) / 180.0)); + + if (m_Dist < (m_Options.DefaultNear + m_SelSize * 0.5)) + { + m_Dist = m_Options.DefaultNear + lengthToFit; + } + } + + } + + void FreeCamera::SetClosestVisibleDistFromPoint(GfVec3d point) + { + GfFrustum frustum = m_Camera.GetFrustum(); + GfVec3d camPos = frustum.GetPosition(); + GfRay camRay = GfRay(camPos, frustum.ComputeViewDirection()); + m_ClosestVisibleDist = camRay.FindClosestPoint(point)[1]; + m_LastFramedDist = m_Dist; + m_LastFramedClosestDist = m_ClosestVisibleDist; + } + + float FreeCamera::ComputePixelsToWorldFactor(int viewportHeight) + { + PushToCameraTransform(); + if (IsOrthographic()) + { + return GetFov() / viewportHeight; + } + else + { + float frustumHeight = m_Camera.GetFrustum().GetWindow().GetSize()[1]; + return frustumHeight * m_Dist / viewportHeight; + } + } + + bool FreeCamera::IsOrthographic() + { + return m_Camera.GetProjection() == GfCamera::Projection::Orthographic; + } + + void FreeCamera::SetProjection(GfCamera::Projection projection) + { + m_Camera.SetProjection(projection); + } + + GfCamera::Projection FreeCamera::GetProjection() + { + return m_Camera.GetProjection(); + } + + void FreeCamera::SetClippingPlanes(GfBBox3d stageBBox) + { + //TfDebug::IsDebugSymbolNameEnabled(); + + double computedNear, computedFar = 0; + if (stageBBox.GetRange().IsEmpty() || (m_OverrideNear && m_OverrideFar)) + { + computedNear = m_Options.DefaultNear; + computedFar = m_Options.DefaultFar; + } + else + { + GfFrustum frustum = m_Camera.GetFrustum(); + GfVec3d camPos = frustum.GetPosition(); + GfRay camRay = GfRay(camPos, frustum.ComputeViewDirection()); + + RangeOfBoxAlongRay(computedNear, computedFar, camRay, stageBBox); + double precisionNear = computedFar / m_Options.MaxGoodZResolution; + + if (m_ClosestVisibleDist) + { + double halfClose = m_ClosestVisibleDist / 2.0; + if (m_ClosestVisibleDist < m_LastFramedClosestDist) + { + halfClose = std::max(std::max(precisionNear, halfClose), computedNear); + } + + if (halfClose < computedNear) + { + computedNear = halfClose; + } + else if (precisionNear > computedNear) + { + computedNear = std::min(((precisionNear + halfClose) / 2.0), halfClose); + } + + } + + } + + double _near = m_OverrideNear || computedNear; + double _far = m_OverrideFar || computedFar; + + _far = std::max(_near + 1, _far); + m_Camera.SetClippingRange(GfRange1f(_near, _far)); + + } + + GfCamera FreeCamera::ComputeGfCamera(GfBBox3d stageBBox, bool autoClip=true) + { + PushToCameraTransform(); + + if (autoClip) + SetClippingPlanes(stageBBox); + else + ResetClipingPlanes(); + + return m_Camera; + } + + GfMatrix4d FreeCamera::RotMatrix(GfVec3d &vec, double angle) + { + return GfMatrix4d(1.0).SetRotate(GfRotation(vec, angle)); + } + + void FreeCamera::RangeOfBoxAlongRay(double &minDist, double &maxDist, GfRay camRay, GfBBox3d stageBBox) + { + minDist = -1 * std::numeric_limits::min(); + maxDist = 1 * std::numeric_limits::max(); + + GfRange3d boxRange = stageBBox.GetRange(); + GfMatrix4d boxXform = stageBBox.GetMatrix(); + for (int i = 0; i < 8; i++) + { + GfVec3d point = boxXform.Transform(boxRange.GetCorner(i)); + double pointDist = camRay.FindClosestPoint(point)[1]; + if (pointDist > maxDist) + maxDist = pointDist; + if (pointDist < minDist) + minDist = pointDist; + } + if (minDist < m_Options.DefaultNear) + minDist = m_Options.DefaultNear; + else + minDist *= 0.99; + + maxDist *= 1.01; + } + + void FreeCamera::PushToCameraTransform() + { + // Updates the camera's transform matrix, that is, the matrix that brings + // the camera to the origin, with the camera view pointing down: + // +Y if this is a Zup camera, or + // -Z if this is a Yup camera . + + if (!m_CameraTransformDirty) + return; + + m_Camera.SetTransform(GfMatrix4d().SetTranslate(GfVec3d().ZAxis() * m_Dist) * + RotMatrix(GfVec3d().ZAxis(), -m_RotPsi) * + RotMatrix(GfVec3d().XAxis(), -m_RotPhi) * + RotMatrix(GfVec3d().YAxis(), -m_RotTheta) * + m_YZUpInvMatrix * + GfMatrix4d().SetTranslate(m_Center) + ); + + m_Camera.SetFocusDistance(m_Dist); + m_CameraTransformDirty = false; + } + + void FreeCamera::PullFromCameraTransform() + { + // Updates parameters (center, rotTheta, etc.) from the camera transform. + // + // reads the transform set on the camera and updates all the other + // parameters.This is the inverse of _pushToCameraTransform + + GfMatrix4d camTransfrom = m_Camera.GetTransform(); + float dist = m_Camera.GetFocusDistance(); + GfFrustum frustum = m_Camera.GetFrustum(); + GfVec3d camPos = frustum.GetPosition(); + GfVec3d camAxis = frustum.ComputeViewDirection(); + + // Compute translational parts + m_Dist = dist; + m_SelSize = dist / 10.0; + m_Center = camPos + dist * camAxis; + + // Compute rotational part + GfMatrix4d transform = camTransfrom * m_YZUpMatrix; + transform.Orthonormalize(); + GfRotation rotation = transform.ExtractRotation(); + + // Decompose and set angles + GfVec3d _decompose = -rotation.Decompose(GfVec3d().YAxis(), GfVec3d().XAxis(), GfVec3d().ZAxis()); + m_RotTheta = _decompose[0]; + m_RotPhi = _decompose[1]; + m_RotPsi = _decompose[2]; + + m_CameraTransformDirty = true; + } + +} \ No newline at end of file diff --git a/src/FlipScope/Usd/FreeCamera.h b/src/FlipScope/Usd/FreeCamera.h new file mode 100644 index 0000000..86087eb --- /dev/null +++ b/src/FlipScope/Usd/FreeCamera.h @@ -0,0 +1,82 @@ +#pragma once + +#include "pxr/pxr.h" +#include "pxr/base/gf/camera.h" +#include "pxr/base/gf/bbox3d.h" +#include "pxr/base/gf/frustum.h" +#include "pxr/base/tf/debug.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +namespace FSV +{ + struct CameraOptions + { + float DefaultNear = 1; + float DefaultFar = 2000000; + float MaxSafeZResolution = 1e6; + float MaxGoodZResolution = 5e4; + }; + + class FreeCamera + { + public: + + FreeCamera(CameraOptions option, bool isZUp, float fov); + ~FreeCamera(); + CameraOptions GetOption() { return m_Options; } + + GfCamera ComputeGfCamera(GfBBox3d stageBBox, bool autoClip); + void SetClippingPlanes(GfBBox3d stageBBox); + void ResetClipingPlanes(); + + void FrameSelection(GfBBox3d selBBox, float frameFit); + void SetClosestVisibleDistFromPoint(GfVec3d point); + + float ComputePixelsToWorldFactor(int viewportHeight); + + bool IsOrthographic(); + void SetProjection(GfCamera::Projection projection); + GfCamera::Projection GetProjection(); + + GfMatrix4d RotMatrix(GfVec3d &vec, double angle); + bool IsZUp() { return m_IsZUp; } + + float GetFov(); + void SetFov(float value); + + float GetNearClip(); + float GetFarClip(); + + private: + + void RangeOfBoxAlongRay(double &minDist, double &maxDist, GfRay camRay, GfBBox3d stageBBox); + void PushToCameraTransform(); + void PullFromCameraTransform(); + + CameraOptions m_Options; + GfCamera m_Camera; + + bool m_IsZUp; + float m_RotTheta; + float m_RotPhi; + float m_RotPsi; + + GfVec3d m_Center; + GfMatrix4d m_YZUpMatrix; + GfMatrix4d m_YZUpInvMatrix; + + float m_Dist; + float m_OverrideNear = -1; + float m_OverrideFar = -1; + + float m_ClosestVisibleDist = -1; + float m_LastFramedDist = -1; + float m_LastFramedClosestDist = -1; + + float m_Fov; + float m_SelSize; + + bool m_CameraTransformDirty = false; + }; +} diff --git a/src/FlipScope/Usd/HdRenderer.cpp b/src/FlipScope/Usd/HdRenderer.cpp new file mode 100644 index 0000000..1730571 --- /dev/null +++ b/src/FlipScope/Usd/HdRenderer.cpp @@ -0,0 +1 @@ +#include "pch.h" \ No newline at end of file diff --git a/src/FlipScope/Usd/HdRenderer.h b/src/FlipScope/Usd/HdRenderer.h new file mode 100644 index 0000000..ff6cb72 --- /dev/null +++ b/src/FlipScope/Usd/HdRenderer.h @@ -0,0 +1,61 @@ +#pragma once + +#include "pxr/pxr.h" +#include "pxr/usd/usd/stage.h" +#include "pxr/imaging/glf/drawTarget.h" +#include "pxr/imaging/hd/engine.h" +#include "pxr/imaging/hd/renderIndex.h" +#include "pxr/imaging/hd/rendererPlugin.h" +#include "pxr/imaging/hd/rprimCollection.h" +#include "pxr/imaging/hdSt/renderDelegate.h" +#include "pxr/imaging/hdx/taskController.h" + +#include "pxr/usdImaging/usdImagingGL/engine.h" + + +PXR_NAMESPACE_USING_DIRECTIVE + +using HgiUniquePtr = std::unique_ptr; + +namespace FSV +{ + class HdRenderer + { + public: + HdRenderer(uint32_t width, uint32_t height); + ~HdRenderer(); + private: + uint32_t _width, _height; + + GlfDrawTargetRefPtr _drawTarget; + + HgiUniquePtr _hgi; + HdEngine _engine; + HdRendererPlugin* _renderPlugin = nullptr; + HdxTaskController* _taskController = nullptr; + HdRenderIndex* _renderIndex = nullptr; + HdxSelectionTrackerSharedPtr _selectionTracker; + HdRprimCollection _renderCollection + { + HdTokens->geometry, + HdReprSelector(HdReprTokens->refined), + SdfPath::AbsoluteRootPath() + }; + HdRprimCollection _selectionCollection{ HdReprTokens->wire, + HdReprSelector(HdReprTokens->wire) }; + HdRprimCollection _pointSnappingCollection{ + HdTokens->geometry, + HdReprSelector(HdReprTokens->refined, TfToken(), HdReprTokens->points), + SdfPath::AbsoluteRootPath() + }; + + GlfSimpleLight _defaultLight; + GfVec4d _viewport; + + const bool _isUsingHdSt = false; + bool _initializationAttempted = false; + bool _initializationSucceeded = false; + bool _hasDefaultLighting = false; + bool _selectionChanged = true; + }; +} \ No newline at end of file diff --git a/src/FlipScope/Usd/HydraRenderer.cpp b/src/FlipScope/Usd/HydraRenderer.cpp new file mode 100644 index 0000000..455cb82 --- /dev/null +++ b/src/FlipScope/Usd/HydraRenderer.cpp @@ -0,0 +1,488 @@ +#include "pch.h" + +#include +//#include +#include + +#include "FlipScope/Core/Application.h" +#include "FlipScope/Usd/HydraRenderer.h" +#include "FlipScope/Core/Log.h" + +#include "pxr/pxr.h" +#include "pxr/usd/usd/prim.h" +#include "pxr/usd/usdGeom/metrics.h" +#include "pxr/usd/usdGeom/bboxCache.h" +#include "pxr/usd/usdGeom/tokens.h" +#include "pxr/imaging/glf/contextCaps.h" +#include "pxr/imaging/glf/simpleLightingContext.h" + + +PXR_NAMESPACE_USING_DIRECTIVE + +namespace FSV +{ + HydraRenderer::HydraRenderer(uint32_t width, uint32_t height) + :m_Width(width), m_Height(height) + { + m_Translate[0] = 0.0; + m_Translate[1] = 1000.0; + m_Translate[2] = 2500.0; + + } + + HydraRenderer::~HydraRenderer() + { + + } + + void HydraRenderer::Init(uint32_t width, uint32_t height) + { + GlfContextCaps::InitInstance(); + + // Build render target + m_DrawTarget = GlfDrawTarget::New(GfVec2i(GetWidth(), GetHeight())); + + m_DrawTarget->Bind(); + + m_DrawTarget->AddAttachment("color", GL_RGBA, GL_FLOAT, GL_RGBA); + m_DrawTarget->AddAttachment("depth", GL_DEPTH_COMPONENT, GL_FLOAT, GL_DEPTH_COMPONENT32F); + + m_Width = width; + m_Height = height; + + SetupRenderer(true); + + m_DrawTarget->Unbind(); + } + + void HydraRenderer::SetupRenderer(bool IsInit=false) + { + FS_INFO("SetupRenderer() : Setp UsdImagingGLEngine."); + + AppController& controller = Application::GetController(); + m_Stage = controller.GetStageDataModel()->GetStage(); + + //m_Stage = UsdStage::Open("C:/TEMP/Kitchen_set/Kitchen_set.usd"); + //m_Stage = UsdStage::CreateInMemory(""); + + SdfPathVector excludedPaths; + + if (UsdImagingGLEngine::IsHydraEnabled()) { + + FS_INFO("Using HD Renderer"); + m_Renderer.reset(new UsdImagingGLEngine(m_Stage->GetPseudoRoot().GetPath(), excludedPaths)); + if (!m_CurrentRenderer.empty()) + { + if (!m_Renderer->SetRendererPlugin(TfToken(m_CurrentRenderer))) + { + FS_ERROR("Couldn't set renderer plugin: {0}", m_CurrentRenderer); + } + else { + FS_INFO("Renderer plugin: {0}", m_CurrentRenderer); + } + } + } + else { + FS_INFO("Using Reference Renderer"); + m_Renderer.reset(new UsdImagingGLEngine(m_Stage->GetPseudoRoot().GetPath(), excludedPaths)); + } + + if (controller.IsStageChanged() || IsInit) + { + m_ShouldFrameAll = true; + + if (m_ShouldFrameAll) + { + TfTokenVector purposes; + purposes.push_back(UsdGeomTokens->default_); + purposes.push_back(UsdGeomTokens->proxy); + + bool useExtentHints = true; + UsdGeomBBoxCache bboxCache(UsdTimeCode::Default(), purposes, useExtentHints); + + GfBBox3d bbox = bboxCache.ComputeWorldBound(m_Stage->GetPseudoRoot()); + GfRange3d world = bbox.ComputeAlignedRange(); + + GfVec3d worldCenter = (world.GetMin() + world.GetMax()) / 2.0; + double worldSize = world.GetSize().GetLength(); + + if (UsdGeomGetStageUpAxis(m_Stage) == UsdGeomTokens->z) + { + m_Translate[0] = -worldCenter[0]; + m_Translate[1] = -worldCenter[2]; + m_Translate[2] = -worldCenter[1] - worldSize; + } + else { + m_Translate[0] = -worldCenter[0]; + m_Translate[1] = -worldCenter[1]; + m_Translate[2] = -worldCenter[2] - worldSize; + } + } + } + + if (IsEnabledLighting()) + { + if (UsdImagingGLEngine::IsHydraEnabled()) { + m_LightingContext = GlfSimpleLightingContext::New(); + GlfSimpleLight light; + + if (IsEnabledCameraLight()) { + + light.SetPosition(GfVec4f(m_Translate[0], m_Translate[2], m_Translate[1], 0)); + } + else + { + light.SetPosition(GfVec4f(0, -.5, .5, 0)); + } + light.SetDiffuse(GfVec4f(1, 1, 1, 1)); + light.SetAmbient(GfVec4f(0, 0, 0, 1)); + light.SetSpecular(GfVec4f(1, 1, 1, 1)); + GlfSimpleLightVector lights; + lights.push_back(light); + m_LightingContext->SetLights(lights); + + GlfSimpleMaterial material; + material.SetAmbient(GfVec4f(0.2, 0.2, 0.2, 1.0)); + material.SetDiffuse(GfVec4f(0.8, 0.8, 0.8, 1.0)); + material.SetSpecular(GfVec4f(0, 0, 0, 1)); + material.SetShininess(0.0001f); + m_LightingContext->SetMaterial(material); + m_LightingContext->SetSceneAmbient(GfVec4f(0.2, 0.2, 0.2, 1.0)); + + } + else { + + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + + if (IsEnabledCameraLight()) + { + float position[4] = { m_Translate[0], m_Translate[2], m_Translate[1], 0 }; + glLightfv(GL_LIGHT0, GL_POSITION, position); + + } + else + { + float position[4] = { 0,-.5,.5,0 }; + glLightfv(GL_LIGHT0, GL_POSITION, position); + } + } + } + + } + + uint32_t HydraRenderer::GetRendererID() + { + return m_DrawTarget->GetAttachment("color")->GetGlTextureName(); + } + + void HydraRenderer::Shutdown() + { + m_DrawTarget = GlfDrawTargetRefPtr(); + FS_INFO("Shutdown HydraEngine"); + m_Renderer->InvalidateBuffers(); + } + + void HydraRenderer::OnWindowResize(uint32_t width, uint32_t height) + { + if (width <= 0 || height <= 0) + return; + + m_Width = width; + m_Height = height; + //FS_INFO("OnWindowResize :: {}, {}", width, height); + OnRender(); + } + + void HydraRenderer::OnRender() + { + int width = GetWidth(); + int height = GetHeight(); + + //FS_INFO("OnRender :: {}, {}", width, height); + if (width <= 0 || height <= 0) + return; + + m_DrawTarget->Bind(); + m_DrawTarget->SetSize(GfVec2i(width, height)); + + // Draw Code Here + OnDraw(); + + m_DrawTarget->Unbind(); + + /* + //Blit color framebuffer to screen + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, m_DrawTarget->GetFramebufferId()); + + glBlitFramebuffer(0, 0, width, height, + 0, 0, width, height, + GL_COLOR_BUFFER_BIT, + GL_NEAREST); + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + */ + } + + void HydraRenderer::OnDraw() + { + int width = GetWidth(); + int height = GetHeight(); + //m_DrawTarget->SetSize(GfVec2i(width, height)); + //FS_INFO("HydraRenderer::Draw : {0}, {1}", width, height); + //m_DrawTarget->Bind(); + + + GfVec4d viewport(0, 0, width, height); + + if (GetCameraPath().empty()) + { + //FS_INFO("CameraPath Empty"); + + GfMatrix4d viewMatrix(1.0); + viewMatrix *= GfMatrix4d().SetRotate(GfRotation(GfVec3d(0, 1, 0), m_Rotate[0])); + viewMatrix *= GfMatrix4d().SetRotate(GfRotation(GfVec3d(1, 0, 0), m_Rotate[1])); + viewMatrix *= GfMatrix4d().SetTranslate(GfVec3d(m_Translate[0], m_Translate[1], m_Translate[2])); + + //FS_INFO("Camera Rotate [{0}, {1}]", m_Rotate[0], m_Rotate[1]); + //FS_INFO("Camera Translate [{0}, {1}, {2}]", m_Translate[0], m_Translate[1], m_Translate[2]); + + GfMatrix4d modelViewMatrix = viewMatrix; + if (UsdGeomGetStageUpAxis(m_Stage) == UsdGeomTokens->z) { + // rotate from z-up to y-up + modelViewMatrix = + GfMatrix4d().SetRotate(GfRotation(GfVec3d(1.0, 0.0, 0.0), -90.0)) * + modelViewMatrix; + } + + const double aspectRatio = double(width) / height; + GfFrustum frustum; + frustum.SetPerspective(60.0, aspectRatio, 1, 100000.0); + const GfMatrix4d projMatrix = frustum.ComputeProjectionMatrix(); + + m_Renderer->SetCameraState(modelViewMatrix, projMatrix); + + } else { + m_Renderer->SetCameraPath(SdfPath(GetCameraPath())); + } + + GfVec4f const &clearColor = GfVec4f(0.12f, 0.12f, 0.12f, 1.0f); + + m_Renderer->SetRenderViewport(viewport); + + m_RenderParams = UsdImagingGLRenderParams(); + m_RenderParams.enableLighting = true; + m_RenderParams.showGuides = true; + m_RenderParams.showRender = false; + m_RenderParams.showProxy = true; + m_RenderParams.clearColor = clearColor; + m_RenderParams.forceRefresh = true; + m_RenderParams.drawMode = UsdImagingGLDrawMode::DRAW_SHADED_SMOOTH; + //m_RenderParams.clipPlanes = + glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); + + if (GetCurrentRendererName() == "GL") + { + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + } + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glViewport(0, 0, width, height); + + m_Renderer->SetRendererAov(TfToken("color")); + + if (IsEnabledLighting()) + { + if (UsdImagingGLEngine::IsHydraEnabled()) + { + m_Renderer->SetLightingState(m_LightingContext); + } else { + m_Renderer->SetLightingStateFromOpenGL(); + } + } + /* + bool const clearOnlyOnce = true; + bool cleared = false; + int convergenceIterations = 0; + GLfloat clearDepth[1] = { 1.0f }; + + do { + convergenceIterations++; + + if (cleared && clearOnlyOnce) + { + // Don't clear the FBO + } else { + glClearBufferfv(GL_COLOR, 0, clearColor.data()); + glClearBufferfv(GL_DEPTH, 0, clearDepth); + cleared = true; + } + + m_Engine->Render(m_Stage->GetPseudoRoot(), m_RenderParams); + //m_Engine->InvalidateBuffers(); + + } while (!m_Engine->IsConverged());*/ + + m_Renderer->Render(m_Stage->GetPseudoRoot(), m_RenderParams); + + //glFinish(); + //m_DrawTarget->Unbind(); + //FS_INFO("Iterations to convergence: {}", convergenceIterations); + //glDisable(GL_DEPTH_TEST); + } + + void DrawAxis() + { + + } + + TfTokenVector HydraRenderer::GetRendererPlugins() + { + TfTokenVector rendererPlugins = m_Renderer->GetRendererPlugins(); + return rendererPlugins; + } + + std::vector HydraRenderer::GetRendererPluginsNames() + { + std::vector rendererPluginNames; + for (auto &plugin : GetRendererPlugins()) + { + rendererPluginNames.push_back(GetRenderer()->GetRendererDisplayName(plugin)); + } + return rendererPluginNames; + } + + TfToken HydraRenderer::GetCurrentRenderer() + { + return GetRenderer()->GetCurrentRendererId(); + } + + std::string HydraRenderer::GetCurrentRendererName() + { + //FS_INFO("GetCurrentRendererName : {}", GetCurrentRenderer().GetText()); + return GetRenderer()->GetRendererDisplayName(GetCurrentRenderer()); + } + + void HydraRenderer::SetCurrentRenderer(std::string rendererName) + { + TfToken rendererId; + for (auto &plugin : GetRendererPlugins()) + { + if (GetRenderer()->GetRendererDisplayName(plugin) == rendererName) + { + rendererId = plugin; + break; + } + } + + if (rendererId.IsEmpty()) + { + FS_WARN("Renderer name : \"{}\" not in register renderer plugin list, skip...", rendererName); + return; + } + m_CurrentRenderer = rendererId; + SetupRenderer(); + //GetEngine()->SetRendererPlugin(rendererId); + //GetEngine()->SetRendererAov(TfToken("color")); + } + + void HydraRenderer::SetCurrentRenderer(TfToken rendererId) + { + TfTokenVector rendererPlugins = GetRendererPlugins(); + auto it = std::find(rendererPlugins.begin(), rendererPlugins.end(), rendererId); + if (it == rendererPlugins.end()) + { + FS_WARN("Renderer plugin : \"{}\" not in register renderer plugin list, skip...", rendererId.GetString()); + return; + } + GetRenderer()->SetRendererPlugin(rendererId); + } + + bool HydraRenderer::WriteToFile(std::string const & attachment, std::string const & filename) + { + if (m_DrawTarget->IsBound()) + m_DrawTarget->Unbind(); + + bool result = m_DrawTarget->WriteToFile(attachment, filename); + + if (m_DrawTarget->IsBound()) + m_DrawTarget->Bind(); + + FS_INFO("Write {0} attachment to {1}", attachment, filename); + return result; + } + + void HydraRenderer::OnMousePress(bool button[], int x, int y, const int& modKeys) + { + FS_INFO("Mouse Press ({}, {}, {}) : {} : {}", button[0], button[1], button[2], x, y); + + m_MouseButton[0] = button[0]; + m_MouseButton[1] = button[1]; + m_MouseButton[2] = button[2]; + + if (modKeys & ImGuiKeyModFlags_Alt) + { + m_MousePos[0] = x; + m_MousePos[1] = y; + } + } + + void HydraRenderer::OnMouseRelease(bool button[], int x, int y, const int& modKeys) + { + FS_INFO("Mouse Release ({}, {}, {}) : {} : {}", button[0], button[1], button[2], x, y); + + m_MouseButton[0] = button[0]; + m_MouseButton[1] = button[1]; + m_MouseButton[2] = button[2]; + } + + void HydraRenderer::OnMouseMove(bool button[], int x, int y, const int& modKeys) + { + FS_INFO("Mouse Move Buttons : {0}, {1}, {2}", m_MouseButton[0], m_MouseButton[1], m_MouseButton[2]); + + int dx = x - m_MousePos[0]; + int dy = y - m_MousePos[1]; + + if (modKeys & ImGuiKeyModFlags_Alt) + { + if (m_MouseButton[0]) { + m_Rotate[0] += dx; + m_Rotate[1] += dy; + } + else if (m_MouseButton[2]) { + m_Translate[0] += dx; + m_Translate[1] -= dy; + } + else if (m_MouseButton[1]) { + m_Translate[2] += dx; + } + + m_MousePos[0] = x; + m_MousePos[1] = y; + } + } + + void HydraRenderer::ResolveCamera() + { + } + + void HydraRenderer::ComputePickFrustum(int x, int y) + { + } + + void HydraRenderer::PickObject(int x, int y, bool button[], const int & modKeys) + { + } + + void HydraRenderer::UpdateSelection() + { + + } +} \ No newline at end of file diff --git a/src/FlipScope/Usd/HydraRenderer.h b/src/FlipScope/Usd/HydraRenderer.h new file mode 100644 index 0000000..426c266 --- /dev/null +++ b/src/FlipScope/Usd/HydraRenderer.h @@ -0,0 +1,96 @@ +#pragma once + +#include "FlipScope/Core/AppController.h" +#include "FlipScope/Renderer/ViewportRenderer.h" + +#include "pxr/pxr.h" +#include "pxr/usd/usd/stage.h" +#include "pxr/imaging/glf/drawTarget.h" +#include "pxr/usdImaging/usdImagingGL/engine.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +namespace FSV +{ + class HydraRenderer + { + public: + HydraRenderer(uint32_t width, uint32_t height); + ~HydraRenderer(); + + virtual void Init(uint32_t width, uint32_t height); + virtual void SetupRenderer(bool IsInit); + virtual void Shutdown(); + + virtual uint32_t GetWidth() { return m_Width; } + virtual uint32_t GetHeight() { return m_Height; } + + UsdStageRefPtr GetStage() { return m_Stage; } + std::shared_ptr GetRenderer() { return m_Renderer; } + + virtual void OnWindowResize(uint32_t width, uint32_t height); + + virtual void OnRender(); + virtual void OnDraw(); + + void DrawAxis(); + + std::string GetCameraPath() { return m_CameraPath; } + + TfTokenVector GetRendererPlugins(); + std::vector GetRendererPluginsNames(); + TfToken GetCurrentRenderer(); + std::string GetCurrentRendererName(); + + void SetCurrentRenderer(std::string rendererName); + void SetCurrentRenderer(TfToken renderer); + + // Lighting Settings + bool IsEnabledLighting() { return m_EnabledLighting; } + void SetEnabledLighting(bool enabled) { m_EnabledLighting = enabled; } + bool IsEnabledCameraLight() { return m_EnabledCameraLight; } + void SetEnabledCameraLight(bool enabled) { m_EnabledCameraLight = enabled; } + + uint32_t GetRendererID(); + + bool WriteToFile(std::string const & attachment, std::string const & filename); + + void OnMousePress(bool button[], int x, int y, const int& modKeys); + void OnMouseRelease(bool button[], int x, int y, const int& modKeys); + void OnMouseMove(bool button[], int x, int y, const int& modKeys); + + void ResolveCamera(); + void ComputePickFrustum(int x, int y); + void PickObject(int x, int y, bool button[], const int& modKeys); + void UpdateSelection(); + + private: + uint32_t m_Width, m_Height = 0; + AppController *m_Controller; + + UsdStageRefPtr m_Stage; + + std::string m_CurrentRenderer; + std::shared_ptr m_Renderer; + + GlfDrawTargetRefPtr m_DrawTarget; + + UsdImagingGLRenderParams m_RenderParams; + + bool m_ShouldFrameAll = false; + + GlfSimpleLightingContextRefPtr m_LightingContext; + bool m_EnabledLighting = true; + bool m_EnabledCameraLight = false; + + // For Camera manipulate transform + std::string m_CameraPath; + + float m_Translate[3]; + float m_Rotate[2]; + + int m_MousePos[2]; + bool m_MouseButton[3]; + + }; +} \ No newline at end of file diff --git a/src/FlipScope/Usd/SelectionModel.cpp b/src/FlipScope/Usd/SelectionModel.cpp new file mode 100644 index 0000000..618217b --- /dev/null +++ b/src/FlipScope/Usd/SelectionModel.cpp @@ -0,0 +1,57 @@ +#include "pch.h" + +#include "FlipScope/Core/Log.h" +#include "FlipScope/Usd/SelectionModel.h" + +#include + +#include +#include + +FSV::SelectionModel::SelectionModel() +{ +} + +FSV::SelectionModel::~SelectionModel() +{ +} + +bool FSV::SelectionModel::IsSelected(UsdPrim& prim) +{ + if(HasPrim(prim)) + return true; + return false; +} + +void FSV::SelectionModel::AddSelection(UsdPrim& prim) +{ + Clear(); + //m_SelectionData.push_back(prim.GetPrimPath().GetString()); + AppendSelection(prim); + //FS_INFO("Add to Selection : {}, HasPrim : {}", prim.GetPrimPath().GetString(), HasPrim(prim)); +} + +void FSV::SelectionModel::AppendSelection(UsdPrim & prim) +{ + if (IsSelected(prim)) + return; + m_SelectionData.push_back(prim.GetPrimPath().GetString()); + m_SelectionPrimData.push_back(prim); + //FS_INFO("Append to Selection : {}", prim.GetPrimPath().GetString()); +} + +void FSV::SelectionModel::Clear() +{ + m_SelectionData.clear(); + m_SelectionPrimData.clear(); +} + +bool FSV::SelectionModel::HasPrim(UsdPrim & prim) +{ + return std::find(m_SelectionData.begin(), m_SelectionData.end(), prim.GetPrimPath().GetString()) != m_SelectionData.end(); +} + +UsdPrim& FSV::SelectionModel::CurrentSelection() +{ + return UsdPrim(); +} \ No newline at end of file diff --git a/src/FlipScope/Usd/SelectionModel.h b/src/FlipScope/Usd/SelectionModel.h new file mode 100644 index 0000000..a284051 --- /dev/null +++ b/src/FlipScope/Usd/SelectionModel.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include +#include +#include + +PXR_NAMESPACE_USING_DIRECTIVE + +namespace FSV +{ + typedef std::vector SelectionData; + typedef std::vector SelectionPrimData; + class SelectionModel + { + public: + SelectionModel(); + ~SelectionModel(); + + bool IsSelected(UsdPrim& prim); + + void AddSelection(UsdPrim& prim); + void AppendSelection(UsdPrim& prim); + SelectionData GetSelection() { return m_SelectionData; }; + UsdPrim& CurrentSelection(); + + void Clear(); + + private: + bool HasPrim(UsdPrim& prim); + + SelectionData m_SelectionData; + SelectionPrimData m_SelectionPrimData; + }; +} \ No newline at end of file diff --git a/src/FlipScope/Usd/StageDataModel.cpp b/src/FlipScope/Usd/StageDataModel.cpp new file mode 100644 index 0000000..1e7a570 --- /dev/null +++ b/src/FlipScope/Usd/StageDataModel.cpp @@ -0,0 +1,105 @@ +#include "pch.h" + +#include "FlipScope/Usd/StageDataModel.h" + +#include "pxr/pxr.h" +#include "pxr/usd/usdGeom/tokens.h" +#include "pxr/usd/usd/notice.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +namespace FSV +{ + StageDataModel::StageDataModel() + { + TfTokenVector includedPurposes; + includedPurposes.push_back(UsdGeomTokens->default_); + includedPurposes.push_back(UsdGeomTokens->proxy); + m_BboxCache = std::make_shared(GetCurrentFrame(), includedPurposes); + + m_XformCache = std::make_shared(); + //m_Stage = UsdStage::CreateNew("C:/Temp/Test.usd"); + //m_Stage = UsdStage::Open("C:/TEMP/Kitchen_set/Kitchen_set.usd"); + //SetStage(UsdStage::Open("C:/TEMP/Kitchen_set/Kitchen_set.usd")); + } + + StageDataModel::~StageDataModel() + { + } + + void StageDataModel::SetStage(UsdStageRefPtr stage) + { + m_StageNoticeListener.SetStage(UsdStageWeakPtr()); + m_StageNoticeListener.SetStageContentsChangedCallback(nullptr); + m_StageNoticeListener.SetStageObjectsChangedCallback(nullptr); + + m_Stage = stage; + + m_StageNoticeListener.SetStage(stage); + m_StageNoticeListener.SetStageContentsChangedCallback( + std::bind(&StageDataModel::OnStageContentChanged, + this, + std::placeholders::_1)); + + m_StageNoticeListener.SetStageObjectsChangedCallback( + std::bind(&StageDataModel::OnStageObjectChanged, + this, + std::placeholders::_1)); + } + + void StageDataModel::GetStageCamera() + { + } + + void StageDataModel::SetCurrentFrame(double value) + { + m_CurrentFrame = UsdTimeCode(value); + m_BboxCache->SetTime(m_CurrentFrame); + m_XformCache->SetTime(m_CurrentFrame); + } + + TfTokenVector StageDataModel::GetIncludedPurposes() + { + return m_BboxCache->GetIncludedPurposes(); + } + + void StageDataModel::SetIncludedPurposes(TfTokenVector includedPurposes) + { + m_BboxCache->SetIncludedPurposes(includedPurposes); + } + + GfBBox3d StageDataModel::ComputeWorldBound(const UsdPrim & prim) + { + return m_BboxCache->ComputeWorldBound(prim); + } + + GfMatrix4d StageDataModel::GetLocalToWorldTransform(const UsdPrim & prim) + { + return m_XformCache->GetLocalToWorldTransform(prim); + } + + UsdShadeMaterial StageDataModel::ComputeBoundMaterial(const UsdPrim & prim) + { + return UsdShadeMaterialBindingAPI(prim).ComputeBoundMaterial(); + } + + void StageDataModel::OnStageContentChanged(const UsdNotice::StageContentsChanged & notice) + { + } + + void StageDataModel::OnStageObjectChanged(const UsdNotice::ObjectsChanged & notice) + { + /*for (auto i : notice.GetResyncedPaths()) { + }*/ + } + + void StageDataModel::ClearCaches() + { + m_BboxCache->Clear(); + m_XformCache->Clear(); + } + std::unique_ptr StageDataModel::Create() + { + return std::make_unique(); + } +} \ No newline at end of file diff --git a/src/FlipScope/Usd/StageDataModel.h b/src/FlipScope/Usd/StageDataModel.h new file mode 100644 index 0000000..e3bb843 --- /dev/null +++ b/src/FlipScope/Usd/StageDataModel.h @@ -0,0 +1,72 @@ +#pragma once + +#include "pch.h" + +#include "pxr/pxr.h" +#include "pxr/usd/usd/timecode.h" +#include "pxr/usd/usd/stage.h" +#include "pxr/usd/usdGeom/bboxCache.h" +#include "pxr/usd/usdGeom/xformCache.h" +#include "pxr/base/tf/notice.h" +#include "pxr/usd/usdShade/materialBindingAPI.h" + +#include "FlipScope/Usd/StageNoticeListener.h" +#include "FlipScope/Usd/SelectionModel.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +namespace FSV +{ + class StageDataModel + { + public: + StageDataModel(); + ~StageDataModel(); + + UsdStageRefPtr GetStage() { return m_Stage; }; + void SetStage(UsdStageRefPtr stage); + + std::string GetStageFilePath() { return m_StageFilePath; } + void SetStageFilePath(std::string filePath) { m_StageFilePath = filePath; } + + void GetStageCamera(); + + UsdTimeCode GetCurrentFrame() { return m_CurrentFrame; }; + void SetCurrentFrame(double value); + + TfTokenVector GetIncludedPurposes(); + void SetIncludedPurposes(TfTokenVector includedPurposes); + //void OnPrimChanged(UsdNotice::ObjectsChanged ¬ice, UsdStageWeakPtr &stage); + + GfBBox3d ComputeWorldBound(const UsdPrim& prim) ; + GfMatrix4d GetLocalToWorldTransform(const UsdPrim& prim); + UsdShadeMaterial ComputeBoundMaterial(const UsdPrim& prim); + + void OnStageContentChanged(const UsdNotice::StageContentsChanged& notice); + void OnStageObjectChanged(const UsdNotice::ObjectsChanged& notice); + + bool IsPlaying() { return m_Playing; }; + void SetPlaying(bool playing) { m_Playing = playing; }; + + void ClearCaches(); + + static std::unique_ptr Create(); + + SelectionModel& GetSelectionModel() { return m_SelectionModel; } + + private: + UsdTimeCode m_CurrentFrame = UsdTimeCode::Default(); + UsdStageRefPtr m_Stage; + + std::string m_StageFilePath; + + std::shared_ptr m_BboxCache; + std::shared_ptr m_XformCache; + + StageNoticeListener m_StageNoticeListener; + + SelectionModel m_SelectionModel; + + bool m_Playing; + }; +} diff --git a/src/FlipScope/Usd/StageNoticeListener.cpp b/src/FlipScope/Usd/StageNoticeListener.cpp new file mode 100644 index 0000000..f6a5973 --- /dev/null +++ b/src/FlipScope/Usd/StageNoticeListener.cpp @@ -0,0 +1,90 @@ +#include "pch.h" + +#include "FlipScope/Usd/StageNoticeListener.h" + +#include "pxr/pxr.h" +#include "pxr/base/tf/notice.h" +#include "pxr/base/tf/weakBase.h" +#include "pxr/usd/usd/notice.h" +#include "pxr/usd/usd/stage.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +namespace FSV +{ + StageNoticeListener::~StageNoticeListener() + { + if (m_StageContentsChangedKey.IsValid()) { + TfNotice::Revoke(m_StageContentsChangedKey); + } + if (m_StageObjectsChangedKey.IsValid()) { + TfNotice::Revoke(m_StageObjectsChangedKey); + } + + } + + void StageNoticeListener::SetStage(const UsdStageWeakPtr & stage) + { + m_Stage = stage; + UpdateStageContentsChangedRegistration(); + } + + void StageNoticeListener::SetStageContentsChangedCallback(const StageContentsChangedCallback & callback) + { + m_StageContentsChangedCallback = callback; + UpdateStageContentsChangedRegistration(); + } + + void StageNoticeListener::SetStageObjectsChangedCallback(const StageObjectsChangedCallback & callback) + { + m_StageObjectsChangedCallback = callback; + } + + void StageNoticeListener::UpdateStageContentsChangedRegistration() + { + if (m_Stage && m_StageContentsChangedCallback) { + // Register for notices if we're not already listening. + if (!m_StageContentsChangedKey.IsValid()) { + m_StageContentsChangedKey = TfNotice::Register( TfCreateWeakPtr(this), &StageNoticeListener::OnStageContentsChanged); + } + + } + else { + // Either the stage or the callback is invalid, so stop listening for + // notices. + if (m_StageContentsChangedKey.IsValid()) { + TfNotice::Revoke(m_StageContentsChangedKey); + } + } + + if (m_Stage && m_StageObjectsChangedCallback) { + + // Register for notices if we're not already listening. + if (!m_StageObjectsChangedKey.IsValid()) { + m_StageObjectsChangedKey = + TfNotice::Register(TfCreateWeakPtr(this), &StageNoticeListener::OnStageObjectsChanged, m_Stage); + } + } + else { + if (m_StageObjectsChangedKey.IsValid()) { + TfNotice::Revoke(m_StageObjectsChangedKey); + } + } + } + + void StageNoticeListener::OnStageContentsChanged(const UsdNotice::StageContentsChanged & notice) const + { + if (notice.GetStage() == m_Stage && m_StageContentsChangedCallback) + { + m_StageContentsChangedCallback(notice); + } + } + + void StageNoticeListener::OnStageObjectsChanged(const UsdNotice::ObjectsChanged & notice, const UsdStageWeakPtr & sender) const + { + if (notice.GetStage() == m_Stage && m_StageObjectsChangedCallback) + { + m_StageObjectsChangedCallback(notice); + } + } +} \ No newline at end of file diff --git a/src/FlipScope/Usd/StageNoticeListener.h b/src/FlipScope/Usd/StageNoticeListener.h new file mode 100644 index 0000000..ee4f782 --- /dev/null +++ b/src/FlipScope/Usd/StageNoticeListener.h @@ -0,0 +1,45 @@ +#pragma once + +#include "pch.h" + +#include "pxr/pxr.h" +#include "pxr/base/tf/notice.h" +#include "pxr/base/tf/weakBase.h" +#include "pxr/usd/usd/notice.h" +#include "pxr/usd/usd/stage.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +namespace FSV +{ + class StageNoticeListener : public TfWeakBase + { + public: + StageNoticeListener() = default; + virtual ~StageNoticeListener(); + + void SetStage(const UsdStageWeakPtr& stage); + + using StageContentsChangedCallback = std::function; + using StageObjectsChangedCallback = std::function; + + void SetStageContentsChangedCallback( const StageContentsChangedCallback& callback ); + void SetStageObjectsChangedCallback( const StageObjectsChangedCallback& callback ); + + + private: + UsdStageWeakPtr m_Stage; + StageNoticeListener(const StageNoticeListener&) = delete; + + TfNotice::Key m_StageContentsChangedKey{}; + StageContentsChangedCallback m_StageContentsChangedCallback{}; + + TfNotice::Key m_StageObjectsChangedKey{}; + StageObjectsChangedCallback m_StageObjectsChangedCallback{}; + + void UpdateStageContentsChangedRegistration(); + void OnStageContentsChanged( const UsdNotice::StageContentsChanged& notice) const; + void OnStageObjectsChanged( const UsdNotice::ObjectsChanged& notice, const UsdStageWeakPtr& sender) const; + + }; +} \ No newline at end of file diff --git a/src/FlipScope/Usd/ViewSettings.cpp b/src/FlipScope/Usd/ViewSettings.cpp new file mode 100644 index 0000000..4f21d30 --- /dev/null +++ b/src/FlipScope/Usd/ViewSettings.cpp @@ -0,0 +1,25 @@ +#include "pch.h" + +#include "ViewSettings.h" + +namespace FSV +{ + ViewSettings::ViewSettings(Settings settings) + { + } + + ViewSettings::~ViewSettings() + { + } + + bool ViewSettings::SaveSettings() + { + return true; + } + + bool ViewSettings::LoadSettings() + { + return true; + } +} + diff --git a/src/FlipScope/Usd/ViewSettings.h b/src/FlipScope/Usd/ViewSettings.h new file mode 100644 index 0000000..bac7657 --- /dev/null +++ b/src/FlipScope/Usd/ViewSettings.h @@ -0,0 +1,69 @@ +#pragma once + +#include "pxr/pxr.h" +#include "pxr/base/gf/vec4f.h" +#include "pxr/usdImaging/usdImagingGL/renderParams.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +namespace FSV +{ + const char* colorCorrectModes[] = { "disabled", "sRGB", "openColorIO" }; + enum ColorCorrectModes + { + DISABLE, + SRGB, + OPENCOLORIO + }; + const char* pickModes[] = {"Prims", "Models", "Instances", "Prototypes"}; + enum PickModes + { + PRIMS, + MODELS, + INSTANCES, + PROTOTYPES + }; + const char* selectionHightlightModes[] = { "Never", "Only when paused", "Always" }; + struct Settings + { + UsdImagingGLDrawMode renderMode = UsdImagingGLDrawMode::DRAW_SHADED_SMOOTH; + float freeCameraFOV = 60.0; + TfToken colorCorrectionMode = TfToken(colorCorrectModes[ColorCorrectModes::SRGB]); + GfVec4f highlightColor = { 1.0, 1.0, 0.0, 0.5 }; + GfVec4f backgroundColor = {}; + bool cameraLightEnabled = true; + bool domeLightEnabled = false; + bool ambientLightOnly = true; + TfToken pickMode = TfToken(pickModes[PickModes::PRIMS]); + bool showBBoxes = true; + bool showAABBoxes = true; + bool displayGuide = false; + bool displayProxy = true; + bool displayRender = false; + bool enableSceneMaterials = true; + bool showInactivePrims = true; + bool showMasterPrims = false; + bool showUndefinedPrims = false; + bool showAbstractPrims = false; + bool showHUD = true; + + + }; + + class ViewSettings + { + public: + ViewSettings(Settings settings); + ~ViewSettings(); + + Settings Get() { return m_Settings; } + void Set(Settings settings) { m_Settings = settings; } + + bool SaveSettings(); + bool LoadSettings(); + + private: + Settings m_Settings; + + }; +} diff --git a/src/FlipScope/Widgets/ShotView.cpp b/src/FlipScope/Widgets/ShotView.cpp new file mode 100644 index 0000000..54f8391 --- /dev/null +++ b/src/FlipScope/Widgets/ShotView.cpp @@ -0,0 +1,177 @@ +#include "pch.h" + +#include "ShotView.h" + +#include "FlipScope/Core/Application.h" + +#include "FlipScope/Pipeline/ProjectInfo.h" +#include "FlipScope/Pipeline/Project.h" + +#include + + +namespace FSV +{ + ShotView::ShotView() + { + } + ShotView::~ShotView() + { + } + void ShotView::Show(bool * p_open) + { + ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + if (!ImGui::Begin("Shots", p_open)) + { + ImGui::End(); + return; + } + + ImGui::PopStyleVar(); + + ProjectInfo projectInfo = Application::GetProjectInfo(); + static ProjectList projectList = projectInfo.GetUserProjects(); + + static Project* currentProject = nullptr; + + static std::string currentEpisodeName; + static StringList episodeNameList; + + static std::string currentShotName; + static ShotList shotList; + + if (currentProject == nullptr && projectList.size()) + { + currentProject = &projectList[0]; + episodeNameList = currentProject->GetEpisodeNameList(); + if (episodeNameList.size() && !currentEpisodeName.length()) + { + currentEpisodeName = episodeNameList[0]; + shotList = currentProject->GetShotListByEpisode(currentEpisodeName); + } + } + + if (ImGui::BeginCombo("Project", currentProject->GetAliasName().c_str(), (ImGuiComboFlags)projectList.size())) + { + for (int n = 0; n < projectList.size(); n++) + { + bool is_selected = (currentProject->GetAliasName() == projectList[n].GetAliasName()); + if (ImGui::Selectable(projectList[n].GetAliasName().c_str(), is_selected)) + { + currentProject = &projectList[n]; + + // Reload Episode List + episodeNameList = currentProject->GetEpisodeNameList(); + currentEpisodeName = ""; + currentShotName = ""; + if (episodeNameList.size() && !currentEpisodeName.length()) + { + currentEpisodeName = episodeNameList[0]; + + // Reload Shot List + shotList = currentProject->GetShotListByEpisode(currentEpisodeName); + if (shotList.size() && !currentShotName.length()) + { + currentShotName = shotList[0].GetName(); + } + } + FS_INFO("{0}", projectList[n].GetAliasName().c_str()); + } + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } + + if (ImGui::BeginCombo("Episode", currentEpisodeName.c_str(), (ImGuiComboFlags)episodeNameList.size())) + { + for (int n = 0; n < episodeNameList.size(); n++) + { + bool is_selected = (currentEpisodeName == episodeNameList[n]); + if (ImGui::Selectable(episodeNameList[n].c_str(), is_selected)) + { + currentEpisodeName = episodeNameList[n]; + shotList = currentProject->GetShotListByEpisode(currentEpisodeName); + // Reload Shot List + currentShotName = ""; + shotList = currentProject->GetShotListByEpisode(currentEpisodeName); + if (shotList.size() && !currentShotName.length()) + { + currentShotName = shotList[0].GetName(); + } + FS_INFO("Current Episode : {0}", currentEpisodeName); + } + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } + + /*for (int n = 0; n < shotList.size(); n++) + { + FS_INFO("{0} : Shot : {1}", currentEpisodeName, shotList[n].GetName()); + }*/ + /*if (ImGui::BeginCombo("Shot", currentShotName.c_str(), shotList.size())) + { + for (int n = 0; n < shotList.size(); n++) + { + bool is_selected = (currentShotName == shotList[n].GetName()); + if (ImGui::Selectable(shotList[n].GetName().c_str(), is_selected)) + { + currentShotName = shotList[n].GetName(); + } + + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + }*/ + + ImGui::ListBoxHeader("Shots"); + for (auto shot : shotList) + { + bool is_selected = (currentShotName == shot.GetName()); + if (ImGui::Selectable(shot.GetName().c_str(), is_selected)) + { + currentShotName = shot.GetName(); + } + } + ImGui::ListBoxFooter(); + + const char* stage_items[] = { "Lay", "Ani", "Lgt", "Sim" }; + static const char* stage_item_current = stage_items[0]; + if (ImGui::BeginCombo("Stage", stage_item_current, IM_ARRAYSIZE(stage_items))) + { + for (int n = 0; n < IM_ARRAYSIZE(stage_items); n++) + { + bool is_selected = (stage_item_current == stage_items[n]); + if (ImGui::Selectable(stage_items[n], is_selected)) + stage_item_current = stage_items[n]; + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } + /*StringList shotNames = current_project.GetProjectData().GetEpisodeShotNameList(episode_item_current); + FS_INFO("{0} : {1}", episode_item_current, shotNames.size()); + std::string shot_item_current = shotNames.size() ? shotNames[0] : ""; + if (ImGui::BeginCombo("Shots", shot_item_current.c_str(), shotNames.size())) + { + for (int n = 0; n < shotNames.size(); n++) + { + bool is_selected = (shot_item_current == shotNames[n]); + if (ImGui::Selectable(shotNames[n].c_str(), is_selected)) + { + shot_item_current = shotNames[n]; + FS_INFO("Current Shot : {0}", shot_item_current); + } + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + + }*/ + ImGui::End(); + } +} \ No newline at end of file diff --git a/src/FlipScope/Widgets/ShotView.h b/src/FlipScope/Widgets/ShotView.h new file mode 100644 index 0000000..2c75582 --- /dev/null +++ b/src/FlipScope/Widgets/ShotView.h @@ -0,0 +1,13 @@ +#pragma once + +namespace FSV +{ + class ShotView + { + public: + ShotView(); + ~ShotView(); + + void Show(bool *p_open); + }; +} \ No newline at end of file diff --git a/src/FlipScope/Widgets/StageView.cpp b/src/FlipScope/Widgets/StageView.cpp new file mode 100644 index 0000000..4e7d06c --- /dev/null +++ b/src/FlipScope/Widgets/StageView.cpp @@ -0,0 +1,358 @@ +#include "pch.h" + +#include +#include +#include + +#include "FlipScope/Core/Application.h" +#include "FlipScope/Core/AppController.h" +#include "FlipScope/Widgets/StageView.h" + +#include +#include + +namespace FSV +{ + StageView::StageView() + { + } + + StageView::~StageView() + { + } + + void StageView::InitToolBar() + { + AppController& controller = Application::GetController(); + + if (ImGui::Button(ICON_FA_PLUS, ImVec2(26.0f, 24.0f))) + { + ImGui::OpenPopup("Create Prim"); + } + + if (ImGui::BeginPopupModal("Create Prim", NULL, ImGuiWindowFlags_AlwaysAutoResize)) + { + static char primName[128] = ""; + static char primTypeName[64] = ""; + static bool useOverPrim = false; + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + ImGui::PopStyleVar(); + ImGui::InputTextWithHint("Path", "Prim path start with /", primName, IM_ARRAYSIZE(primName)); + ImGui::Checkbox("Override", &useOverPrim); + const char* stage_items[] = { "Xform", "Mesh", "Light", "Camera" }; + static const char* stage_item_current = stage_items[0]; + + if (useOverPrim) + { + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); + } + + if (ImGui::BeginCombo("Type", stage_item_current, IM_ARRAYSIZE(stage_items))) + { + for (int n = 0; n < IM_ARRAYSIZE(stage_items); n++) + { + bool is_selected = (stage_item_current == stage_items[n]); + if (ImGui::Selectable(stage_items[n], is_selected)) + stage_item_current = stage_items[n]; + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } + + if (useOverPrim) + { + ImGui::PopItemFlag(); + ImGui::PopStyleVar(); + } + + if (ImGui::Button("OK", ImVec2(120, 0))) { + controller.CreatePrim(primName, stage_item_current); + ImGui::CloseCurrentPopup(); + } + ImGui::SetItemDefaultFocus(); + ImGui::SameLine(); + if (ImGui::Button("Cancel", ImVec2(120, 0))) { + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + + /*if (ImGui::MenuItem("Override Prim", "Alt+O", false, true)) + { + controller.CreateOverridePrim("/refPath"); + }*/ + + ImGui::SameLine(0.0, 2.0); + ImGui::Button(ICON_FA_MINUS, ImVec2(26.0f, 24.0f)); + ImGui::Separator(); + } + + void StageView::BuildTreeNode(UsdPrim &prim) + { + /*if (prim.GetChildren().empty()) + { + ImGui::AlignTextToFramePadding(); + ImGui::Selectable(prim.GetName().GetText()); + //ImGui::Selectable(ICON_FA_HOME); + ImGui::NextColumn(); + ImGui::Text(prim.GetTypeName().GetText()); + ImGui::NextColumn(); + }*/ + ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth; + AppController& controller = Application::GetController(); + static SelectionModel selectionModel = controller.GetStageDataModel()->GetSelectionModel(); + + for (auto &p : prim.GetChildren()) + { + + ImGui::AlignTextToFramePadding(); + ImGuiTreeNodeFlags node_flags = base_flags; + + if (!p.GetChildren()) { + node_flags = ImGuiTreeNodeFlags_Leaf; + } + + //const bool is_selected = selectionModel.HasPrim(p); + + if (selectionModel.IsSelected(p)){ + node_flags |= ImGuiTreeNodeFlags_Selected; + } + + //bool p_open = ImGui::TreeNodeEx(ICON_FA_CUBE + p.GetName().GetText(), node_flags); + char treeText[1024]; + //sprintf(treeText, "%s %s", ICON_FA_CUBE, p.GetName().GetText()); + //sprintf(treeText, "%sXX", p.GetName().GetText()); + //bool p_open = ImGui::TreeNodeEx(treeText, node_flags); + + bool p_open = ImGui::TreeNodeEx(p.GetName().GetText(), node_flags); + /*ImGui::SameLine(); + if (p.GetTypeName().GetString() == "Xform") { + ImGui::TextColored(ImVec4(0.0, 1.0, 0.5, 1.0), ICON_FA_ASTERISK); + } + else if (p.GetTypeName().GetString() == "Mesh") { + //ImGui::Text(ICON_FA_SHAPES); + ImGui::TextColored(ImVec4(0.0, 0.5, 0.8, 1.0), ICON_FA_CUBE); + } + else if (p.GetTypeName().GetString() == "Camera") { + ImGui::TextColored(ImVec4(0.0, 0.5, 0.8, 1.0), ICON_FA_CAMERA); + } + ImGui::SameLine(); + ImGui::Text(p.GetName().GetText()); + */ + //ImGui::SameLine(); + //bool p_open = ImGui::TreeNodeEx(&p, node_flags, p.GetName().GetText()); + + ImGui::NextColumn(); + + if (ImGui::IsItemClicked()) + { + if (ImGui::GetIO().KeyCtrl) { + selectionModel.AppendSelection(p); // Append selection + } else { + selectionModel.AddSelection(p); // Add selection + } + } + + // Some usaful icon + // ICON_FA_SHAPES - + // ICON_FA_LINK - Reference + /*ImGui::AlignTextToFramePadding(); + if (p.GetTypeName().GetString() == "Xform") { + ImGui::TextColored(ImVec4(0.0, 1.0, 0.5, 1.0), ICON_FA_ASTERISK); + } + else if (p.GetTypeName().GetString() == "Mesh") { + //ImGui::Text(ICON_FA_SHAPES); + ImGui::TextColored(ImVec4(0.0, 0.5, 0.8, 1.0), ICON_FA_CUBE); + } + else if (p.GetTypeName().GetString() == "Camera") { + ImGui::TextColored(ImVec4(0.0, 0.5, 0.8, 1.0), ICON_FA_CAMERA); + }*/ + /*node_flags = ImGuiTreeNodeFlags_Leaf; + + if (selectionModel.IsSelected(p)) { + node_flags |= ImGuiTreeNodeFlags_Selected; + }*/ + //ImGui::TreeNodeEx(p.GetTypeName().GetText(), node_flags); + + /*ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_None; + ImGuiIO& io = ImGui::GetIO(); + ImGuiStyle& style = ImGui::GetStyle(); + float font_size = ImGui::GetFontSize(); + //ImGui::AlignTextToFramePadding(); + ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.0, 0.5)); + ImGui::Selectable(p.GetTypeName().GetText(), selectionModel.IsSelected(p), selectable_flags, ImVec2(ImGui::GetColumnWidth(), font_size+ (style.FramePadding.y * 2) - 2)); + ImGui::PopStyleVar(); + //ImGui::SameLine();*/ + ImGui::AlignTextToFramePadding(); + char PrimTypeText[1024]; + auto PrimTypeColor = ImVec4(1.0, 1.0, 1.5, 1.0); + if (p.GetTypeName().GetString() == "Xform") + { + PrimTypeColor = ImVec4(0.0, 1.0, 0.5, 1.0); + sprintf(PrimTypeText, "%s %s", ICON_FA_ASTERISK, p.GetTypeName().GetText()); + } + else if (p.GetTypeName().GetString() == "Mesh") + { + PrimTypeColor = ImVec4(0.0, 0.5, 0.8, 1.0); + sprintf(PrimTypeText, "%s %s", ICON_FA_CUBE, p.GetTypeName().GetText()); + } + else if (p.GetTypeName().GetString() == "Camera") + { + PrimTypeColor = ImVec4(0.0, 0.5, 0.8, 1.0); + sprintf(PrimTypeText, "%s %s", ICON_FA_CAMERA, p.GetTypeName().GetText()); + } + else { + sprintf(PrimTypeText, "%s", p.GetTypeName().GetText()); + } + + //ImGui::TextColored(PrimTypeColor, PrimTypeText); + ImGui::SetItemAllowOverlap(); + //ImGui::Selectable(PrimTypeText, selectionModel.IsSelected(p), ImGuiSelectableFlags_SpanAllColumns); + ImGui::Selectable(PrimTypeText, selectionModel.IsSelected(p)); + + //ImGui::Text(p.GetTypeName().GetText()); + ImGui::NextColumn(); + //ImGui::SetItemAllowOverlap(); + + /*auto primSpec = p.GetPrimDefinition(); + static bool isChecked = !primSpec->GetHidden(); + char chk_name[1024]; + sprintf(chk_name, "%s", p.GetPath().GetText()); + if (ImGui::Checkbox(chk_name, &isChecked)) + { + FS_INFO("Changed {}:{}", p.GetPath().GetText(), isChecked); + //isChecked ? p.SetHidden(true) : p.SetHidden(false); + isChecked ? primSpec->SetHidden(true) : primSpec->SetHidden(false); + }*/ + + constexpr const char* inheritedIcon = ICON_FA_EYE; + UsdGeomImageable imageable(prim); + + if (imageable) { + VtValue visibleValue; + auto attr = imageable.GetVisibilityAttr(); + if (attr.HasAuthoredValue()) { + attr.Get(&visibleValue); + const TfToken& visibilityToken = visibleValue.Get(); + const char* icon = visibilityToken == UsdGeomTokens->invisible + ? ICON_FA_EYE_SLASH : inheritedIcon; + if (ImGui::SmallButton(icon)) { + UsdTimeCode tc = UsdTimeCode::Default(); + if (visibilityToken == UsdGeomTokens->inherited) { + attr.Set(VtValue(UsdGeomTokens->invisible), tc); + } + else if (visibilityToken == UsdGeomTokens->invisible) + { + prim.RemoveProperty(attr.GetName()); + } + } + } + else { + if (ImGui::SmallButton(inheritedIcon)) { + UsdTimeCode tc = UsdTimeCode::Default(); + attr.Set(VtValue(UsdGeomTokens->inherited), tc); + } + } + } + + + //ImGui::SmallButton("") + ImGui::NextColumn(); + + if(p_open){ + BuildTreeNode(p); + ImGui::TreePop(); + } + } + } + + void StageView::BuildOutliner() + { + AppController& controller = Application::GetController(); + constexpr ImGuiTableFlags tableFlags = ImGuiTableFlags_SizingFixedFit | /*ImGuiTableFlags_RowBg |*/ ImGuiTableFlags_ScrollY | ImGuiTableFlags_Resizable; + /*if (ImGui::BeginTable("##DrawStageOutliner", 3, tableFlags)) { + ImGui::TableSetupScrollFreeze(3, 1); // Freeze the root node of the tree (the layer) + ImGui::TableSetupColumn("Hierarchy"); + ImGui::TableSetupColumn("V", ImGuiTableColumnFlags_WidthFixed, 40); + ImGui::TableSetupColumn("Type"); + + UsdPrim rootPrim = controller.GetStageDataModel()->GetStage()->GetPseudoRoot(); + SdfLayerHandle layer = controller.GetStageDataModel()->GetStage()->GetSessionLayer(); + + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + ImGuiTreeNodeFlags nodeflags = ImGuiTreeNodeFlags_OpenOnArrow; + + ImGuiListClipper clipper; + + + ImGui::EndTable(); + }*/ + if (ImGui::BeginTable("split2", 3, ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody)) + { + //ImGui::TableSetupScrollFreeze(3, 1); // Freeze the root node of the tree (the layer) + ImGui::TableSetupColumn("Hierarchy", ImGuiTableColumnFlags_NoHide); + ImGui::TableSetupColumn("V", ImGuiTableColumnFlags_WidthFixed, 40); + ImGui::TableSetupColumn("Type"); + ImGui::TableHeadersRow(); + static bool selected[10] = {}; + for (int i = 0; i < 10; i++) + { + char label[32]; + sprintf(label, "Item %d", i); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Selectable(label, &selected[i], ImGuiSelectableFlags_SpanAllColumns); + ImGui::TableNextColumn(); + ImGui::Text("Some other contents"); + ImGui::TableNextColumn(); + ImGui::Text("123456"); + } + ImGui::EndTable(); + } + } + + void StageView::BuildTreeItem(UsdPrim& prim) + { + + } + + void StageView::Show(bool *p_open) + { + AppController& controller = Application::GetController(); + controller.GetStageDataModel()->GetStage(); + + ImGuiIO& io = ImGui::GetIO(); + ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 2)); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0, 4)); + + if (!ImGui::Begin("Stage", p_open)) + { + ImGui::End(); + return; + } + //InitToolBar(); + + BuildOutliner(); + /*ImGui::Columns(3, "tree", true); + ImGui::Text("Path"); + ImGui::NextColumn(); + + ImGui::Text("Type"); + ImGui::NextColumn(); + + ImGui::Text(ICON_FA_EYE); + ImGui::NextColumn(); + + BuildTreeNode(controller.GetStageDataModel()->GetStage()->GetPseudoRoot()); + */ + //ImGui::Columns(1); + ImGui::PopStyleVar(3); + ImGui::End(); + } +} + diff --git a/src/FlipScope/Widgets/StageView.h b/src/FlipScope/Widgets/StageView.h new file mode 100644 index 0000000..e4182a8 --- /dev/null +++ b/src/FlipScope/Widgets/StageView.h @@ -0,0 +1,29 @@ +#pragma once + +#include "FlipScope/Usd/StageDataModel.h" + + +#include +#include + +PXR_NAMESPACE_USING_DIRECTIVE + +namespace FSV +{ + class StageView + { + public: + StageView(); + ~StageView(); + void InitToolBar(); + + //StageDataModel* GetModel() { return m_StageDataModel; }; + //void SetModel(StageDataModel *model); + void BuildTreeNode(UsdPrim &prim); + void BuildOutliner(); + void BuildTreeItem(UsdPrim &prim); + void Show(bool *p_open); + private: + + }; +} diff --git a/src/FlipScope/Widgets/Viewport.cpp b/src/FlipScope/Widgets/Viewport.cpp new file mode 100644 index 0000000..885a319 --- /dev/null +++ b/src/FlipScope/Widgets/Viewport.cpp @@ -0,0 +1,232 @@ +#include "pch.h" + +#include +#include +#include + +#include "FlipScope/Core/Log.h" +#include "FlipScope/Widgets/Viewport.h" + +namespace FSV +{ + + Viewport::Viewport(uint32_t width, uint32_t height) + :m_Width(width), m_Height(height) + { + m_HydraRenderer = std::make_shared(width, height); + m_HydraRenderer->Init(width, height); + } + + Viewport::~Viewport() + { + } + + void Viewport::Update() + { + // Re-initialize Renderer + m_HydraRenderer->SetupRenderer(false); + } + + void Viewport::Show(bool *p_open) + { + ImGuiIO& io = ImGui::GetIO(); +/*#ifdef IMGUI_HAS_VIEWPORT + ImGui::SetNextWindowSize(ImGui::GetMainViewport()->Size); + ImGui::SetNextWindowPos(ImGui::GetMainViewport()->Pos); +#else + ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver); +#endif*/ + ImGui::SetNextWindowSize(io.DisplaySize, ImGuiCond_Once); + //ImGui::SetNextWindowSize(ImVec2(430, 450)); + + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(1.0f, 1.0f)); + //ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 3.0f); + std::string viewportName = "Viewport - (" + GetRenderer()->GetCurrentRendererName() + ")"; + + if (!ImGui::Begin(viewportName.c_str(), p_open)) + { + ImGui::End(); + return; + } + + //InitToolBar(); + + ImVec2 viewportPos = ImGui::GetCursorScreenPos(); + ImVec2 viewportPanelSize = ImGui::GetContentRegionAvail(); + ImVec2 mousePosInViewport = ImVec2(io.MousePos.x - viewportPos.x, io.MousePos.y - viewportPos.y); + + // FS_INFO("viewportPanelSize {}, {}", viewportPanelSize.x, viewportPanelSize.y); + + /*bool IsMouseInViewport = false; + if (mousePosInViewport.x > 0 && mousePosInViewport.x < viewportPanelSize.x && + mousePosInViewport.y > 0 && mousePosInViewport.y < viewportPanelSize.y) + { + io.ConfigFlags |= ImGuiConfigFlags_NoMouse; + IsMouseInViewport = true; + // FS_INFO("{} {}", mousePosInViewport.x, mousePosInViewport.y); + } else { + io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse; + IsMouseInViewport = true; + }*/ + + ImGuiWindow* window = ImGui::GetCurrentWindow(); + + const ImRect bb(window->DC.CursorPos, ImVec2(window->DC.CursorPos.x+ viewportPanelSize.x, window->DC.CursorPos.y + viewportPanelSize.y)); + + uint64_t rendererID = m_HydraRenderer->GetRendererID(); + + ImGui::PushID((void*)(intptr_t)rendererID); + const ImGuiID id = window->GetID("#image"); + ImGui::PopID(); + + bool hovered, held; + bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held); + + if (hovered) + { + + //if (ImGui::GetMergedKeyModFlags() & ImGuiKeyModFlags_Alt) + if (io.KeyMods & ImGuiKeyModFlags_Alt) + { + ImGui::SetMouseCursor(ImGuiMouseCursor_Arrow); + if (ImGui::IsAnyMouseDown()) + { + if (io.MouseClicked[0] || io.MouseClicked[1] || io.MouseClicked[2]) + m_HydraRenderer->OnMousePress(io.MouseClicked, io.MousePos.x, io.MousePos.y, io.KeyMods); + + m_HydraRenderer->OnMouseMove(io.MouseDown, io.MousePos.x, io.MousePos.y, io.KeyMods); + } + + if (io.MouseReleased[0] || io.MouseReleased[1] || io.MouseReleased[2]) + { + m_HydraRenderer->OnMouseRelease(io.MouseReleased, io.MousePos.x, io.MousePos.y, io.KeyMods); + } + + } + } + + // Update renderer + m_HydraRenderer->OnWindowResize(viewportPanelSize.x, viewportPanelSize.y); + + ImGui::PopStyleVar(); + ImGui::Image((void*)rendererID, ImVec2{ viewportPanelSize.x, viewportPanelSize.y }, ImVec2{ 0, 1 }, ImVec2{ 1, 0 }); + + //if (ImGui::IsItemHovered()){} + + ImVec2 work_area_pos = viewportPos; + ImVec2 work_area_size = viewportPanelSize; + ImVec2 window_pos = ImVec2(work_area_pos.x + 10, work_area_pos.y + 10); + ImVec2 window_pos_pivot = ImVec2(0, 0); + /*ImGui::SetNextWindowFocus(); + ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot); + ImGui::SetNextWindowViewport(window->ViewportId); + ImGui::SetNextWindowBgAlpha(0.35f); + int corner = -1; + if (ImGui::Begin("Example: Simple overlay", p_open, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNav)) + { + ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)"); + ImGui::Separator(); + if (ImGui::IsMousePosValid()) + ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y); + else + ImGui::Text("Mouse Position: "); + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::MenuItem("Top-left", NULL, corner == 0)) corner = 0; + if (ImGui::MenuItem("Top-right", NULL, corner == 1)) corner = 1; + if (ImGui::MenuItem("Bottom-left", NULL, corner == 2)) corner = 2; + if (ImGui::MenuItem("Bottom-right", NULL, corner == 3)) corner = 3; + ImGui::EndPopup(); + } + } + ImGui::End(); + */ + ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot); + + ImGui::PushClipRect(window_pos, ImVec2(window_pos.x + work_area_size.x, window_pos.y + work_area_size.y), true); + + ImGui::BeginChild("#ViewportWidgets", ImVec2(work_area_size.x, 100), false); + ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y); + ImGui::Button(ICON_FA_HOME, ImVec2(22.0f, 22.0f)); + ImGui::SameLine(); + ImGui::Button(ICON_FA_HOME, ImVec2(22.0f, 22.0f)); + ImGui::SameLine(); + static std::string currentRendererName = GetRenderer()->GetCurrentRendererName(); + std::vector rendererPluginNames = GetRenderer()->GetRendererPluginsNames(); + //FS_INFO("### currentRendererName : {}", currentRendererName); + + ImGui::PushStyleColor(ImGuiCol_FrameBg, IM_COL32(0, 0, 0, 100)); + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, IM_COL32(0, 0, 0, 150)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 5.0f); + + if (ImGui::BeginCombo("", currentRendererName.c_str(), (ImGuiComboFlags)rendererPluginNames.size())) + { + for (int n = 0; n < rendererPluginNames.size(); n++) + { + bool is_selected = (currentRendererName == rendererPluginNames[n]); + + if (ImGui::Selectable(rendererPluginNames[n].c_str(), is_selected)) + { + currentRendererName = rendererPluginNames[n]; + GetRenderer()->SetCurrentRenderer(currentRendererName); + } + + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } + ImGui::PopStyleVar(); + ImGui::PopStyleColor(2); + ImGui::EndChild(); + ImGui::PopClipRect(); + ImGui::End(); + } + + void Viewport::InitToolBar() + { + + ImGui::Button(ICON_FA_HOME, ImVec2(22.0f, 22.0f)); + ImGui::SameLine(); + ImGui::Button(ICON_FA_HOME, ImVec2(22.0f, 22.0f)); + ImGui::SameLine(); + static std::string currentRendererName = GetRenderer()->GetCurrentRendererName(); + std::vector rendererPluginNames = GetRenderer()->GetRendererPluginsNames(); + //FS_INFO("### currentRendererName : {}", currentRendererName); + + if (ImGui::BeginCombo("Renderer", currentRendererName.c_str(), (ImGuiComboFlags)rendererPluginNames.size())) + { + for (int n = 0; n < rendererPluginNames.size(); n++) + { + bool is_selected = (currentRendererName == rendererPluginNames[n]); + + if (ImGui::Selectable(rendererPluginNames[n].c_str(), is_selected)) + { + currentRendererName = rendererPluginNames[n]; + GetRenderer()->SetCurrentRenderer(currentRendererName); + } + + + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } + + ImGui::SameLine(); + if (ImGui::BeginCombo("Camera", "Free Camera")) + { + ImGui::EndCombo(); + } + } + + void Viewport::OnMousePress(bool button[], int x, int y, int modKeys) + { + } + void Viewport::OnMouseRelease(bool button[], int x, int y, int modKeys) + { + } + void Viewport::OnMouseMove(int x, int y, int modKeys) + { + } +} \ No newline at end of file diff --git a/src/FlipScope/Widgets/Viewport.h b/src/FlipScope/Widgets/Viewport.h new file mode 100644 index 0000000..ad73b97 --- /dev/null +++ b/src/FlipScope/Widgets/Viewport.h @@ -0,0 +1,38 @@ +#pragma once +#include "pch.h" + +#include +#include + +#include "FlipScope/Usd/StageDataModel.h" +#include "FlipScope/Usd/HydraRenderer.h" + +namespace FSV +{ + class Viewport + { + public: + + Viewport(uint32_t width, uint32_t height); + virtual ~Viewport(); + + void Update(); + + void Show(bool *p_open); + + std::shared_ptr GetRenderer() { return m_HydraRenderer; }; + void InitToolBar(); + + int GetWidth() { return m_Width; }; + int GetHeight() { return m_Height; }; + + void OnMousePress(bool button[], int x, int y, int modKeys); + void OnMouseRelease(bool button[], int x, int y, int modKeys); + void OnMouseMove(int x, int y, int modKeys); + + private: + uint32_t m_Width, m_Height; + std::shared_ptr m_HydraRenderer; + std::shared_ptr m_StageDataModel; + }; +} \ No newline at end of file diff --git a/src/Platform/OpenGL/OpenGLContext.cpp b/src/Platform/OpenGL/OpenGLContext.cpp new file mode 100644 index 0000000..a41d76c --- /dev/null +++ b/src/Platform/OpenGL/OpenGLContext.cpp @@ -0,0 +1,42 @@ +#include "pch.h" + +#include "FlipScope/Core/Core.h" +#include "FlipScope/Core/Log.h" + +#include "Platform/OpenGL/OpenGLContext.h" + +namespace FSV +{ + OpenGLContext::OpenGLContext(GLFWwindow* windowHandle) + : m_WindowHandle(windowHandle) + { + + } + + void OpenGLContext::Init() + { + glfwMakeContextCurrent(m_WindowHandle); + + int status = gladLoadGLLoader((GLADloadproc)glfwGetProcAddress); + //GLenum status = glewInit(); + if (!status) { + //if(GLEW_OK != status) + //{ + //FS_ERROR("OpenGLContext::Init() : Fail initialize OpenGL."); + FS_ERROR("OpenGLContext::Init() : Fail initialize OpenGL. {0}", status); + } + else { + FS_INFO("OpenGLContext.Init(): {0}", status); + } + + FS_INFO("OpenGL Info:"); + FS_INFO(" Vendor: {0}", glGetString(GL_VENDOR)); + FS_INFO(" Renderer: {0}", glGetString(GL_RENDERER)); + FS_INFO(" Version: {0}", glGetString(GL_VERSION)); + } + + void OpenGLContext::SwapBuffers() + { + glfwSwapBuffers(m_WindowHandle); + } +} \ No newline at end of file diff --git a/src/Platform/OpenGL/OpenGLContext.h b/src/Platform/OpenGL/OpenGLContext.h new file mode 100644 index 0000000..761fee9 --- /dev/null +++ b/src/Platform/OpenGL/OpenGLContext.h @@ -0,0 +1,20 @@ +#pragma once + +#include "FlipScope/Renderer/GraphicsContext.h" + +struct GLFWwindow; + +namespace FSV +{ + class OpenGLContext :public GraphicsContext + { + public: + OpenGLContext(GLFWwindow* windowHandle); + + virtual void Init() override; + virtual void SwapBuffers() override; + + private: + GLFWwindow* m_WindowHandle; + }; +} diff --git a/src/Platform/OpenGL/OpenGLFramebuffer.cpp b/src/Platform/OpenGL/OpenGLFramebuffer.cpp new file mode 100644 index 0000000..15e5f48 --- /dev/null +++ b/src/Platform/OpenGL/OpenGLFramebuffer.cpp @@ -0,0 +1,77 @@ +#include "pch.h" + +#include "FlipScope/Core/Log.h" + +#include "Platform/OpenGL/OpenGLFramebuffer.h" + +#include +//#include + + +namespace FSV +{ + OpenGLFramebuffer::OpenGLFramebuffer(const FramebufferSpecification& spec) + :m_Specification(spec) + { + Invalidate(); + } + + OpenGLFramebuffer::~OpenGLFramebuffer() + { + glDeleteFramebuffers(1, &m_RendererID); + glDeleteTextures(1, &m_ColorAttachment); + glDeleteTextures(1, &m_DepthAttachment); + } + + void OpenGLFramebuffer::Invalidate() + { + + if (m_RendererID) + { + glDeleteFramebuffers(1, &m_RendererID); + glDeleteTextures(1, &m_ColorAttachment); + glDeleteTextures(1, &m_DepthAttachment); + } + + glCreateFramebuffers(1, &m_RendererID); + glBindFramebuffer(GL_FRAMEBUFFER, m_RendererID); + + glCreateTextures(GL_TEXTURE_2D, 1, &m_ColorAttachment); + glBindTexture(GL_TEXTURE_2D, m_ColorAttachment); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_Specification.Width, m_Specification.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_ColorAttachment, 0); + + glCreateTextures(GL_TEXTURE_2D, 1, &m_DepthAttachment); + glBindTexture(GL_TEXTURE_2D, m_DepthAttachment); + + glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH24_STENCIL8, m_Specification.Width, m_Specification.Height); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_DepthAttachment, 0); + + if (!(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE)) + FS_ERROR("Framebuffer is incomplete!"); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + void OpenGLFramebuffer::Bind() + { + glBindFramebuffer(GL_FRAMEBUFFER, m_RendererID); + } + + void OpenGLFramebuffer::Unbind() + { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + void OpenGLFramebuffer::Resize(uint32_t width, uint32_t height) + { + m_Specification.Width = width; + m_Specification.Height = height; + + Invalidate(); + } +} \ No newline at end of file diff --git a/src/Platform/OpenGL/OpenGLFramebuffer.h b/src/Platform/OpenGL/OpenGLFramebuffer.h new file mode 100644 index 0000000..b8dbca5 --- /dev/null +++ b/src/Platform/OpenGL/OpenGLFramebuffer.h @@ -0,0 +1,30 @@ +#pragma once + +#include "FlipScope/Renderer/FrameBuffer.h" + +namespace FSV +{ + class OpenGLFramebuffer :public Framebuffer + { + public: + OpenGLFramebuffer(const FramebufferSpecification& spec); + virtual ~OpenGLFramebuffer(); + + virtual void Bind() override; + virtual void Unbind() override; + + void Invalidate(); + + virtual void Resize(uint32_t width, uint32_t height) override; + + + virtual uint32_t GetColorAttachmentRendererID() const override { return m_ColorAttachment; } + + virtual const FramebufferSpecification& GetSpecification() const override { return m_Specification; } + private: + uint32_t m_RendererID = 0; + uint32_t m_ColorAttachment = 0, m_DepthAttachment = 0; + FramebufferSpecification m_Specification; + + }; +} diff --git a/src/Platform/OpenGL/OpenGLRendererAPI.cpp b/src/Platform/OpenGL/OpenGLRendererAPI.cpp new file mode 100644 index 0000000..9e14e34 --- /dev/null +++ b/src/Platform/OpenGL/OpenGLRendererAPI.cpp @@ -0,0 +1,33 @@ +#include "pch.h" + +#include "OpenGLRendererAPI.h" + +#include +//#include + +namespace FSV +{ + void OpenGLRendererAPI::Init() + { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnable(GL_DEPTH_TEST); + } + + void OpenGLRendererAPI::SetViewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height) + { + glViewport(x, y, width, height); + } + + void OpenGLRendererAPI::SetClearColor(const glm::vec4& color) + { + glClearColor(color.r, color.g, color.b, color.a); + } + + void OpenGLRendererAPI::Clear() + { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + +} \ No newline at end of file diff --git a/src/Platform/OpenGL/OpenGLRendererAPI.h b/src/Platform/OpenGL/OpenGLRendererAPI.h new file mode 100644 index 0000000..363af1d --- /dev/null +++ b/src/Platform/OpenGL/OpenGLRendererAPI.h @@ -0,0 +1,18 @@ +#pragma once + +#include "FlipScope/Renderer/RendererAPI.h" + +namespace FSV +{ + class OpenGLRendererAPI : public RendererAPI + { + public: + virtual void Init() override; + virtual void SetViewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height) override; + + virtual void SetClearColor(const glm::vec4& color) override; + virtual void Clear() override; + + }; +} + diff --git a/src/Platform/OpenGL/OpenGLTexture.cpp b/src/Platform/OpenGL/OpenGLTexture.cpp new file mode 100644 index 0000000..9b4a7af --- /dev/null +++ b/src/Platform/OpenGL/OpenGLTexture.cpp @@ -0,0 +1,90 @@ +#include "pch.h" + +#include "FlipScope/Core/Log.h" +#include "Platform/OpenGL/OpenGLTexture.h" + +#include + +namespace FSV +{ + OpenGLTexture::OpenGLTexture(uint32_t width, uint32_t height) + :m_Width(width), m_Height(height) + { + m_InternalFormat = GL_RGBA8; + m_DataFormat = GL_RGBA; + + glCreateTextures(GL_TEXTURE_2D, 1, &m_RendererID); + glTextureStorage2D(m_RendererID, 1, m_InternalFormat, m_Width, m_Height); + + glTextureParameteri(m_RendererID, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTextureParameteri(m_RendererID, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + + OpenGLTexture::OpenGLTexture(const std::string path) + :m_Path(path) + { + int width, height, channels; + stbi_uc *data; + stbi_set_flip_vertically_on_load(1); + { + FS_INFO("stbi_load - OpenGLTexture2D::OpenGLTexture2D(const std:string&)"); + data = stbi_load(path.c_str(), &width, &height, &channels, 0); + } + + m_Width = width; + m_Height = height; + + GLenum internalFormat = 0, dataFormat = 0; + if (channels == 4) + { + internalFormat = GL_RGBA8; + dataFormat = GL_RGBA; + } + else if (channels == 3) + { + internalFormat = GL_RGB8; + dataFormat = GL_RGB; + } + + m_InternalFormat = internalFormat; + m_DataFormat = dataFormat; + + if (!(internalFormat & dataFormat)) + { + FS_ERROR("Format not supported!"); + return; + } + + glCreateTextures(GL_TEXTURE_2D, 1, &m_RendererID); + glTextureStorage2D(m_RendererID, 1, internalFormat, m_Width, m_Height); + + glTextureParameteri(m_RendererID, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTextureParameteri(m_RendererID, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_T, GL_REPEAT); + + glTextureSubImage2D(m_RendererID, 0, 0, 0, m_Width, m_Height, dataFormat, GL_UNSIGNED_BYTE, data); + + stbi_image_free(data); + } + + OpenGLTexture::~OpenGLTexture() + { + glDeleteTextures(1, &m_RendererID); + } + + void OpenGLTexture::SetData(void *data, uint32_t size) const + { + uint32_t bpp = m_DataFormat == GL_RGBA ? 4 : 3; + glTextureSubImage2D(m_RendererID, 0, 0, 0, m_Width, m_Height, m_DataFormat, GL_UNSIGNED_BYTE, data); + } + + void OpenGLTexture::Bind(uint32_t slot) const + { + glBindTextureUnit(slot, m_RendererID); + } +} \ No newline at end of file diff --git a/src/Platform/OpenGL/OpenGLTexture.h b/src/Platform/OpenGL/OpenGLTexture.h new file mode 100644 index 0000000..04ef1a5 --- /dev/null +++ b/src/Platform/OpenGL/OpenGLTexture.h @@ -0,0 +1,38 @@ +#pragma once + +#include "FlipScope/Renderer/Texture.h" + +#include +//#include + +namespace FSV +{ + class OpenGLTexture :public Texture + { + public: + + OpenGLTexture(uint32_t width, uint32_t height); + OpenGLTexture(const std::string path); + + virtual ~OpenGLTexture(); + + virtual uint32_t GetWidth() const override { return m_Width; } + virtual uint32_t GetHeight() const override { return m_Height; } + virtual uint32_t GetRendererID() const override { return m_RendererID; } + + virtual void SetData(void* data, uint32_t size) const override; + + virtual void Bind(uint32_t slot = 0) const override; + + virtual bool operator==(const Texture& other) const override + { + return m_RendererID == ((OpenGLTexture&)other).m_RendererID; + } + + private: + std::string m_Path; + uint32_t m_Width, m_Height; + uint32_t m_RendererID; + GLenum m_InternalFormat, m_DataFormat; + }; +} diff --git a/src/Platform/OpenGL/OpenGLViewportRenderer.cpp b/src/Platform/OpenGL/OpenGLViewportRenderer.cpp new file mode 100644 index 0000000..65054f8 --- /dev/null +++ b/src/Platform/OpenGL/OpenGLViewportRenderer.cpp @@ -0,0 +1,35 @@ +#include "pch.h" + +#include "Platform/OpenGL/OpenGLViewportRenderer.h" + +namespace FSV +{ + OpenGLViewportRenderer::OpenGLViewportRenderer() + { + + } + OpenGLViewportRenderer::~OpenGLViewportRenderer() + { + + } + void OpenGLViewportRenderer::Init() + { + + } + + void OpenGLViewportRenderer::Shutdown() + { + + } + + void OpenGLViewportRenderer::OnWindowResize(uint32_t width, uint32_t height) + { + m_Width = width; + m_Height = height; + } + + void OpenGLViewportRenderer::OnRender() + { + + } +} \ No newline at end of file diff --git a/src/Platform/OpenGL/OpenGLViewportRenderer.h b/src/Platform/OpenGL/OpenGLViewportRenderer.h new file mode 100644 index 0000000..5a60013 --- /dev/null +++ b/src/Platform/OpenGL/OpenGLViewportRenderer.h @@ -0,0 +1,28 @@ +#pragma once + +#include "FlipScope/Renderer/ViewportRenderer.h" +#include +//#include + +namespace FSV +{ + class OpenGLViewportRenderer :public ViewportRenderer + { + public: + OpenGLViewportRenderer(); + virtual ~OpenGLViewportRenderer(); + virtual void Init() override; + virtual void Shutdown() override; + + virtual uint32_t GetWidth() const override { return m_Width; } + virtual uint32_t GetHeight() const override { return m_Height; } + + virtual void OnWindowResize(uint32_t width, uint32_t height); + + virtual void OnRender(); + + private: + uint32_t m_Width, m_Height; + GLenum m_DrawTarget; + }; +} \ No newline at end of file diff --git a/src/Platform/Windows/WindowsWindow.cpp b/src/Platform/Windows/WindowsWindow.cpp new file mode 100644 index 0000000..5b3f5ac --- /dev/null +++ b/src/Platform/Windows/WindowsWindow.cpp @@ -0,0 +1,145 @@ +#include "pch.h" + +#include "Platform/Windows/WindowsWindow.h" + +#include "FlipScope/Core/Log.h" +#include "FlipScope/Event/ApplicationEvent.h" + +#include "FlipScope/Renderer/Renderer.h" + +#include "Platform/OpenGL/OpenGLContext.h" + +namespace FSV +{ + static uint8_t s_GLFWWindowCount = 0; + + static void GLFWErrorCallback(int error, const char* description) + { + FS_ERROR("GLFW Error : {0} , {1}", error, description); + } + + WindowsWindow::WindowsWindow(const WindowProps& props) + { + Init(props); + } + + WindowsWindow::~WindowsWindow() + { + Shutdown(); + } + + void WindowsWindow::Init(const WindowProps& props) + { + FS_INFO("WindowsWindow::Init()"); + m_Data.Title = props.Title; + m_Data.Width = props.Width; + m_Data.Height = props.Height; + + if (s_GLFWWindowCount == 0) + { + int success = glfwInit(); + FS_INFO("WindowsWindow::Init() : glfwInit() : {0}", success); + glfwSetErrorCallback(GLFWErrorCallback); + } + + glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); + m_Window = glfwCreateWindow((int)props.Width, (int)props.Height, m_Data.Title.c_str(), nullptr, nullptr); + ++s_GLFWWindowCount; + + m_Context = GraphicsContext::Create(m_Window); + m_Context->Init(); + + //glfwSetWindowUserPointer(m_Window, &m_Data); + glfwSetWindowUserPointer(m_Window, this); + SetVSync(true); + + glfwSetWindowSizeCallback(m_Window, WindowResizeCallback); + glfwSetWindowCloseCallback(m_Window, WindowCloseCallback); + glfwSetMouseButtonCallback(m_Window, MouseButtonCallback); + glfwSetCursorPosCallback(m_Window, CursorPosCallback); + glfwSetDropCallback(m_Window, FileDropCallback); + glfwSetScrollCallback(m_Window, ScrollCallback); + } + + void WindowsWindow::Shutdown() + { + glfwDestroyWindow(m_Window); + --s_GLFWWindowCount; + + if (s_GLFWWindowCount == 0) + { + glfwTerminate(); + } + FS_INFO("WindowsWindow::Shutdown()"); + } + + void WindowsWindow::OnUpdate() + { + glfwPollEvents(); + //Renderer + + m_Context->SwapBuffers(); + } + + void WindowsWindow::SetVSync(bool enabled) + { + if (enabled) + glfwSwapInterval(1); + else + glfwSwapInterval(0); + m_Data.VSync = enabled; + } + + bool WindowsWindow::IsVSync() const + { + return m_Data.VSync; + } + + bool WindowsWindow::Close() const + { + if (glfwWindowShouldClose(m_Window)) + return true; + return false; + } + + void WindowsWindow::OnWindowResize(unsigned int width, unsigned int height) + { + m_Data.Width = width; + m_Data.Height = height; + FS_INFO("WindowsWindow::OnWindowResize() : Resize {0} {1}", width, height); + Renderer::OnWindowResize(width, height); + } + + void WindowsWindow::OnWindowClose() + { + FS_INFO("WindowsWindow::OnWindowClose() : Close"); + } + + void WindowsWindow::OnFileDrop(unsigned int count, const char *paths[]) + { + for (unsigned int i = 0; i < count; i++) { + const std::string &filepath = paths[i]; + FS_INFO("WindowsWindow::OnFileDrop() : {0} : {1}", i, filepath); + } + } + + void WindowsWindow::OnScroll(double xOffset, double yOffset) + { + FS_INFO("WindowsWindow::OnScroll() : {0} {1}", xOffset, yOffset); + } + + void WindowsWindow::OnCursorPos(double xPos, double yPos) + { + //FS_INFO("WindowsWindow::OnCursorPos() : {0} {1}", xPos, yPos); + } + + void WindowsWindow::OnMousePress(int button, int mods) + { + FS_INFO("WindowsWindow::OnMousePress() : {0} {1}", button, mods); + } + + void WindowsWindow::OnMouseRelease(int button, int mods) + { + FS_INFO("WindowsWindow::OnMouseRelease() : {0} {1}", button, mods); + } +} \ No newline at end of file diff --git a/src/Platform/Windows/WindowsWindow.h b/src/Platform/Windows/WindowsWindow.h new file mode 100644 index 0000000..829168e --- /dev/null +++ b/src/Platform/Windows/WindowsWindow.h @@ -0,0 +1,93 @@ +#pragma once +#include "FlipScope/Core/Core.h" + +#include "FlipScope/Core/Window.h" +#include "FlipScope/Renderer/GraphicsContext.h" + +namespace FSV +{ + class WindowsWindow : public Window + { + public: + WindowsWindow(const WindowProps& props); + virtual ~WindowsWindow(); + + void OnUpdate() override; + + inline unsigned int GetWidth() const override { return m_Data.Width; } + inline unsigned int GetHeight() const override { return m_Data.Height; } + + void SetEventCallback(const EventCallbackFn& callback) override { m_Data.EventCallback = callback; } + void SetVSync(bool enabled) override; + bool IsVSync() const override; + bool Close() const; + + void OnWindowResize(unsigned int width, unsigned int height); + void OnWindowClose(); + void OnFileDrop(unsigned int count, const char* paths[]); + void OnScroll(double xOffset, double yOffset); + void OnCursorPos(double xPos, double yPos); + void OnMousePress(int button, int mods); + void OnMouseRelease(int button, int mods); + + inline virtual void* GetNativeWindow() const { return m_Window; } + + private: + virtual void Init(const WindowProps& props); + virtual void Shutdown(); + + private: + GLFWwindow* m_Window; + std::unique_ptr m_Context; + bool m_Running; + + struct WindowData + { + std::string Title; + unsigned int Width, Height; + bool VSync; + EventCallbackFn EventCallback; + }; + + WindowData m_Data; + + inline static auto WindowResizeCallback(GLFWwindow *win, int width, int height) -> void { + WindowsWindow *window = static_cast(glfwGetWindowUserPointer(win)); + window->OnWindowResize(width, height); + } + + inline static auto WindowCloseCallback(GLFWwindow *win) -> void { + WindowsWindow *window = static_cast(glfwGetWindowUserPointer(win)); + window->OnWindowClose(); + } + + inline static auto FileDropCallback(GLFWwindow *win, int count, const char* paths[]) -> void { + WindowsWindow *window = static_cast(glfwGetWindowUserPointer(win)); + window->OnFileDrop(count, paths); + } + + inline static auto ScrollCallback(GLFWwindow *win, double xOffset, double yOffset) -> void { + WindowsWindow *window = static_cast(glfwGetWindowUserPointer(win)); + window->OnScroll(xOffset, yOffset); + } + + inline static auto CursorPosCallback(GLFWwindow *win, double xPos, double yPos) -> void { + WindowsWindow *window = static_cast(glfwGetWindowUserPointer(win)); + window->OnCursorPos(xPos, yPos); + } + + + inline static auto MouseButtonCallback(GLFWwindow *win, int button, int action, int mods) -> void { + WindowsWindow *window = static_cast(glfwGetWindowUserPointer(win)); + switch (action) + { + case GLFW_PRESS: + window->OnMousePress(button, mods); + break; + case GLFW_RELEASE: + window->OnMouseRelease(button, mods); + break; + } + } + }; +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..e2463b3 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,11 @@ +#include "pch.h" + +#include "FlipScope/Core/Application.h" +#include "FlipScope/Core/Log.h" + + +int main(int argc, char *argv[]) { + FSV::Log::Init(); + auto *app = FSV::CreateApplication(); + app->Run(); +} \ No newline at end of file diff --git a/src/pch.cpp b/src/pch.cpp new file mode 100644 index 0000000..1730571 --- /dev/null +++ b/src/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" \ No newline at end of file diff --git a/src/pch.h b/src/pch.h new file mode 100644 index 0000000..ab3b7fc --- /dev/null +++ b/src/pch.h @@ -0,0 +1,19 @@ +#pragma once +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include \ No newline at end of file