mirror of
https://github.com/redstrate/Novus.git
synced 2025-07-22 15:17:45 +00:00
renderer: Add support for imgui
This commit is contained in:
parent
43c394bbf4
commit
5c9284106f
24 changed files with 51999 additions and 6 deletions
|
@ -13,4 +13,8 @@ License: MIT
|
|||
|
||||
Files: extern/magic_enum/*
|
||||
Copyright: 2019 - 2023 Daniil Goncharov
|
||||
License: MIT
|
||||
|
||||
Files: extern/imgui/*
|
||||
Copyright: 2014-2023 Omar Cornut
|
||||
License: MIT
|
|
@ -27,6 +27,7 @@ target_link_libraries(armoury PUBLIC
|
|||
magic_enum
|
||||
physis z
|
||||
mdlpart
|
||||
imgui
|
||||
NovusCommon)
|
||||
|
||||
install(TARGETS armoury
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <QThreadPool>
|
||||
#include <QVBoxLayout>
|
||||
#include <QtConcurrent>
|
||||
#include <imgui.h>
|
||||
|
||||
#include "filecache.h"
|
||||
#include "magic_enum.hpp"
|
||||
|
@ -21,6 +22,8 @@ GearView::GearView(GameData* data, FileCache& cache) : data(data), cache(cache)
|
|||
setLayout(layout);
|
||||
|
||||
mdlPart->requestUpdate = [this] {
|
||||
ImGui::Text("Hello, world!");
|
||||
|
||||
if (updating) {
|
||||
return;
|
||||
}
|
||||
|
|
3
extern/CMakeLists.txt
vendored
3
extern/CMakeLists.txt
vendored
|
@ -17,4 +17,5 @@ target_include_directories(physis INTERFACE ${libphysis_SOURCE_DIR}/target/publi
|
|||
target_link_libraries(physis INTERFACE unshield)
|
||||
|
||||
add_subdirectory(magic_enum)
|
||||
add_subdirectory(tinygltf)
|
||||
add_subdirectory(tinygltf)
|
||||
add_subdirectory(imgui)
|
13
extern/imgui/CMakeLists.txt
vendored
Normal file
13
extern/imgui/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
add_library(imgui STATIC)
|
||||
target_sources(imgui PRIVATE
|
||||
include/imconfig.h
|
||||
include/imgui.h
|
||||
|
||||
src/imgui.cpp
|
||||
src/imgui_demo.cpp
|
||||
src/imgui_draw.cpp
|
||||
src/imgui_internal.h
|
||||
src/imgui_tables.cpp
|
||||
src/imgui_widgets.cpp)
|
||||
target_include_directories(imgui PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
target_link_libraries(imgui PUBLIC stb::stb)
|
135
extern/imgui/include/imconfig.h
vendored
Normal file
135
extern/imgui/include/imconfig.h
vendored
Normal file
|
@ -0,0 +1,135 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// DEAR IMGUI COMPILE-TIME OPTIONS
|
||||
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
|
||||
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
|
||||
//-----------------------------------------------------------------------------
|
||||
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)
|
||||
// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template.
|
||||
//-----------------------------------------------------------------------------
|
||||
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
|
||||
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
|
||||
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
|
||||
// Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
//---- Define assertion handler. Defaults to calling assert().
|
||||
// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
|
||||
// #define IM_ASSERT(_EXPR) MyAssert(_EXPR)
|
||||
// #define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
|
||||
|
||||
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
|
||||
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI
|
||||
// compatibility. DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() for
|
||||
// each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
|
||||
// #define IMGUI_API __declspec( dllexport )
|
||||
// #define IMGUI_API __declspec( dllimport )
|
||||
|
||||
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.
|
||||
// #define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
// #define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87: disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This will be folded
|
||||
// into IMGUI_DISABLE_OBSOLETE_FUNCTIONS in a few versions.
|
||||
|
||||
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
|
||||
// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read
|
||||
// comments in imgui_demo.cpp.
|
||||
// #define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
|
||||
// #define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
|
||||
// #define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and
|
||||
// ShowStackToolWindow() will be empty (this was called IMGUI_DISABLE_METRICS_WINDOW before 1.88).
|
||||
|
||||
//---- Don't implement some functions to reduce linkage requirements.
|
||||
// #define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with
|
||||
// OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a) #define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32]
|
||||
// [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW) #define
|
||||
// IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require
|
||||
// imm32.lib/.a) #define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME). #define
|
||||
// IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this
|
||||
// is why this is not the default). #define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can
|
||||
// implement them yourself (e.g. if you don't want to link with vsnprintf) #define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement
|
||||
// ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself. #define IMGUI_DISABLE_FILE_FUNCTIONS // Don't
|
||||
// implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies) #define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS //
|
||||
// Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with
|
||||
// fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. #define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement
|
||||
// default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). #define IMGUI_DISABLE_SSE //
|
||||
// Disable use of SSE intrinsics even if available
|
||||
|
||||
//---- Include imgui_user.h at the end of imgui.h as a convenience
|
||||
// #define IMGUI_INCLUDE_IMGUI_USER_H
|
||||
|
||||
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
|
||||
// #define IMGUI_USE_BGRA_PACKED_COLOR
|
||||
|
||||
//---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient
|
||||
// languages, etc...) #define IMGUI_USE_WCHAR32
|
||||
|
||||
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
|
||||
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
|
||||
// #define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
|
||||
// #define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
|
||||
// #define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if IMGUI_USE_STB_SPRINTF is defined.
|
||||
// #define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
|
||||
// #define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
||||
// #define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION // only disabled if IMGUI_USE_STB_SPRINTF is defined.
|
||||
|
||||
//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
|
||||
// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.
|
||||
// #define IMGUI_USE_STB_SPRINTF
|
||||
|
||||
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
|
||||
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) +
|
||||
// the FreeType library (not provided). On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
|
||||
// #define IMGUI_ENABLE_FREETYPE
|
||||
|
||||
//---- Use FreeType+lunasvg library to render OpenType SVG fonts (SVGinOT)
|
||||
// Requires lunasvg headers to be available in the include path + program to be linked with the lunasvg library (not provided).
|
||||
// Only works in combination with IMGUI_ENABLE_FREETYPE.
|
||||
// (implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
|
||||
// #define IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||
|
||||
//---- Use stb_truetype to build and rasterize the font atlas (default)
|
||||
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
|
||||
// #define IMGUI_ENABLE_STB_TRUETYPE
|
||||
|
||||
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
|
||||
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
|
||||
/*
|
||||
#define IM_VEC2_CLASS_EXTRA \
|
||||
constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \
|
||||
operator MyVec2() const { return MyVec2(x,y); }
|
||||
|
||||
#define IM_VEC4_CLASS_EXTRA \
|
||||
constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \
|
||||
operator MyVec4() const { return MyVec4(x,y,z,w); }
|
||||
*/
|
||||
//---- ...Or use Dear ImGui's own very basic math operators.
|
||||
// #define IMGUI_DEFINE_MATH_OPERATORS
|
||||
|
||||
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
|
||||
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
|
||||
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
|
||||
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
|
||||
// #define ImDrawIdx unsigned int
|
||||
|
||||
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
|
||||
// struct ImDrawList;
|
||||
// struct ImDrawCmd;
|
||||
// typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
|
||||
// #define ImDrawCallback MyImDrawCallback
|
||||
|
||||
//---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase)
|
||||
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
|
||||
// #define IM_DEBUG_BREAK IM_ASSERT(0)
|
||||
// #define IM_DEBUG_BREAK __debugbreak()
|
||||
|
||||
//---- Debug Tools: Enable slower asserts
|
||||
// #define IMGUI_DEBUG_PARANOID
|
||||
|
||||
//---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files)
|
||||
/*
|
||||
namespace ImGui
|
||||
{
|
||||
void MyFunction(const char* name, MyMatrix44* mtx);
|
||||
}
|
||||
*/
|
4646
extern/imgui/include/imgui.h
vendored
Normal file
4646
extern/imgui/include/imgui.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
15692
extern/imgui/src/imgui.cpp
vendored
Normal file
15692
extern/imgui/src/imgui.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
8542
extern/imgui/src/imgui_demo.cpp
vendored
Normal file
8542
extern/imgui/src/imgui_demo.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
4575
extern/imgui/src/imgui_draw.cpp
vendored
Normal file
4575
extern/imgui/src/imgui_draw.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
4642
extern/imgui/src/imgui_internal.h
vendored
Normal file
4642
extern/imgui/src/imgui_internal.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
4178
extern/imgui/src/imgui_tables.cpp
vendored
Normal file
4178
extern/imgui/src/imgui_tables.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
9107
extern/imgui/src/imgui_widgets.cpp
vendored
Normal file
9107
extern/imgui/src/imgui_widgets.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
|
@ -16,6 +16,7 @@
|
|||
#include <glm/gtc/type_ptr.inl>
|
||||
|
||||
#include "filecache.h"
|
||||
#include "imgui.h"
|
||||
#include "tiny_gltf.h"
|
||||
|
||||
#ifndef USE_STANDALONE_WINDOW
|
||||
|
@ -116,9 +117,18 @@ public:
|
|||
}
|
||||
|
||||
void render() {
|
||||
ImGui::SetCurrentContext(m_renderer->ctx);
|
||||
|
||||
auto &io = ImGui::GetIO();
|
||||
io.DisplaySize = ImVec2(width(), height());
|
||||
|
||||
ImGui::NewFrame();
|
||||
|
||||
if (part->requestUpdate)
|
||||
part->requestUpdate();
|
||||
|
||||
ImGui::Render();
|
||||
|
||||
glm::vec3 position(
|
||||
part->cameraDistance * sin(part->yaw),
|
||||
part->cameraDistance * part->pitch,
|
||||
|
|
|
@ -7,9 +7,9 @@ if(USE_STANDALONE_WINDOW)
|
|||
set(EXTRA_LIBRARIES SDL2::SDL2)
|
||||
endif()
|
||||
|
||||
add_library(renderer STATIC src/renderer.cpp ${EXTRA_SRC})
|
||||
add_library(renderer STATIC src/renderer.cpp src/imguipass.cpp src/imguipass.h ${EXTRA_SRC})
|
||||
target_include_directories(renderer PUBLIC include)
|
||||
target_link_libraries(renderer PUBLIC Qt6::Core Vulkan::Vulkan physis z glm::glm ${EXTRA_LIBRARIES})
|
||||
target_link_libraries(renderer PUBLIC Qt6::Core Vulkan::Vulkan physis z glm::glm imgui ${EXTRA_LIBRARIES})
|
||||
target_compile_definitions(renderer PUBLIC GLM_FORCE_RADIANS GLM_FORCE_DEPTH_ZERO_TO_ONE)
|
||||
|
||||
if(USE_STANDALONE_WINDOW)
|
||||
|
|
|
@ -51,6 +51,9 @@ struct RenderModel {
|
|||
VkDeviceMemory boneInfoMemory = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
class ImGuiPass;
|
||||
struct ImGuiContext;
|
||||
|
||||
class Renderer {
|
||||
public:
|
||||
Renderer();
|
||||
|
@ -124,6 +127,10 @@ public:
|
|||
|
||||
glm::mat4 view;
|
||||
|
||||
ImGuiContext *ctx = nullptr;
|
||||
|
||||
private:
|
||||
void createDummyTexture();
|
||||
|
||||
ImGuiPass *imGuiPass = nullptr;
|
||||
};
|
|
@ -3,4 +3,6 @@
|
|||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
glslc mesh.vert -o mesh.vert.spv &&
|
||||
glslc mesh.frag -o mesh.frag.spv
|
||||
glslc mesh.frag -o mesh.frag.spv &&
|
||||
glslc imgui.vert -o imgui.vert.spv &&
|
||||
glslc imgui.frag -o imgui.frag.spv
|
15
renderer/shaders/imgui.frag
Normal file
15
renderer/shaders/imgui.frag
Normal file
|
@ -0,0 +1,15 @@
|
|||
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
#version 460 core
|
||||
|
||||
layout(location = 0) in vec2 inUV;
|
||||
layout(location = 1) in vec4 inColor;
|
||||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
layout(binding = 0) uniform sampler2D boundSampler;
|
||||
|
||||
void main() {
|
||||
outColor = inColor * texture(boundSampler, inUV);
|
||||
}
|
BIN
renderer/shaders/imgui.frag.spv
Normal file
BIN
renderer/shaders/imgui.frag.spv
Normal file
Binary file not shown.
21
renderer/shaders/imgui.vert
Normal file
21
renderer/shaders/imgui.vert
Normal file
|
@ -0,0 +1,21 @@
|
|||
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
#version 460 core
|
||||
|
||||
layout(location = 0) in vec2 inPos;
|
||||
layout(location = 1) in vec2 inUV;
|
||||
layout(location = 2) in vec4 inColor;
|
||||
|
||||
layout(push_constant) uniform PushConstants {
|
||||
vec2 scale, translate;
|
||||
} pushConstants;
|
||||
|
||||
layout(location = 0) out vec2 outUV;
|
||||
layout(location = 1) out vec4 outColor;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(inPos * pushConstants.scale + pushConstants.translate, 0.0, 1.0);
|
||||
outUV = inUV;
|
||||
outColor = inColor;
|
||||
}
|
BIN
renderer/shaders/imgui.vert.spv
Normal file
BIN
renderer/shaders/imgui.vert.spv
Normal file
Binary file not shown.
341
renderer/src/imguipass.cpp
Normal file
341
renderer/src/imguipass.cpp
Normal file
|
@ -0,0 +1,341 @@
|
|||
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "imguipass.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <array>
|
||||
#include <glm/glm.hpp>
|
||||
#include <imgui.h>
|
||||
|
||||
#include "renderer.hpp"
|
||||
|
||||
ImGuiPass::ImGuiPass(Renderer &renderer)
|
||||
: renderer_(renderer)
|
||||
{
|
||||
createDescriptorSetLayout();
|
||||
createPipeline();
|
||||
createFontImage();
|
||||
}
|
||||
|
||||
ImGuiPass::~ImGuiPass()
|
||||
{
|
||||
vkDestroySampler(renderer_.device, fontSampler_, nullptr);
|
||||
vkDestroyImageView(renderer_.device, fontImageView_, nullptr);
|
||||
vkFreeMemory(renderer_.device, fontMemory_, nullptr);
|
||||
vkDestroyImage(renderer_.device, fontImage_, nullptr);
|
||||
|
||||
vkDestroyPipeline(renderer_.device, pipeline_, nullptr);
|
||||
vkDestroyPipelineLayout(renderer_.device, pipelineLayout_, nullptr);
|
||||
|
||||
vkDestroyDescriptorSetLayout(renderer_.device, setLayout_, nullptr);
|
||||
}
|
||||
|
||||
void ImGuiPass::render(VkCommandBuffer commandBuffer)
|
||||
{
|
||||
ImDrawData *drawData = ImGui::GetDrawData();
|
||||
if (drawData == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t newVertexSize = drawData->TotalVtxCount * sizeof(ImDrawVert);
|
||||
if (newVertexSize > vertexSize) {
|
||||
createBuffer(vertexBuffer, vertexMemory, newVertexSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
|
||||
vertexSize = newVertexSize;
|
||||
}
|
||||
|
||||
const size_t newIndexSize = drawData->TotalIdxCount * sizeof(ImDrawIdx);
|
||||
if (newIndexSize > indexSize) {
|
||||
createBuffer(indexBuffer, indexMemory, newIndexSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
|
||||
indexSize = newIndexSize;
|
||||
}
|
||||
|
||||
if (vertexSize == 0 || indexSize == 0)
|
||||
return;
|
||||
|
||||
ImDrawVert *vertexData = nullptr;
|
||||
ImDrawIdx *indexData = nullptr;
|
||||
vkMapMemory(renderer_.device, vertexMemory, 0, vertexSize, 0, reinterpret_cast<void **>(&vertexData));
|
||||
vkMapMemory(renderer_.device, indexMemory, 0, indexSize, 0, reinterpret_cast<void **>(&indexData));
|
||||
|
||||
for (int i = 0; i < drawData->CmdListsCount; i++) {
|
||||
const ImDrawList *cmd_list = drawData->CmdLists[i];
|
||||
|
||||
memcpy(vertexData, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
|
||||
vertexData += cmd_list->VtxBuffer.Size;
|
||||
|
||||
memcpy(indexData, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||
indexData += cmd_list->IdxBuffer.Size;
|
||||
}
|
||||
|
||||
vkUnmapMemory(renderer_.device, vertexMemory);
|
||||
vkUnmapMemory(renderer_.device, indexMemory);
|
||||
|
||||
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_);
|
||||
|
||||
VkDeviceSize offset = 0;
|
||||
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertexBuffer, &offset);
|
||||
vkCmdBindIndexBuffer(commandBuffer, indexBuffer, 0, VK_INDEX_TYPE_UINT16);
|
||||
|
||||
float scale[2];
|
||||
scale[0] = 2.0f / drawData->DisplaySize.x;
|
||||
scale[1] = 2.0f / drawData->DisplaySize.y;
|
||||
|
||||
float translate[2];
|
||||
translate[0] = -1.0f - drawData->DisplayPos.x * scale[0];
|
||||
translate[1] = -1.0f - drawData->DisplayPos.y * scale[1];
|
||||
|
||||
vkCmdPushConstants(commandBuffer, pipelineLayout_, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 0, sizeof(float) * 2, scale);
|
||||
vkCmdPushConstants(commandBuffer, pipelineLayout_, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 2, sizeof(float) * 2, translate);
|
||||
|
||||
int vertexOffset = 0, indexOffset = 0;
|
||||
const ImVec2 displayPos = drawData->DisplayPos;
|
||||
for (int n = 0; n < drawData->CmdListsCount; n++) {
|
||||
const ImDrawList *cmd_list = drawData->CmdLists[n];
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) {
|
||||
const ImDrawCmd *pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
|
||||
if (descriptorSets_.count((VkImageView)pcmd->TextureId)) {
|
||||
vkCmdBindDescriptorSets(commandBuffer,
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
pipelineLayout_,
|
||||
0,
|
||||
1,
|
||||
&descriptorSets_[(VkImageView)pcmd->TextureId],
|
||||
0,
|
||||
nullptr);
|
||||
} else {
|
||||
VkDescriptorSetAllocateInfo allocInfo = {};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
allocInfo.descriptorPool = renderer_.descriptorPool;
|
||||
allocInfo.descriptorSetCount = 1;
|
||||
allocInfo.pSetLayouts = &setLayout_;
|
||||
|
||||
VkDescriptorSet set = nullptr;
|
||||
vkAllocateDescriptorSets(renderer_.device, &allocInfo, &set);
|
||||
|
||||
VkDescriptorImageInfo imageInfo = {};
|
||||
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
imageInfo.imageView = (VkImageView)pcmd->TextureId;
|
||||
imageInfo.sampler = fontSampler_;
|
||||
|
||||
VkWriteDescriptorSet descriptorWrite = {};
|
||||
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
descriptorWrite.descriptorCount = 1;
|
||||
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
descriptorWrite.dstSet = set;
|
||||
descriptorWrite.pImageInfo = &imageInfo;
|
||||
|
||||
vkUpdateDescriptorSets(renderer_.device, 1, &descriptorWrite, 0, nullptr);
|
||||
|
||||
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &set, 0, nullptr);
|
||||
|
||||
descriptorSets_[(VkImageView)pcmd->TextureId] = set;
|
||||
}
|
||||
|
||||
if (pcmd->UserCallback) {
|
||||
pcmd->UserCallback(cmd_list, pcmd);
|
||||
} else {
|
||||
VkRect2D scissor;
|
||||
scissor.offset.x = (int32_t)(pcmd->ClipRect.x - displayPos.x) > 0 ? (int32_t)(pcmd->ClipRect.x - displayPos.x) : 0;
|
||||
scissor.offset.y = (int32_t)(pcmd->ClipRect.y - displayPos.y) > 0 ? (int32_t)(pcmd->ClipRect.y - displayPos.y) : 0;
|
||||
scissor.extent.width = (uint32_t)(pcmd->ClipRect.z - pcmd->ClipRect.x);
|
||||
scissor.extent.height = (uint32_t)(pcmd->ClipRect.w - pcmd->ClipRect.y + 1);
|
||||
|
||||
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
||||
|
||||
vkCmdDrawIndexed(commandBuffer, pcmd->ElemCount, 1, indexOffset, vertexOffset, 0);
|
||||
}
|
||||
|
||||
indexOffset += pcmd->ElemCount;
|
||||
}
|
||||
|
||||
vertexOffset += cmd_list->VtxBuffer.Size;
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiPass::createDescriptorSetLayout()
|
||||
{
|
||||
VkDescriptorSetLayoutBinding samplerBinding = {};
|
||||
samplerBinding.descriptorCount = 1;
|
||||
samplerBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
samplerBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
|
||||
VkDescriptorSetLayoutCreateInfo createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||
createInfo.bindingCount = 1;
|
||||
createInfo.pBindings = &samplerBinding;
|
||||
|
||||
vkCreateDescriptorSetLayout(renderer_.device, &createInfo, nullptr, &setLayout_);
|
||||
}
|
||||
|
||||
void ImGuiPass::createPipeline()
|
||||
{
|
||||
VkShaderModule vertShaderModule = renderer_.loadShaderFromDisk("imgui.vert.spv");
|
||||
VkShaderModule fragShaderModule = renderer_.loadShaderFromDisk("imgui.frag.spv");
|
||||
|
||||
VkPipelineShaderStageCreateInfo vertShaderStageInfo = {};
|
||||
vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
vertShaderStageInfo.module = vertShaderModule;
|
||||
vertShaderStageInfo.pName = "main";
|
||||
|
||||
VkPipelineShaderStageCreateInfo fragShaderStageInfo = {};
|
||||
fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
fragShaderStageInfo.module = fragShaderModule;
|
||||
fragShaderStageInfo.pName = "main";
|
||||
|
||||
const std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages = {vertShaderStageInfo, fragShaderStageInfo};
|
||||
|
||||
VkVertexInputBindingDescription vertexBindingDescription = {};
|
||||
vertexBindingDescription.stride = sizeof(ImDrawVert);
|
||||
vertexBindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
|
||||
VkVertexInputAttributeDescription positionAttribute = {};
|
||||
positionAttribute.format = VK_FORMAT_R32G32_SFLOAT;
|
||||
positionAttribute.offset = offsetof(ImDrawVert, pos);
|
||||
|
||||
VkVertexInputAttributeDescription uvAttribute = {};
|
||||
uvAttribute.location = 1;
|
||||
uvAttribute.format = VK_FORMAT_R32G32_SFLOAT;
|
||||
uvAttribute.offset = offsetof(ImDrawVert, uv);
|
||||
|
||||
VkVertexInputAttributeDescription colorAttribute = {};
|
||||
colorAttribute.location = 2;
|
||||
colorAttribute.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
colorAttribute.offset = offsetof(ImDrawVert, col);
|
||||
|
||||
const std::array<VkVertexInputAttributeDescription, 3> attributes = {positionAttribute, uvAttribute, colorAttribute};
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
|
||||
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||
vertexInputInfo.vertexBindingDescriptionCount = 1;
|
||||
vertexInputInfo.pVertexBindingDescriptions = &vertexBindingDescription;
|
||||
vertexInputInfo.vertexAttributeDescriptionCount = attributes.size();
|
||||
vertexInputInfo.pVertexAttributeDescriptions = attributes.data();
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
|
||||
inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||
inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
|
||||
VkPipelineViewportStateCreateInfo viewportState = {};
|
||||
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||
viewportState.viewportCount = 1;
|
||||
viewportState.scissorCount = 1;
|
||||
|
||||
VkPipelineRasterizationStateCreateInfo rasterizer = {};
|
||||
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||
rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
|
||||
rasterizer.cullMode = VK_CULL_MODE_NONE;
|
||||
rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
|
||||
rasterizer.lineWidth = 1.0f;
|
||||
|
||||
VkPipelineMultisampleStateCreateInfo multisampling = {};
|
||||
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
|
||||
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||
colorBlendAttachment.blendEnable = VK_TRUE;
|
||||
colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
||||
colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
|
||||
colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||
|
||||
VkPipelineColorBlendStateCreateInfo colorBlending = {};
|
||||
colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||
colorBlending.attachmentCount = 1;
|
||||
colorBlending.pAttachments = &colorBlendAttachment;
|
||||
|
||||
const std::array<VkDynamicState, 2> dynamicStates = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
|
||||
|
||||
VkPipelineDynamicStateCreateInfo dynamicState = {};
|
||||
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||
dynamicState.dynamicStateCount = dynamicStates.size();
|
||||
dynamicState.pDynamicStates = dynamicStates.data();
|
||||
|
||||
VkPushConstantRange pushConstant = {};
|
||||
pushConstant.size = sizeof(glm::vec4);
|
||||
pushConstant.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
|
||||
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
pipelineLayoutInfo.setLayoutCount = 1;
|
||||
pipelineLayoutInfo.pSetLayouts = &setLayout_;
|
||||
pipelineLayoutInfo.pushConstantRangeCount = 1;
|
||||
pipelineLayoutInfo.pPushConstantRanges = &pushConstant;
|
||||
|
||||
vkCreatePipelineLayout(renderer_.device, &pipelineLayoutInfo, nullptr, &pipelineLayout_);
|
||||
|
||||
VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = {};
|
||||
depthStencilStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||||
|
||||
VkGraphicsPipelineCreateInfo pipelineInfo = {};
|
||||
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||
pipelineInfo.stageCount = shaderStages.size();
|
||||
pipelineInfo.pStages = shaderStages.data();
|
||||
pipelineInfo.pVertexInputState = &vertexInputInfo;
|
||||
pipelineInfo.pInputAssemblyState = &inputAssembly;
|
||||
pipelineInfo.pViewportState = &viewportState;
|
||||
pipelineInfo.pRasterizationState = &rasterizer;
|
||||
pipelineInfo.pMultisampleState = &multisampling;
|
||||
pipelineInfo.pColorBlendState = &colorBlending;
|
||||
pipelineInfo.pDynamicState = &dynamicState;
|
||||
pipelineInfo.layout = pipelineLayout_;
|
||||
pipelineInfo.pDepthStencilState = &depthStencilStateCreateInfo;
|
||||
pipelineInfo.renderPass = renderer_.renderPass;
|
||||
|
||||
vkCreateGraphicsPipelines(renderer_.device, nullptr, 1, &pipelineInfo, nullptr, &pipeline_);
|
||||
|
||||
vkDestroyShaderModule(renderer_.device, fragShaderModule, nullptr);
|
||||
vkDestroyShaderModule(renderer_.device, vertShaderModule, nullptr);
|
||||
}
|
||||
|
||||
void ImGuiPass::createFontImage()
|
||||
{
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
|
||||
unsigned char *pixels = nullptr;
|
||||
int width = 0, height = 0;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||
|
||||
qInfo() << "Uploading imgui font size" << width << "x" << height;
|
||||
|
||||
auto texture = renderer_.addTexture(width, height, pixels, width * height * 4);
|
||||
fontImageView_ = texture.view;
|
||||
fontSampler_ = texture.sampler;
|
||||
|
||||
io.Fonts->SetTexID(static_cast<ImTextureID>(fontImageView_));
|
||||
}
|
||||
|
||||
void ImGuiPass::createBuffer(VkBuffer &buffer, VkDeviceMemory &memory, VkDeviceSize size, VkBufferUsageFlagBits bufferUsage)
|
||||
{
|
||||
if (buffer != nullptr)
|
||||
vkDestroyBuffer(renderer_.device, buffer, nullptr);
|
||||
|
||||
if (memory != nullptr)
|
||||
vkFreeMemory(renderer_.device, memory, nullptr);
|
||||
|
||||
VkBufferCreateInfo bufferInfo = {};
|
||||
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
bufferInfo.size = size;
|
||||
bufferInfo.usage = bufferUsage;
|
||||
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
|
||||
vkCreateBuffer(renderer_.device, &bufferInfo, nullptr, &buffer);
|
||||
|
||||
VkMemoryRequirements memRequirements = {};
|
||||
vkGetBufferMemoryRequirements(renderer_.device, buffer, &memRequirements);
|
||||
|
||||
VkMemoryAllocateInfo allocInfo = {};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
allocInfo.allocationSize = memRequirements.size;
|
||||
allocInfo.memoryTypeIndex =
|
||||
renderer_.findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
|
||||
vkAllocateMemory(renderer_.device, &allocInfo, nullptr, &memory);
|
||||
vkBindBufferMemory(renderer_.device, buffer, memory, 0);
|
||||
}
|
43
renderer/src/imguipass.h
Normal file
43
renderer/src/imguipass.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
class Renderer;
|
||||
struct RenderTarget;
|
||||
|
||||
class ImGuiPass
|
||||
{
|
||||
public:
|
||||
ImGuiPass(Renderer &renderer);
|
||||
~ImGuiPass();
|
||||
|
||||
void render(VkCommandBuffer commandBuffer);
|
||||
|
||||
private:
|
||||
void createDescriptorSetLayout();
|
||||
void createPipeline();
|
||||
void createFontImage();
|
||||
void createBuffer(VkBuffer &buffer, VkDeviceMemory &memory, VkDeviceSize size, VkBufferUsageFlagBits bufferUsage);
|
||||
|
||||
VkDescriptorSetLayout setLayout_ = nullptr;
|
||||
|
||||
VkPipelineLayout pipelineLayout_ = nullptr;
|
||||
VkPipeline pipeline_ = nullptr;
|
||||
|
||||
VkImage fontImage_ = nullptr;
|
||||
VkDeviceMemory fontMemory_ = nullptr;
|
||||
VkImageView fontImageView_ = nullptr;
|
||||
VkSampler fontSampler_ = nullptr;
|
||||
|
||||
VkBuffer vertexBuffer = VK_NULL_HANDLE, indexBuffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory vertexMemory = VK_NULL_HANDLE, indexMemory = VK_NULL_HANDLE;
|
||||
size_t vertexSize = 0, indexSize = 0;
|
||||
|
||||
std::map<VkImageView, VkDescriptorSet> descriptorSets_ = {};
|
||||
|
||||
Renderer &renderer_;
|
||||
};
|
|
@ -12,6 +12,9 @@
|
|||
#include <vector>
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imguipass.h"
|
||||
|
||||
VkResult CreateDebugUtilsMessengerEXT(
|
||||
VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
|
||||
const VkAllocationCallbacks* pAllocator,
|
||||
|
@ -39,6 +42,11 @@ DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
|||
}
|
||||
|
||||
Renderer::Renderer() {
|
||||
ctx = ImGui::CreateContext();
|
||||
ImGui::SetCurrentContext(ctx);
|
||||
|
||||
ImGui::StyleColorsDark();
|
||||
|
||||
VkApplicationInfo applicationInfo = {};
|
||||
|
||||
std::vector<const char*> instanceExtensions = {"VK_EXT_debug_utils"};
|
||||
|
@ -422,6 +430,9 @@ bool Renderer::initSwapchain(VkSurfaceKHR surface, int width, int height) {
|
|||
vkCreateFence(device, &fenceCreateInfo, nullptr, &inFlightFences[i]);
|
||||
}
|
||||
|
||||
ImGui::SetCurrentContext(ctx);
|
||||
imGuiPass = new ImGuiPass(*this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -538,8 +549,12 @@ void Renderer::render(std::vector<RenderModel> models) {
|
|||
}
|
||||
}
|
||||
|
||||
vkCmdEndRenderPass(commandBuffer);
|
||||
if (imGuiPass != nullptr) {
|
||||
ImGui::SetCurrentContext(ctx);
|
||||
imGuiPass->render(commandBuffer);
|
||||
}
|
||||
|
||||
vkCmdEndRenderPass(commandBuffer);
|
||||
vkEndCommandBuffer(commandBuffer);
|
||||
|
||||
VkSubmitInfo submitInfo = {};
|
||||
|
@ -1191,7 +1206,7 @@ VkDescriptorSet Renderer::createDescriptorFor(const RenderModel& model, const Re
|
|||
|
||||
vkAllocateDescriptorSets(device, &allocateInfo, &set);
|
||||
if (set == VK_NULL_HANDLE) {
|
||||
qFatal("Failed to create descriptor set!");
|
||||
// qFatal("Failed to create descriptor set!");
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue