From a7bfed486d7d161db44f4aefdc8007b84c6e0957 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 21 Jul 2024 15:49:32 +0200 Subject: [PATCH] Hook up the 3d viewport rendering --- SurrealEngine/Engine.cpp | 16 ++++---- SurrealEngine/Render/RenderScene.cpp | 3 ++ SurrealEngine/RenderDevice/RenderDevice.cpp | 41 +++++++++++-------- SurrealEngine/RenderDevice/RenderDevice.h | 12 +++--- .../RenderDevice/Vulkan/RenderPassManager.cpp | 2 +- .../Vulkan/VulkanRenderDevice.cpp | 12 +++--- .../RenderDevice/Vulkan/VulkanRenderDevice.h | 2 +- SurrealEngine/UI/Editor/Editor3DViewport.cpp | 15 +++---- SurrealEngine/UI/Editor/EditorMainWindow.cpp | 18 +++++++- SurrealEngine/UI/Editor/EditorMainWindow.h | 2 + .../zwidget/widgets/mainwindow/mainwindow.h | 2 +- .../src/widgets/mainwindow/mainwindow.cpp | 2 +- .../window/win32/win32_open_file_dialog.cpp | 37 +++++++++++++++-- 13 files changed, 112 insertions(+), 52 deletions(-) diff --git a/SurrealEngine/Engine.cpp b/SurrealEngine/Engine.cpp index 3c06df0b..08aef9b1 100644 --- a/SurrealEngine/Engine.cpp +++ b/SurrealEngine/Engine.cpp @@ -35,15 +35,7 @@ Engine::Engine(GameLaunchInfo launchinfo) : LaunchInfo(launchinfo) //packages = std::make_unique(LaunchInfo.folder, LaunchInfo.engineVersion, LaunchInfo.gameName); packages = std::make_unique(LaunchInfo); -} - -Engine::~Engine() -{ - engine = nullptr; -} -void Engine::Run() -{ std::srand((unsigned int)std::time(nullptr)); gameengine = UObject::Cast(packages->NewObject("gameengine", "Engine", "GameEngine")); @@ -63,7 +55,15 @@ void Engine::Run() console->Viewport() = viewport; canvas->Viewport() = viewport; viewport->Console() = console; +} + +Engine::~Engine() +{ + engine = nullptr; +} +void Engine::Run() +{ LoadEngineSettings(); LoadKeybindings(); diff --git a/SurrealEngine/Render/RenderScene.cpp b/SurrealEngine/Render/RenderScene.cpp index f01dfadc..96a3b54b 100644 --- a/SurrealEngine/Render/RenderScene.cpp +++ b/SurrealEngine/Render/RenderScene.cpp @@ -12,6 +12,9 @@ void RenderSubsystem::DrawScene() Scene.Clipper.numSurfs = 0; Scene.Clipper.numTris = 0; + if (!engine->Level) + return; + // Make sure all actors are at the right location in the BSP for (UActor* actor : engine->Level->Actors) { diff --git a/SurrealEngine/RenderDevice/RenderDevice.cpp b/SurrealEngine/RenderDevice/RenderDevice.cpp index 03c7ebe0..31c7a9b5 100644 --- a/SurrealEngine/RenderDevice/RenderDevice.cpp +++ b/SurrealEngine/RenderDevice/RenderDevice.cpp @@ -4,8 +4,9 @@ #include "Vulkan/VulkanRenderDevice.h" #include "UObject/ULevel.h" #include +#include -std::unique_ptr RenderDevice::Create(GameWindow* viewport, std::shared_ptr surface) +std::unique_ptr RenderDevice::Create(Widget* viewport, std::shared_ptr surface) { return std::make_unique(viewport, surface); } @@ -19,6 +20,25 @@ RenderDeviceCanvas::RenderDeviceCanvas(RenderDevice* device) : device(device) void RenderDeviceCanvas::begin(const Colorf& color) { device->Lock(vec4(0.0f), vec4(0.0f), vec4(color.r, color.g, color.b, color.a)); + + frame.XB = 0; + frame.YB = 0; + frame.X = device->Viewport->GetNativePixelWidth(); + frame.Y = device->Viewport->GetNativePixelHeight(); + frame.FX = (float)device->Viewport->GetNativePixelWidth(); + frame.FY = (float)device->Viewport->GetNativePixelHeight(); + frame.FX2 = (float)device->Viewport->GetNativePixelWidth() * 0.5f; + frame.FY2 = (float)device->Viewport->GetNativePixelHeight() * 0.5f; + frame.Viewport = device->Viewport; + frame.FovAngle = 90.0f; + frame.ObjectToWorld = mat4::identity(); + frame.WorldToView = mat4::identity(); + float Aspect = frame.FY / frame.FX; + float RProjZ = (float)std::tan(radians(frame.FovAngle) * 0.5f); + float RFX2 = 2.0f * RProjZ / frame.FX; + float RFY2 = 2.0f * RProjZ * Aspect / frame.FY; + frame.Projection = mat4::frustum(-RProjZ, RProjZ, -Aspect * RProjZ, Aspect * RProjZ, 1.0f, 32768.0f, handedness::left, clipzrange::zero_positive_w); + device->SetSceneNode(&frame); } void RenderDeviceCanvas::end() @@ -28,13 +48,12 @@ void RenderDeviceCanvas::end() void RenderDeviceCanvas::begin3d() { - CheckFrame(); device->ClearZ(&frame); } void RenderDeviceCanvas::end3d() { - CheckFrame(); + device->SetSceneNode(&frame); device->ClearZ(&frame); } @@ -44,7 +63,7 @@ std::unique_ptr RenderDeviceCanvas::createTexture(int width, int texture->Width = width; texture->Height = height; texture->Info.CacheID = (uint64_t)(ptrdiff_t)texture.get(); - texture->Info.Format = TextureFormat::ARGB8; + texture->Info.Format = TextureFormat::BGRA8; texture->Info.USize = width; texture->Info.VSize = height; texture->Info.NumMips = 1; @@ -58,30 +77,20 @@ std::unique_ptr RenderDeviceCanvas::createTexture(int width, int void RenderDeviceCanvas::drawLineAntialiased(float x0, float y0, float x1, float y1, Colorf color) { - CheckFrame(); device->Draw2DLine(&frame, vec4(color.r, color.g, color.b, color.a), vec3(x0, y0, 1.0f), vec3(x1, y1, 1.0f)); } void RenderDeviceCanvas::fillTile(float x, float y, float width, float height, Colorf color) { - CheckFrame(); - device->DrawTile(&frame, static_cast(whiteTexture.get())->Info, x, y, width, height, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, vec4(color.r, color.g, color.b, color.a), vec4(0.0f), 0); + device->DrawTile(&frame, static_cast(whiteTexture.get())->Info, x, y, width, height, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, vec4(color.r, color.g, color.b, color.a), vec4(0.0f), PF_Highlighted); } void RenderDeviceCanvas::drawTile(CanvasTexture* texture, float x, float y, float width, float height, float u, float v, float uvwidth, float uvheight, Colorf color) { - CheckFrame(); - device->DrawTile(&frame, static_cast(texture)->Info, x, y, width, height, u, v, uvwidth, uvheight, 1.0f, vec4(color.r, color.g, color.b, color.a), vec4(0.0f), 0); + device->DrawTile(&frame, static_cast(texture)->Info, x, y, width, height, u, v, uvwidth, uvheight, 1.0f, vec4(color.r, color.g, color.b, color.a), vec4(0.0f), PF_Highlighted); } void RenderDeviceCanvas::drawGlyph(CanvasTexture* texture, float x, float y, float width, float height, float u, float v, float uvwidth, float uvheight, Colorf color) { - CheckFrame(); device->DrawTile(&frame, static_cast(texture)->Info, x, y, width, height, u, v, uvwidth, uvheight, 1.0f, vec4(color.r, color.g, color.b, color.a), vec4(0.0f), PF_SubpixelFont); } - -void RenderDeviceCanvas::CheckFrame() -{ - // To do: check if frame is up to date and update it if not - // device->SetSceneNode(&frame); -} diff --git a/SurrealEngine/RenderDevice/RenderDevice.h b/SurrealEngine/RenderDevice/RenderDevice.h index c03a2824..cc2cd696 100644 --- a/SurrealEngine/RenderDevice/RenderDevice.h +++ b/SurrealEngine/RenderDevice/RenderDevice.h @@ -9,10 +9,10 @@ #include #include -class GameWindow; class UTexture; class UActor; class VulkanSurface; +class Widget; struct FSceneNode { @@ -20,7 +20,7 @@ struct FSceneNode int X, Y; // viewport size float FX, FY; float FX2, FY2; - GameWindow* Viewport = nullptr; + Widget* Viewport = nullptr; float FovAngle; mat4 ObjectToWorld; @@ -91,7 +91,7 @@ class OutputDevice class RenderDevice { public: - static std::unique_ptr Create(GameWindow* viewport, std::shared_ptr surface); + static std::unique_ptr Create(Widget* viewport, std::shared_ptr surface); virtual ~RenderDevice() = default; @@ -115,7 +115,7 @@ class RenderDevice bool ParseCommand(std::string* cmd, const std::string& keyword) { return false; } - GameWindow* Viewport = nullptr; + Widget* Viewport = nullptr; bool PrecacheOnFlip = false; float Brightness = 0.5f; }; @@ -138,6 +138,8 @@ class RenderDeviceCanvas : public Canvas void begin3d() override; void end3d() override; + RenderDevice* GetRenderDevice() { return device; } + protected: std::unique_ptr createTexture(int width, int height, const void* pixels, ImageFormat format) override; void drawLineAntialiased(float x0, float y0, float x1, float y1, Colorf color) override; @@ -146,8 +148,6 @@ class RenderDeviceCanvas : public Canvas void drawGlyph(CanvasTexture* texture, float x, float y, float width, float height, float u, float v, float uvwidth, float uvheight, Colorf color) override; private: - void CheckFrame(); - RenderDevice* device = nullptr; FSceneNode frame; }; diff --git a/SurrealEngine/RenderDevice/Vulkan/RenderPassManager.cpp b/SurrealEngine/RenderDevice/Vulkan/RenderPassManager.cpp index e86cc818..447fda2f 100644 --- a/SurrealEngine/RenderDevice/Vulkan/RenderPassManager.cpp +++ b/SurrealEngine/RenderDevice/Vulkan/RenderPassManager.cpp @@ -208,7 +208,7 @@ void RenderPassManager::CreatePipelines() } else // PF_SubpixelFont { - builder.BlendMode(VK_BLEND_OP_ADD, VK_BLEND_FACTOR_CONSTANT_COLOR, VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR/*, VK_BLEND_FACTOR_ZERO, VK_BLEND_FACTOR_ONE*/); + builder.BlendMode(VK_BLEND_OP_ADD, VK_BLEND_FACTOR_CONSTANT_COLOR, VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR); builder.AddFragmentShader(fragShaderAlphaTest[type]); } diff --git a/SurrealEngine/RenderDevice/Vulkan/VulkanRenderDevice.cpp b/SurrealEngine/RenderDevice/Vulkan/VulkanRenderDevice.cpp index cbe137a5..f6f2fd5e 100644 --- a/SurrealEngine/RenderDevice/Vulkan/VulkanRenderDevice.cpp +++ b/SurrealEngine/RenderDevice/Vulkan/VulkanRenderDevice.cpp @@ -23,7 +23,7 @@ void VulkanError(const char* text) Exception::Throw(text); } -VulkanRenderDevice::VulkanRenderDevice(GameWindow* InViewport, std::shared_ptr surface) +VulkanRenderDevice::VulkanRenderDevice(Widget* InViewport, std::shared_ptr surface) { Viewport = InViewport; @@ -286,8 +286,8 @@ void VulkanRenderDevice::Lock(vec4 InFlashScale, vec4 InFlashFog, vec4 ScreenCle FlashScale = InFlashScale; FlashFog = InFlashFog; - int width = Viewport->GetPixelWidth(); - int height = Viewport->GetPixelHeight(); + int width = Viewport->GetNativePixelWidth(); + int height = Viewport->GetNativePixelHeight(); if (!Textures->Scene || Textures->Scene->width != width || Textures->Scene->height != height) { @@ -384,7 +384,7 @@ void VulkanRenderDevice::Unlock(bool Blit) RenderPasses->EndScene(Commands->GetDrawCommands()); BlitSceneToPostprocess(); - SubmitAndWait(Blit, Viewport->GetPixelWidth(), Viewport->GetPixelHeight()); + SubmitAndWait(Blit, Viewport->GetNativePixelWidth(), Viewport->GetNativePixelHeight()); IsLocked = false; } @@ -858,8 +858,8 @@ void VulkanRenderDevice::ClearZ(FSceneNode* Frame) void VulkanRenderDevice::ReadPixels(FColor* Pixels) { - int w = Viewport->GetPixelWidth(); - int h = Viewport->GetPixelHeight(); + int w = Viewport->GetNativePixelWidth(); + int h = Viewport->GetNativePixelHeight(); void* data = Pixels; auto dstimage = ImageBuilder() diff --git a/SurrealEngine/RenderDevice/Vulkan/VulkanRenderDevice.h b/SurrealEngine/RenderDevice/Vulkan/VulkanRenderDevice.h index eac18589..065215a7 100644 --- a/SurrealEngine/RenderDevice/Vulkan/VulkanRenderDevice.h +++ b/SurrealEngine/RenderDevice/Vulkan/VulkanRenderDevice.h @@ -20,7 +20,7 @@ class CachedTexture; class VulkanRenderDevice : public RenderDevice { public: - VulkanRenderDevice(GameWindow* InViewport, std::shared_ptr surface); + VulkanRenderDevice(Widget* InViewport, std::shared_ptr surface); ~VulkanRenderDevice(); void Flush(bool AllowPrecache) override; diff --git a/SurrealEngine/UI/Editor/Editor3DViewport.cpp b/SurrealEngine/UI/Editor/Editor3DViewport.cpp index 4239cfef..eb25f510 100644 --- a/SurrealEngine/UI/Editor/Editor3DViewport.cpp +++ b/SurrealEngine/UI/Editor/Editor3DViewport.cpp @@ -3,6 +3,7 @@ #include "Editor3DViewport.h" #include "Engine.h" #include "Render/RenderSubsystem.h" +#include "RenderDevice/RenderDevice.h" #include Editor3DViewport::Editor3DViewport(Widget* parent) : EditorViewport(parent) @@ -24,16 +25,16 @@ void Editor3DViewport::OnPaint(Canvas* canvas) canvas->begin3d(); - //if (!engine->render) - // engine->render = std::make_unique(Window()->GetRenderDevice()); + if (!engine->render) + engine->render = std::make_unique(static_cast(canvas)->GetRenderDevice()); engine->CameraLocation = Location; engine->CameraRotation = Rotation; - engine->ViewportX = (int)std::round(topLeft.x); - engine->ViewportY = (int)std::round(topLeft.y); - engine->ViewportWidth = (int)std::round(GetWidth()); - engine->ViewportHeight = (int)std::round(GetHeight()); - //engine->render->DrawEditorViewport(); + engine->ViewportX = (int)std::round(topLeft.x * GetDpiScale()); + engine->ViewportY = (int)std::round(topLeft.y * GetDpiScale()); + engine->ViewportWidth = (int)std::round(GetWidth() * GetDpiScale()); + engine->ViewportHeight = (int)std::round(GetHeight() * GetDpiScale()); + engine->render->DrawEditorViewport(); canvas->end3d(); } diff --git a/SurrealEngine/UI/Editor/EditorMainWindow.cpp b/SurrealEngine/UI/Editor/EditorMainWindow.cpp index 5c095a39..25bb6171 100644 --- a/SurrealEngine/UI/Editor/EditorMainWindow.cpp +++ b/SurrealEngine/UI/Editor/EditorMainWindow.cpp @@ -7,10 +7,26 @@ #include "UObject/UActor.h" #include "UObject/ULevel.h" #include "Utils/File.h" +#include "RenderDevice/RenderDevice.h" +#include +#include +#include #include -EditorMainWindow::EditorMainWindow() +EditorMainWindow::EditorMainWindow() : MainWindow(RenderAPI::Vulkan) { + std::shared_ptr instance = CreateZVulkanInstanceBuilder(this) + .OptionalSwapchainColorspace() + .DebugLayer(false) + .Create(); + + std::shared_ptr surface = CreateZVulkanSurface(this, instance); + if (!surface) + throw std::runtime_error("No vulkan surface found"); + + device = RenderDevice::Create(this, surface); + SetCanvas(std::make_unique(device.get())); + GetMenubar()->AddItem("File", [this](Menu* menu) { OnFileMenu(menu); }); GetMenubar()->AddItem("Edit", [this](Menu* menu) { OnEditMenu(menu); }); GetMenubar()->AddItem("View", [this](Menu* menu) { OnViewMenu(menu); }); diff --git a/SurrealEngine/UI/Editor/EditorMainWindow.h b/SurrealEngine/UI/Editor/EditorMainWindow.h index 6a9df4a1..47480e20 100644 --- a/SurrealEngine/UI/Editor/EditorMainWindow.h +++ b/SurrealEngine/UI/Editor/EditorMainWindow.h @@ -6,6 +6,7 @@ class EditorWorkspace; class Menu; +class RenderDevice; class EditorMainWindow : public MainWindow { @@ -52,5 +53,6 @@ class EditorMainWindow : public MainWindow private: void LoadMap(std::string& mapName); + std::unique_ptr device; std::unique_ptr openFileDialog = nullptr; }; diff --git a/Thirdparty/ZWidget/include/zwidget/widgets/mainwindow/mainwindow.h b/Thirdparty/ZWidget/include/zwidget/widgets/mainwindow/mainwindow.h index abba23d6..9db3daf3 100644 --- a/Thirdparty/ZWidget/include/zwidget/widgets/mainwindow/mainwindow.h +++ b/Thirdparty/ZWidget/include/zwidget/widgets/mainwindow/mainwindow.h @@ -10,7 +10,7 @@ class Statusbar; class MainWindow : public Widget { public: - MainWindow(); + MainWindow(RenderAPI api = RenderAPI::Unspecified); ~MainWindow(); Menubar* GetMenubar() const { return MenubarWidget; } diff --git a/Thirdparty/ZWidget/src/widgets/mainwindow/mainwindow.cpp b/Thirdparty/ZWidget/src/widgets/mainwindow/mainwindow.cpp index 7a98a2ce..0b4d713a 100644 --- a/Thirdparty/ZWidget/src/widgets/mainwindow/mainwindow.cpp +++ b/Thirdparty/ZWidget/src/widgets/mainwindow/mainwindow.cpp @@ -4,7 +4,7 @@ #include "widgets/toolbar/toolbar.h" #include "widgets/statusbar/statusbar.h" -MainWindow::MainWindow() : Widget(nullptr, WidgetType::Window) +MainWindow::MainWindow(RenderAPI api) : Widget(nullptr, WidgetType::Window, api) { MenubarWidget = new Menubar(this); // ToolbarWidget = new Toolbar(this); diff --git a/Thirdparty/ZWidget/src/window/win32/win32_open_file_dialog.cpp b/Thirdparty/ZWidget/src/window/win32/win32_open_file_dialog.cpp index 767ae3a2..092a78da 100644 --- a/Thirdparty/ZWidget/src/window/win32/win32_open_file_dialog.cpp +++ b/Thirdparty/ZWidget/src/window/win32/win32_open_file_dialog.cpp @@ -3,6 +3,10 @@ #include "win32_display_window.h" #include "core/widget.h" #include +#include +#include +#include +#include Win32OpenFileDialog::Win32OpenFileDialog(Win32DisplayWindow* owner) : owner(owner) { @@ -88,10 +92,35 @@ bool Win32OpenFileDialog::Show() } } - if (owner) - result = open_dialog->Show(owner->WindowHandle.hwnd); - else - result = open_dialog->Show(0); + // For some reason this can hang deep inside Win32 if we do it on the calling thread! + { + bool done = false; + std::mutex mutex; + std::condition_variable condvar; + + std::thread thread([&]() { + + if (owner) + result = open_dialog->Show(owner->WindowHandle.hwnd); + else + result = open_dialog->Show(0); + + std::unique_lock lock(mutex); + done = true; + condvar.notify_all(); + + }); + + std::unique_lock lock(mutex); + while (!done) + { + DisplayBackend::Get()->ProcessEvents(); + using namespace std::chrono_literals; + condvar.wait_for(lock, 50ms, [&]() { return done; }); + } + lock.unlock(); + thread.join(); + } if (SUCCEEDED(result)) {