Compare commits
4 Commits
d56918e71d
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5aa085da9 | ||
|
|
4228fe554d | ||
|
|
561a92d557 | ||
| e354e20e54 |
@@ -9,6 +9,7 @@ if not hasattr(env, 'Jinja'):
|
|||||||
src_files = Split("""
|
src_files = Split("""
|
||||||
application.cpp
|
application.cpp
|
||||||
config.cpp
|
config.cpp
|
||||||
|
imutil.cpp
|
||||||
fonts.gen.cpp
|
fonts.gen.cpp
|
||||||
stb_image.cpp
|
stb_image.cpp
|
||||||
""")
|
""")
|
||||||
|
|||||||
@@ -459,6 +459,7 @@ bool Application::init()
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (!initImGui())
|
if (!initImGui())
|
||||||
{
|
{
|
||||||
@@ -501,6 +502,10 @@ void Application::cleanup()
|
|||||||
vk.DeviceWaitIdle(vk.device);
|
vk.DeviceWaitIdle(vk.device);
|
||||||
vk.DestroyDevice(vk.device, nullptr);
|
vk.DestroyDevice(vk.device, nullptr);
|
||||||
}
|
}
|
||||||
|
if (vk.debugUtilsMessenger != nullptr)
|
||||||
|
{
|
||||||
|
vk.DestroyDebugUtilsMessengerEXT(vk.instance, vk.debugUtilsMessenger, /* pAllocator = */ nullptr);
|
||||||
|
}
|
||||||
if (vk.instance != nullptr)
|
if (vk.instance != nullptr)
|
||||||
{
|
{
|
||||||
vk.DestroyInstance(vk.instance, nullptr);
|
vk.DestroyInstance(vk.instance, nullptr);
|
||||||
@@ -592,18 +597,90 @@ bool Application::initOpenGL()
|
|||||||
bool Application::initVulkan()
|
bool Application::initVulkan()
|
||||||
{
|
{
|
||||||
vk.GetInstanceProc = reinterpret_cast<vkGetInstanceProcAddr_fn_t>(SDL_Vulkan_GetVkGetInstanceProcAddr());
|
vk.GetInstanceProc = reinterpret_cast<vkGetInstanceProcAddr_fn_t>(SDL_Vulkan_GetVkGetInstanceProcAddr());
|
||||||
|
vk.EnumerateInstanceLayerProperties = reinterpret_cast<vkEnumerateInstanceLayerProperties_fn_t>(vk.GetInstanceProc(nullptr, "vkEnumerateInstanceLayerProperties"));
|
||||||
|
vk.EnumerateInstanceExtensionProperties = reinterpret_cast<vkEnumerateInstanceExtensionProperties_fn_t>(vk.GetInstanceProc(nullptr, "vkEnumerateInstanceExtensionProperties"));
|
||||||
vk.CreateInstance = reinterpret_cast<vkCreateInstance_fn_t>(vk.GetInstanceProc(nullptr, "vkCreateInstance"));
|
vk.CreateInstance = reinterpret_cast<vkCreateInstance_fn_t>(vk.GetInstanceProc(nullptr, "vkCreateInstance"));
|
||||||
|
|
||||||
|
std::uint32_t numInstanceLayers = 0;
|
||||||
|
if (const VkResult result = vk.EnumerateInstanceLayerProperties(&numInstanceLayers, nullptr); result != VK_SUCCESS && result != VK_INCOMPLETE)
|
||||||
|
{
|
||||||
|
msgError("Error enumerating instance layers: 0x{:x}.", static_cast<unsigned>(result));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::vector<VkLayerProperties> instanceLayers;
|
||||||
|
instanceLayers.resize(numInstanceLayers);
|
||||||
|
if (const VkResult result = vk.EnumerateInstanceLayerProperties(&numInstanceLayers, instanceLayers.data()); result != VK_SUCCESS && result != VK_INCOMPLETE)
|
||||||
|
{
|
||||||
|
msgError("Error enumerating instance layers: 0x{:x}.", static_cast<unsigned>(result));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<const char*> enabledInstanceLayers;
|
||||||
|
for (const VkLayerProperties& props : instanceLayers) {
|
||||||
|
if (std::strcmp(props.layerName, "VK_LAYER_KHRONOS_validation") == 0) {
|
||||||
|
enabledInstanceLayers.push_back("VK_LAYER_KHRONOS_validation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t numInstanceExtensions = 0;
|
||||||
|
if (const VkResult result = vk.EnumerateInstanceExtensionProperties(nullptr, &numInstanceExtensions, nullptr); result != VK_SUCCESS && result != VK_INCOMPLETE)
|
||||||
|
{
|
||||||
|
msgError("Error enumerating instance extensions: 0x{:x}.", static_cast<unsigned>(result));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::vector<VkExtensionProperties> instanceExtensions;
|
||||||
|
instanceExtensions.resize(numInstanceExtensions);
|
||||||
|
if (const VkResult result = vk.EnumerateInstanceExtensionProperties(nullptr, &numInstanceExtensions, instanceExtensions.data()); result != VK_SUCCESS && result != VK_INCOMPLETE)
|
||||||
|
{
|
||||||
|
msgError("Error enumerating instance extensions: 0x{:x}.", static_cast<unsigned>(result));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t numSdlExtensions = 0;
|
||||||
|
const char* const* sdlExtensions = SDL_Vulkan_GetInstanceExtensions(&numSdlExtensions);
|
||||||
|
std::uint32_t numSupportedSdlExtensions = 0;
|
||||||
|
|
||||||
|
bool hasDebugUtils = false;
|
||||||
|
std::vector<const char*> enabledInstanceExtensions;
|
||||||
|
for (const VkExtensionProperties& props : instanceExtensions) {
|
||||||
|
if (std::strcmp(props.extensionName, "VK_EXT_debug_utils") == 0)
|
||||||
|
{
|
||||||
|
enabledInstanceExtensions.push_back("VK_EXT_debug_utils");
|
||||||
|
hasDebugUtils = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (std::uint32_t idx = 0; idx < numSdlExtensions; ++idx)
|
||||||
|
{
|
||||||
|
if (std::strncmp(props.extensionName, sdlExtensions[idx], VK_MAX_EXTENSION_NAME_SIZE) == 0)
|
||||||
|
{
|
||||||
|
enabledInstanceExtensions.push_back(sdlExtensions[idx]);
|
||||||
|
++numSupportedSdlExtensions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numSupportedSdlExtensions != numSdlExtensions)
|
||||||
|
{
|
||||||
|
msgError("Cannot create Vulkan device, not all required instance extensions are supported.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const VkApplicationInfo applicationInfo = {
|
const VkApplicationInfo applicationInfo = {
|
||||||
.apiVersion = vkMakeApiVersion(0, 1, 3, 0) // TODO: probably should let the user specify this?
|
.apiVersion = vkMakeApiVersion(0, 1, 3, 0) // TODO: probably should let the user specify this?
|
||||||
};
|
};
|
||||||
const VkInstanceCreateInfo instanceCreateInfo = {
|
const VkInstanceCreateInfo instanceCreateInfo = {
|
||||||
.pApplicationInfo = &applicationInfo
|
.pApplicationInfo = &applicationInfo,
|
||||||
|
.enabledLayerCount = static_cast<std::uint32_t>(enabledInstanceLayers.size()),
|
||||||
|
.ppEnabledLayerNames = enabledInstanceLayers.data(),
|
||||||
|
.enabledExtensionCount = static_cast<std::uint32_t>(enabledInstanceExtensions.size()),
|
||||||
|
.ppEnabledExtensionNames = enabledInstanceExtensions.data()
|
||||||
};
|
};
|
||||||
|
|
||||||
if (const VkResult result = vk.CreateInstance(&instanceCreateInfo, nullptr, &vk.instance); result != VK_SUCCESS)
|
if (const VkResult result = vk.CreateInstance(&instanceCreateInfo, nullptr, &vk.instance); result != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
msgError("Error creating Vulkan instance: {:x}.", static_cast<unsigned>(result));
|
msgError("Error creating Vulkan instance: 0x{:x}.", static_cast<unsigned>(result));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -615,11 +692,35 @@ bool Application::initVulkan()
|
|||||||
vk.DeviceWaitIdle = reinterpret_cast<vkDeviceWaitIdle_fn_t>(vk.GetInstanceProc(vk.instance, "vkDeviceWaitIdle"));
|
vk.DeviceWaitIdle = reinterpret_cast<vkDeviceWaitIdle_fn_t>(vk.GetInstanceProc(vk.instance, "vkDeviceWaitIdle"));
|
||||||
vk.GetDeviceQueue = reinterpret_cast<vkGetDeviceQueue_fn_t>(vk.GetInstanceProc(vk.instance, "vkGetDeviceQueue"));
|
vk.GetDeviceQueue = reinterpret_cast<vkGetDeviceQueue_fn_t>(vk.GetInstanceProc(vk.instance, "vkGetDeviceQueue"));
|
||||||
|
|
||||||
|
if (hasDebugUtils)
|
||||||
|
{
|
||||||
|
vk.CreateDebugUtilsMessengerEXT = reinterpret_cast<vkCreateDebugUtilsMessengerEXT_fn_t>(vk.GetInstanceProc(vk.instance, "vkCreateDebugUtilsMessengerEXT"));
|
||||||
|
vk.DestroyDebugUtilsMessengerEXT = reinterpret_cast<vkDestroyDebugUtilsMessengerEXT_fn_t>(vk.GetInstanceProc(vk.instance, "vkDestroyDebugUtilsMessengerEXT"));
|
||||||
|
|
||||||
|
const VkDebugUtilsMessengerCreateInfoEXT messengerCreateInfo = {
|
||||||
|
.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
|
||||||
|
.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
|
||||||
|
.pfnUserCallback = [](VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) {
|
||||||
|
return static_cast<Application*>(pUserData)->handleDebugUtilsMessage(messageSeverity, messageTypes, pCallbackData);
|
||||||
|
},
|
||||||
|
.pUserData = this
|
||||||
|
};
|
||||||
|
|
||||||
|
if (const VkResult result = vk.CreateDebugUtilsMessengerEXT(vk.instance, &messengerCreateInfo, /* pAllocator = */ nullptr, &vk.debugUtilsMessenger); result != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
msgWarning("Error creating Vulkan debug utils messenger: 0x{:x}.", static_cast<unsigned>(result));
|
||||||
|
vk.debugUtilsMessenger = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vk.debugUtilsMessenger = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: this is really cheap... (but should be sufficient in most cases)
|
// TODO: this is really cheap... (but should be sufficient in most cases)
|
||||||
std::uint32_t physicalDeviceCount = 1;
|
std::uint32_t physicalDeviceCount = 1;
|
||||||
if (const VkResult result = vk.EnumeratePhysicalDevices(vk.instance, &physicalDeviceCount, &vk.physicalDevice); result != VK_SUCCESS)
|
if (const VkResult result = vk.EnumeratePhysicalDevices(vk.instance, &physicalDeviceCount, &vk.physicalDevice); result != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
msgError("Error enumerating Vulkan physical devices: {:x}.", static_cast<unsigned>(result));
|
msgError("Error enumerating Vulkan physical devices: 0x{:x}.", static_cast<unsigned>(result));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -634,7 +735,10 @@ bool Application::initVulkan()
|
|||||||
std::uint32_t queueFamilyIndex = 0;
|
std::uint32_t queueFamilyIndex = 0;
|
||||||
for (; queueFamilyIndex < queueFamilyPropertyCount; ++queueFamilyIndex)
|
for (; queueFamilyIndex < queueFamilyPropertyCount; ++queueFamilyIndex)
|
||||||
{
|
{
|
||||||
if (queueFamilyProperties[queueFamilyIndex].queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
const bool supportsGraphics = queueFamilyProperties[queueFamilyIndex].queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT;
|
||||||
|
const bool supportsPresent = SDL_Vulkan_GetPresentationSupport(vk.instance, vk.physicalDevice, queueFamilyIndex);
|
||||||
|
|
||||||
|
if (supportsGraphics && supportsPresent) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -652,7 +756,7 @@ bool Application::initVulkan()
|
|||||||
.pQueuePriorities = &queuePriority
|
.pQueuePriorities = &queuePriority
|
||||||
};
|
};
|
||||||
static const std::array DEVICE_EXTENSIONS = {
|
static const std::array DEVICE_EXTENSIONS = {
|
||||||
"VK_KHR_surface"
|
"VK_KHR_swapchain"
|
||||||
};
|
};
|
||||||
const VkDeviceCreateInfo deviceCreateInfo = {
|
const VkDeviceCreateInfo deviceCreateInfo = {
|
||||||
.queueCreateInfoCount = 1,
|
.queueCreateInfoCount = 1,
|
||||||
@@ -662,7 +766,7 @@ bool Application::initVulkan()
|
|||||||
};
|
};
|
||||||
if (const VkResult result = vk.CreateDevice(vk.physicalDevice, &deviceCreateInfo, nullptr, &vk.device); result != VK_SUCCESS)
|
if (const VkResult result = vk.CreateDevice(vk.physicalDevice, &deviceCreateInfo, nullptr, &vk.device); result != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
msgError("Error creating Vulkan device: {:x}.", static_cast<unsigned>(result));
|
msgError("Error creating Vulkan device: 0x{:x}.", static_cast<unsigned>(result));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
vk.GetDeviceQueue(vk.device, /* queueFamilyIndex = */ 0, /* queueIndex = */ 0, &vk.queue);
|
vk.GetDeviceQueue(vk.device, /* queueFamilyIndex = */ 0, /* queueIndex = */ 0, &vk.queue);
|
||||||
@@ -788,6 +892,25 @@ void Application::saveImGuiConfig()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Application::handleDebugUtilsMessage(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||||
|
VkDebugUtilsMessageTypeFlagsEXT /* messageTypes */,
|
||||||
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData) -> VkBool32
|
||||||
|
{
|
||||||
|
switch (messageSeverity)
|
||||||
|
{
|
||||||
|
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
|
||||||
|
msgError("Vulkan debug error message: {}.", pCallbackData->pMessage);
|
||||||
|
break;
|
||||||
|
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
|
||||||
|
msgWarning("Vulkan debug warning message: {}.", pCallbackData->pMessage);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
msgInfo("Vulkan debug message: {}.", pCallbackData->pMessage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void QuickApp::preInit(QuickAppOptions options)
|
void QuickApp::preInit(QuickAppOptions options)
|
||||||
{
|
{
|
||||||
MIJIN_ASSERT_FATAL(options.callbacks.render, "Missing render callback.");
|
MIJIN_ASSERT_FATAL(options.callbacks.render, "Missing render callback.");
|
||||||
|
|||||||
7
private/raid/imutil.cpp
Normal file
7
private/raid/imutil.cpp
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
#include "raid/imutil.hpp"
|
||||||
|
|
||||||
|
namespace raid::impl
|
||||||
|
{
|
||||||
|
// std::string gFormatBuffer;
|
||||||
|
}
|
||||||
@@ -157,23 +157,23 @@ protected:
|
|||||||
void msgInfo(const char* text)
|
void msgInfo(const char* text)
|
||||||
{
|
{
|
||||||
handleMessage({
|
handleMessage({
|
||||||
.severity = MessageSeverity::INFO,
|
.severity = MessageSeverity::INFO,
|
||||||
.text = text
|
.text = text
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
void msgWarning(const char* text)
|
void msgWarning(const char* text)
|
||||||
{
|
{
|
||||||
handleMessage({
|
handleMessage({
|
||||||
.severity = MessageSeverity::WARNING,
|
.severity = MessageSeverity::WARNING,
|
||||||
.text = text
|
.text = text
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
void msgError(const char* text)
|
void msgError(const char* text)
|
||||||
{
|
{
|
||||||
handleMessage({
|
handleMessage({
|
||||||
.severity = MessageSeverity::ERROR,
|
.severity = MessageSeverity::ERROR,
|
||||||
.text = text
|
.text = text
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
void msgInfo(const std::string& text)
|
void msgInfo(const std::string& text)
|
||||||
{
|
{
|
||||||
@@ -215,6 +215,10 @@ private:
|
|||||||
void handleSDLEvents();
|
void handleSDLEvents();
|
||||||
void loadImGuiConfig();
|
void loadImGuiConfig();
|
||||||
void saveImGuiConfig();
|
void saveImGuiConfig();
|
||||||
|
|
||||||
|
VkBool32 handleDebugUtilsMessage(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||||
|
VkDebugUtilsMessageTypeFlagsEXT messageTypes,
|
||||||
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData);
|
||||||
};
|
};
|
||||||
|
|
||||||
using render_cb_t = std::function<void()>;
|
using render_cb_t = std::function<void()>;
|
||||||
|
|||||||
@@ -5,16 +5,24 @@
|
|||||||
#define RAID_PUBLIC_RAID_IMRAID_HPP_INCLUDED 1
|
#define RAID_PUBLIC_RAID_IMRAID_HPP_INCLUDED 1
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cinttypes>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <ranges>
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
#include <imgui_internal.h>
|
||||||
#include <mijin/async/coroutine.hpp>
|
#include <mijin/async/coroutine.hpp>
|
||||||
#include <mijin/debug/assert.hpp>
|
#include <mijin/debug/assert.hpp>
|
||||||
|
#include <mijin/util/bitflags.hpp>
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
#include "./imutil.hpp"
|
||||||
|
|
||||||
namespace ImRaid
|
namespace ImRaid
|
||||||
{
|
{
|
||||||
@@ -58,7 +66,7 @@ inline bool ToggleImageButton(const char* strId, ImTextureID textureId, const Im
|
|||||||
return clicked;
|
return clicked;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool BeginPopupButton(const char* label)
|
inline bool BeginPopupButton(const char* label, const ImVec2& size = {} , ImGuiWindowFlags flags = ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoSavedSettings)
|
||||||
{
|
{
|
||||||
char popupId[128] = {"popup##"};
|
char popupId[128] = {"popup##"};
|
||||||
std::strcat(popupId, label);
|
std::strcat(popupId, label);
|
||||||
@@ -70,9 +78,47 @@ inline bool BeginPopupButton(const char* label)
|
|||||||
|
|
||||||
const float popupY = ImGui::GetCursorScreenPos().y;
|
const float popupY = ImGui::GetCursorScreenPos().y;
|
||||||
ImGui::SetNextWindowPos({popupX, popupY});
|
ImGui::SetNextWindowPos({popupX, popupY});
|
||||||
return ImGui::BeginPopup(popupId, ImGuiWindowFlags_NoNav);
|
ImGui::SetNextWindowSize(size);
|
||||||
|
return ImGui::BeginPopup(popupId, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void TextUnformatted(std::string_view stringView)
|
||||||
|
{
|
||||||
|
ImGui::TextUnformatted(stringView.data(), stringView.data() + stringView.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float CalcButtonWidth(const char* text)
|
||||||
|
{
|
||||||
|
return ImGui::CalcTextSize(text).x + (2.f * ImGui::GetStyle().FramePadding.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
class IDScope
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit IDScope(int intId)
|
||||||
|
{
|
||||||
|
ImGui::PushID(intId);
|
||||||
|
}
|
||||||
|
explicit IDScope(const void* ptrId)
|
||||||
|
{
|
||||||
|
ImGui::PushID(ptrId);
|
||||||
|
}
|
||||||
|
explicit IDScope(const char* strId)
|
||||||
|
{
|
||||||
|
ImGui::PushID(strId);
|
||||||
|
}
|
||||||
|
IDScope(const char* strId, const char* strIdEnd)
|
||||||
|
{
|
||||||
|
ImGui::PushID(strId, strIdEnd);
|
||||||
|
}
|
||||||
|
IDScope(const IDScope&) = delete;
|
||||||
|
~IDScope()
|
||||||
|
{
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
IDScope& operator=(const IDScope&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
struct DataTableState
|
struct DataTableState
|
||||||
{
|
{
|
||||||
std::vector<std::size_t> sortedIndices;
|
std::vector<std::size_t> sortedIndices;
|
||||||
@@ -99,18 +145,66 @@ struct DataTableColumn
|
|||||||
const char* header;
|
const char* header;
|
||||||
renderer_t renderer;
|
renderer_t renderer;
|
||||||
comparator_t comparator;
|
comparator_t comparator;
|
||||||
|
ImGuiTableColumnFlags flags = ImGuiTableColumnFlags_None;
|
||||||
|
float initialWidthOrWeight = 0.f;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DataTableItemState
|
||||||
|
{
|
||||||
|
bool selected = false;
|
||||||
|
bool hovered = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename TObject>
|
||||||
|
struct DataTableRenderState
|
||||||
|
{
|
||||||
|
const TObject* currentObject = nullptr;
|
||||||
|
std::size_t rowIdx = 0;
|
||||||
|
unsigned currentTreeDepth = 0;
|
||||||
|
DataTableItemState item = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SelectAction
|
||||||
|
{
|
||||||
|
ADD,
|
||||||
|
REMOVE,
|
||||||
|
SET
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DataTableTreeItem
|
||||||
|
{
|
||||||
|
unsigned depth = 0;
|
||||||
|
ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_SpanAllColumns;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename TObject>
|
template<typename TObject>
|
||||||
struct DataTableOptions
|
struct DataTableOptions
|
||||||
{
|
{
|
||||||
|
|
||||||
|
using filter_t = std::function<bool(const TObject&)>;
|
||||||
|
using getid_t = std::function<const char*(const TObject&)>;
|
||||||
|
using click_handler_t = std::function<void(const TObject&)>;
|
||||||
|
using getstate_t = std::function<DataTableItemState(const TObject&)>;
|
||||||
|
using select_handler_t = std::function<void(const TObject&, SelectAction)>;
|
||||||
|
using gettreeitem_t = std::function<DataTableTreeItem(const TObject&)>;
|
||||||
|
|
||||||
std::span<const DataTableColumn<TObject>> columns;
|
std::span<const DataTableColumn<TObject>> columns;
|
||||||
ImGuiTableFlags tableFlags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Sortable
|
ImGuiTableFlags tableFlags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Sortable
|
||||||
| ImGuiTableFlags_ScrollY | ImGuiTableFlags_SortMulti;
|
| ImGuiTableFlags_ScrollY | ImGuiTableFlags_SortMulti;
|
||||||
|
bool hoverable = false;
|
||||||
|
bool tree = false;
|
||||||
|
bool noHeaders = false;
|
||||||
|
|
||||||
|
filter_t filter = {};
|
||||||
|
getid_t getId = {};
|
||||||
|
click_handler_t rightClickHandler = {};
|
||||||
|
getstate_t getState = {};
|
||||||
|
select_handler_t selectHandler = {};
|
||||||
|
gettreeitem_t getTreeItem = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename TObject,typename TData>
|
template<typename TObject, typename TData>
|
||||||
inline void DataTable(const char* strId, const DataTableOptions<TObject>& options, const TData& data, DataTableState& state, ImVec2 outerSize = {})
|
inline void DataTable(const char* strId, const DataTableOptions<TObject>& options, TData&& data, DataTableState& state, DataTableRenderState<TObject>& renderState, ImVec2 outerSize = {})
|
||||||
{
|
{
|
||||||
if (outerSize.y <= 0.f) {
|
if (outerSize.y <= 0.f) {
|
||||||
outerSize.y = ImGui::GetContentRegionAvail().y;
|
outerSize.y = ImGui::GetContentRegionAvail().y;
|
||||||
@@ -122,15 +216,19 @@ inline void DataTable(const char* strId, const DataTableOptions<TObject>& option
|
|||||||
|
|
||||||
for (const DataTableColumn<TObject>& column : options.columns)
|
for (const DataTableColumn<TObject>& column : options.columns)
|
||||||
{
|
{
|
||||||
ImGuiTableColumnFlags flags = 0;
|
ImGuiTableColumnFlags flags = column.flags;
|
||||||
MIJIN_ASSERT(column.renderer, "Missing column renderer.");
|
MIJIN_ASSERT(column.renderer, "Missing column renderer.");
|
||||||
if (!column.comparator) {
|
if (!column.comparator) {
|
||||||
flags |= ImGuiTableColumnFlags_NoSort;
|
flags |= ImGuiTableColumnFlags_NoSort;
|
||||||
}
|
}
|
||||||
ImGui::TableSetupColumn(column.header, flags);
|
ImGui::TableSetupColumn(column.header, flags, column.initialWidthOrWeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.noHeaders)
|
||||||
|
{
|
||||||
|
ImGui::TableSetupScrollFreeze(0, 1);
|
||||||
|
ImGui::TableHeadersRow();
|
||||||
}
|
}
|
||||||
ImGui::TableSetupScrollFreeze(0, 1);
|
|
||||||
ImGui::TableHeadersRow();
|
|
||||||
|
|
||||||
ImGuiTableSortSpecs* sortSpecs = ImGui::TableGetSortSpecs();
|
ImGuiTableSortSpecs* sortSpecs = ImGui::TableGetSortSpecs();
|
||||||
if (sortSpecs != nullptr && sortSpecs->SpecsDirty)
|
if (sortSpecs != nullptr && sortSpecs->SpecsDirty)
|
||||||
@@ -156,56 +254,159 @@ inline void DataTable(const char* strId, const DataTableOptions<TObject>& option
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.sortedIndices.size() != data.size())
|
static constexpr bool kSortable = std::ranges::random_access_range<TData>;
|
||||||
{
|
|
||||||
state.dirty = true;
|
|
||||||
state.sortedIndices.resize(data.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.dirty)
|
typename DataTableOptions<TObject>::getid_t getId = options.getId;
|
||||||
|
|
||||||
|
static constexpr std::size_t kGetIdBufferSize = 19; // 16 digits + ## and \0
|
||||||
|
char getIdBuffer[kGetIdBufferSize] = {0};
|
||||||
|
if (!getId)
|
||||||
{
|
{
|
||||||
for (std::size_t idx = 0; idx < data.size(); ++idx) {
|
getId = [&](const TObject& object)
|
||||||
state.sortedIndices[idx] = idx;
|
|
||||||
}
|
|
||||||
std::ranges::sort(state.sortedIndices, [&](std::size_t leftIdx, std::size_t rightIdx)
|
|
||||||
{
|
{
|
||||||
for (const DataTableState::SortColumn& column : state.sortColumns)
|
std::snprintf(getIdBuffer, kGetIdBufferSize, "##%016" PRIXPTR, reinterpret_cast<std::uintptr_t>(&object));
|
||||||
{
|
return getIdBuffer;
|
||||||
const bool less = options.columns[column.index].comparator(data[leftIdx], data[rightIdx]);
|
};
|
||||||
if (less)
|
|
||||||
{ // left < right
|
|
||||||
return !column.sortDescending;
|
|
||||||
}
|
|
||||||
if (options.columns[column.index].comparator(data[rightIdx], data[leftIdx]))
|
|
||||||
{ // left > right
|
|
||||||
return column.sortDescending;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// left == right
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
state.dirty = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const std::size_t dataIdx : state.sortedIndices)
|
typename DataTableOptions<TObject>::gettreeitem_t getTreeItem = options.getTreeItem;
|
||||||
|
if (!getTreeItem)
|
||||||
{
|
{
|
||||||
const TObject& object = data[dataIdx];
|
getTreeItem = [](const TObject&) -> DataTableTreeItem {
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
renderState.rowIdx = 0;
|
||||||
|
renderState.currentTreeDepth = 0;
|
||||||
|
|
||||||
|
auto renderRow = [&](const TObject& object)
|
||||||
|
{
|
||||||
|
if (options.tree && getTreeItem(object).depth > renderState.currentTreeDepth) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.filter && !options.filter(object)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
|
renderState.currentObject = &object;
|
||||||
|
|
||||||
|
bool hoverNext = options.hoverable || options.tree;
|
||||||
|
renderState.item = options.getState ? options.getState(object) : DataTableItemState{};
|
||||||
for (const DataTableColumn<TObject>& column : options.columns)
|
for (const DataTableColumn<TObject>& column : options.columns)
|
||||||
{
|
{
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
|
if (hoverNext)
|
||||||
|
{
|
||||||
|
hoverNext = false;
|
||||||
|
|
||||||
|
bool clicked = false;
|
||||||
|
if (options.tree)
|
||||||
|
{
|
||||||
|
const DataTableTreeItem treeItem = getTreeItem(object);
|
||||||
|
MIJIN_ASSERT(treeItem.depth <= renderState.currentTreeDepth + 1, "Tree depth cannot increase by more than 1 per item.");
|
||||||
|
|
||||||
|
// close up to new depth
|
||||||
|
for (unsigned cnt = treeItem.depth; cnt < renderState.currentTreeDepth; ++cnt) {
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
|
||||||
|
const ImGuiTreeNodeFlags flags = treeItem.flags
|
||||||
|
| (renderState.item.selected ? ImGuiTreeNodeFlags_Selected : ImGuiTreeNodeFlags_None);
|
||||||
|
const bool open = ImGui::TreeNodeEx(getId(object), flags, "");
|
||||||
|
renderState.currentTreeDepth = treeItem.depth + (open ? 1 : 0);
|
||||||
|
clicked = ImGui::IsItemClicked();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const ImGuiSelectableFlags flags = ImGuiSelectableFlags_SpanAllColumns
|
||||||
|
| (renderState.item.hovered ? ImGuiSelectableFlags_Highlight : ImGuiSelectableFlags_None);
|
||||||
|
clicked = ImGui::Selectable(getId(object), renderState.item.selected, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clicked && options.selectHandler)
|
||||||
|
{
|
||||||
|
if (ImGui::IsKeyDown(ImGuiKey_LeftCtrl) || ImGui::IsKeyDown(ImGuiKey_RightCtrl)) {
|
||||||
|
options.selectHandler(object, renderState.item.selected ? SelectAction::REMOVE : SelectAction::ADD);
|
||||||
|
}
|
||||||
|
else if (!renderState.item.selected) {
|
||||||
|
options.selectHandler(object, SelectAction::SET);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (options.rightClickHandler && ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
|
||||||
|
options.rightClickHandler(object);
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
}
|
||||||
column.renderer({
|
column.renderer({
|
||||||
.object = object
|
.object = object
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
++renderState.rowIdx;
|
||||||
|
};
|
||||||
|
|
||||||
|
if constexpr (kSortable)
|
||||||
|
{
|
||||||
|
if (state.sortedIndices.size() != data.size())
|
||||||
|
{
|
||||||
|
state.dirty = true;
|
||||||
|
state.sortedIndices.resize(data.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.dirty)
|
||||||
|
{
|
||||||
|
for (std::size_t idx = 0; idx < data.size(); ++idx) {
|
||||||
|
state.sortedIndices[idx] = idx;
|
||||||
|
}
|
||||||
|
std::ranges::sort(state.sortedIndices, [&](std::size_t leftIdx, std::size_t rightIdx)
|
||||||
|
{
|
||||||
|
for (const DataTableState::SortColumn& column : state.sortColumns)
|
||||||
|
{
|
||||||
|
const bool less = options.columns[column.index].comparator(data[leftIdx], data[rightIdx]);
|
||||||
|
if (less)
|
||||||
|
{ // left < right
|
||||||
|
return !column.sortDescending;
|
||||||
|
}
|
||||||
|
if (options.columns[column.index].comparator(data[rightIdx], data[leftIdx]))
|
||||||
|
{ // left > right
|
||||||
|
return column.sortDescending;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// left == right
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
state.dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const std::size_t dataIdx : state.sortedIndices) {
|
||||||
|
renderRow(std::forward<TData>(data)[dataIdx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // constexpr kSortable
|
||||||
|
{
|
||||||
|
for (const TObject& object : std::forward<TData>(data)) {
|
||||||
|
renderRow(object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned cnt = 0; cnt < renderState.currentTreeDepth; ++cnt) {
|
||||||
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
|
template<typename TObject, typename TData>
|
||||||
|
void DataTable(const char* strId, const DataTableOptions<TObject>& options, TData&& data, DataTableState& state, ImVec2 outerSize = {})
|
||||||
|
{
|
||||||
|
DataTableRenderState<TObject> renderState;
|
||||||
|
DataTable(strId, options, std::forward<TData>(data), state, renderState, outerSize);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename TObject>
|
template<typename TObject>
|
||||||
inline DataTableColumn<TObject> MakeStringColumn(const char* header, const char* TObject::* member)
|
DataTableColumn<TObject> MakeStringColumn(const char* header, const char* TObject::* member)
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
.header = header,
|
.header = header,
|
||||||
@@ -215,7 +416,7 @@ inline DataTableColumn<TObject> MakeStringColumn(const char* header, const char*
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename TObject>
|
template<typename TObject>
|
||||||
inline DataTableColumn<TObject> MakeStringColumn(const char* header, std::string TObject::* member)
|
DataTableColumn<TObject> MakeStringColumn(const char* header, std::string TObject::* member)
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
.header = header,
|
.header = header,
|
||||||
@@ -225,7 +426,7 @@ inline DataTableColumn<TObject> MakeStringColumn(const char* header, std::string
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename TObject, typename TMember>
|
template<typename TObject, typename TMember>
|
||||||
inline DataTableColumn<TObject> MakeColumn(const char* header, const char* fmt, TMember TObject::* member)
|
DataTableColumn<TObject> MakeColumn(const char* header, const char* fmt, TMember TObject::* member)
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
.header = header,
|
.header = header,
|
||||||
@@ -234,22 +435,301 @@ inline DataTableColumn<TObject> MakeColumn(const char* header, const char* fmt,
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename TFunc>
|
enum class WindowReopenMode
|
||||||
mijin::Task<> c_MessageBox(const char* titleId, TFunc&& renderFunc)
|
|
||||||
{
|
{
|
||||||
ImGui::OpenPopup(titleId);
|
APPEND,
|
||||||
|
DONT_OPEN,
|
||||||
|
FOCUS,
|
||||||
|
DUPLICATE,
|
||||||
|
CLOSE_EXISTING
|
||||||
|
};
|
||||||
|
|
||||||
bool open = true;
|
struct WindowFlags : mijin::BitFlags<WindowFlags>
|
||||||
while (ImGui::BeginPopupModal(titleId, &open, ImGuiWindowFlags_NoResize))
|
{
|
||||||
|
bool topmost : 1 = false;
|
||||||
|
bool applicationTopmost : 1 = false;
|
||||||
|
bool noTaskbarIcon : 1 = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr ImGuiWindowFlags kUnspecifiedWindowFlags = std::numeric_limits<ImGuiWindowFlags>::max();
|
||||||
|
struct WindowOptions
|
||||||
|
{
|
||||||
|
ImGuiWindowFlags imguiFlags = kUnspecifiedWindowFlags;
|
||||||
|
ImVec2 initialSize = {-1.f, -1.f};
|
||||||
|
WindowReopenMode reopenMode = WindowReopenMode::APPEND;
|
||||||
|
WindowFlags flags = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr ImGuiWindowFlags kDefaultWindowFlags = ImGuiWindowFlags_None;
|
||||||
|
inline constexpr ImGuiWindowFlags kDefaultPopupFlags = ImGuiWindowFlags_NoSavedSettings;
|
||||||
|
inline constexpr ImGuiWindowFlags kDefaultDialogFlags = ImGuiWindowFlags_NoSavedSettings;
|
||||||
|
|
||||||
|
inline constexpr WindowOptions kDefaultPopupOptions = {
|
||||||
|
.imguiFlags = kDefaultPopupFlags,
|
||||||
|
.reopenMode = WindowReopenMode::CLOSE_EXISTING
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr WindowOptions kDefaultMessageBoxOptions = {
|
||||||
|
.imguiFlags = kDefaultDialogFlags | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize,
|
||||||
|
.reopenMode = WindowReopenMode::DUPLICATE, // TODO: this depends on the message box...
|
||||||
|
.flags = {
|
||||||
|
.applicationTopmost = true,
|
||||||
|
.noTaskbarIcon = true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace impl
|
||||||
|
{
|
||||||
|
struct WindowState
|
||||||
|
{
|
||||||
|
std::string newTitleId; // in case we want to duplicate the window if opened twice a new ID is automatically generated
|
||||||
|
int myInstanceID = 0; // used to close previous instances, if that is requested
|
||||||
|
bool showOnAppFocus = false; // for app topmost windows: has been hidden earlier and should be shown when the app regains focus
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const ImGuiID kLastInstanceKey = ImHashStr("last_instance");
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
inline mijin::Task<bool> c_prepareOpenWindow(const char*& titleId, const WindowOptions& options, WindowState& state)
|
||||||
|
{
|
||||||
|
if (options.reopenMode != WindowReopenMode::APPEND)
|
||||||
{
|
{
|
||||||
std::invoke(std::forward<TFunc>(renderFunc));
|
if (ImGuiWindow* window = ImGui::FindWindowByName(titleId); window != nullptr)
|
||||||
|
{
|
||||||
|
if (!window->WasActive)
|
||||||
|
{
|
||||||
|
// exists, but isn't active, reset the instance ID
|
||||||
|
window->StateStorage.SetInt(kLastInstanceKey, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (options.reopenMode)
|
||||||
|
{
|
||||||
|
case WindowReopenMode::APPEND:
|
||||||
|
break; // how?5
|
||||||
|
case WindowReopenMode::DONT_OPEN:
|
||||||
|
co_return false;
|
||||||
|
case WindowReopenMode::FOCUS:
|
||||||
|
ImGui::SetWindowFocus(titleId);
|
||||||
|
co_return false;
|
||||||
|
case WindowReopenMode::DUPLICATE:
|
||||||
|
state.newTitleId = std::format("{}##{}", titleId, mijin::getCurrentTask().getState());
|
||||||
|
titleId = state.newTitleId.c_str();
|
||||||
|
break;
|
||||||
|
case WindowReopenMode::CLOSE_EXISTING:
|
||||||
|
state.myInstanceID = window->StateStorage.GetInt(kLastInstanceKey) + 1;
|
||||||
|
window->StateStorage.SetInt(kLastInstanceKey, state.myInstanceID);
|
||||||
|
if (!(options.imguiFlags & ImGuiWindowFlags_NoFocusOnAppearing))
|
||||||
|
{
|
||||||
|
// ImGui treats it as the same window, but it's actually a new one
|
||||||
|
ImGui::SetNextWindowFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait one frame, otherwise it will be drawn twice, which breaks auto-sizing
|
||||||
|
co_await mijin::c_suspend();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ImGuiViewportFlags viewportFlags =
|
||||||
|
(options.flags.topmost ? ImGuiViewportFlags_TopMost : ImGuiViewportFlags_None)
|
||||||
|
| (options.flags.applicationTopmost ? ImGuiViewportFlags_NoAutoMerge : ImGuiViewportFlags_None)
|
||||||
|
| (options.flags.noTaskbarIcon ? ImGuiViewportFlags_NoTaskBarIcon : ImGuiViewportFlags_None);
|
||||||
|
if (viewportFlags != ImGuiViewportFlags_None)
|
||||||
|
{
|
||||||
|
ImGuiWindowClass windowClass;
|
||||||
|
windowClass.ViewportFlagsOverrideSet = viewportFlags;
|
||||||
|
ImGui::SetNextWindowClass(&windowClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SetNextWindowSize(options.initialSize);
|
||||||
|
co_return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
inline bool updateWindow(const WindowOptions& options, WindowState& state)
|
||||||
|
{
|
||||||
|
const ImGuiWindow* const window = ImGui::GetCurrentWindow();
|
||||||
|
if (window->StateStorage.GetInt(kLastInstanceKey) != state.myInstanceID) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.flags.applicationTopmost && window->Viewport != nullptr && window->Viewport->PlatformHandle != nullptr)
|
||||||
|
{
|
||||||
|
const ImGuiWindow* popupModal = ImGui::GetTopMostPopupModal();
|
||||||
|
const bool forceNoTopmost = (popupModal != nullptr && popupModal != window); // don't move to front if there is currently a modal popup
|
||||||
|
bool appHasFocus = false;
|
||||||
|
|
||||||
|
for (ImGuiViewport* viewport : ImGui::GetPlatformIO().Viewports)
|
||||||
|
{
|
||||||
|
if (viewport->Flags & ImGuiViewportFlags_IsFocused)
|
||||||
|
{
|
||||||
|
appHasFocus = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const SDL_WindowID sdlID = static_cast<SDL_WindowID>(reinterpret_cast<std::uintptr_t>(window->Viewport->PlatformHandle));
|
||||||
|
SDL_Window* sdlWindow = SDL_GetWindowFromID(sdlID);
|
||||||
|
|
||||||
|
const SDL_WindowFlags sdlFlags = SDL_GetWindowFlags(sdlWindow);
|
||||||
|
const bool isTopmost = (sdlFlags & SDL_WINDOW_ALWAYS_ON_TOP);
|
||||||
|
const bool wantTopmost = (appHasFocus && !forceNoTopmost);
|
||||||
|
if (isTopmost != wantTopmost)
|
||||||
|
{
|
||||||
|
const bool isHidden = (sdlFlags & SDL_WINDOW_HIDDEN);
|
||||||
|
SDL_SetWindowAlwaysOnTop(sdlWindow, wantTopmost);
|
||||||
|
|
||||||
|
// if we just removed the flag, it was topmost when the focused changed, so it's still on top
|
||||||
|
// minimize it to make up for that
|
||||||
|
if (!appHasFocus && !isHidden)
|
||||||
|
{
|
||||||
|
SDL_HideWindow(sdlWindow);
|
||||||
|
state.showOnAppFocus = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// when regaining focus, check if we need to un-hide this window
|
||||||
|
if (appHasFocus && state.showOnAppFocus)
|
||||||
|
{
|
||||||
|
if (isHidden) {
|
||||||
|
SDL_ShowWindow(sdlWindow);
|
||||||
|
}
|
||||||
|
state.showOnAppFocus = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TFunc>
|
||||||
|
mijin::Task<> c_Window(const char* titleId, bool& open, const WindowOptions& options, TFunc renderFunc)
|
||||||
|
{
|
||||||
|
impl::WindowState state;
|
||||||
|
if (!co_await impl::c_prepareOpenWindow(titleId, options, state)) {
|
||||||
|
co_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ImGuiWindowFlags flags = (options.imguiFlags != kUnspecifiedWindowFlags) ? options.imguiFlags : kDefaultWindowFlags;
|
||||||
|
while (open)
|
||||||
|
{
|
||||||
|
if (ImGui::Begin(titleId, &open, flags)) {
|
||||||
|
std::invoke(renderFunc);
|
||||||
|
}
|
||||||
|
if (!impl::updateWindow(options, state)) {
|
||||||
|
open = false;
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
co_await mijin::c_suspend();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TFunc>
|
||||||
|
mijin::Task<> c_Window(const char* titleId, bool& open, TFunc renderFunc)
|
||||||
|
{
|
||||||
|
co_return co_await c_Window(titleId, open, WindowOptions{}, std::move(renderFunc));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TFunc>
|
||||||
|
mijin::Task<> c_Window(const char* titleId, const WindowOptions& options, TFunc renderFunc)
|
||||||
|
{
|
||||||
|
bool open = true;
|
||||||
|
co_return co_await c_Window(titleId, open, options, std::move(renderFunc));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TFunc>
|
||||||
|
mijin::Task<> c_Window(const char* titleId, TFunc renderFunc)
|
||||||
|
{
|
||||||
|
co_return co_await c_Window(titleId, WindowOptions{}, std::move(renderFunc));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TFunc>
|
||||||
|
mijin::Task<> c_Popup(const char* titleId, const WindowOptions& options, TFunc renderFunc)
|
||||||
|
{
|
||||||
|
impl::WindowState state;
|
||||||
|
if (!co_await impl::c_prepareOpenWindow(titleId, options, state)) {
|
||||||
|
co_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ImGuiWindowFlags flags = (options.imguiFlags != kUnspecifiedWindowFlags) ? options.imguiFlags : kDefaultPopupFlags;
|
||||||
|
bool open = true;
|
||||||
|
|
||||||
|
ImGui::OpenPopup(titleId);
|
||||||
|
while (open && ImGui::BeginPopup(titleId, flags))
|
||||||
|
{
|
||||||
|
std::invoke(renderFunc);
|
||||||
|
if (!impl::updateWindow(options, state)) {
|
||||||
|
open = false;
|
||||||
|
}
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
co_await mijin::c_suspend();
|
co_await mijin::c_suspend();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename TFunc>
|
||||||
|
mijin::Task<> c_Popup(const char* titleId, TFunc renderFunc)
|
||||||
|
{
|
||||||
|
co_return co_await c_Popup(titleId, kDefaultPopupOptions, std::move(renderFunc));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TFunc>
|
||||||
|
mijin::Task<> c_Dialog(const char* titleId, bool& open, const WindowOptions& options, TFunc renderFunc)
|
||||||
|
{
|
||||||
|
impl::WindowState state;
|
||||||
|
if (!co_await impl::c_prepareOpenWindow(titleId, options, state)) {
|
||||||
|
co_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ImGuiWindowFlags flags = (options.imguiFlags != kUnspecifiedWindowFlags) ? options.imguiFlags : kDefaultDialogFlags;
|
||||||
|
|
||||||
|
ImGui::OpenPopup(titleId);
|
||||||
|
while (open && ImGui::BeginPopupModal(titleId, &open, flags))
|
||||||
|
{
|
||||||
|
std::invoke(renderFunc);
|
||||||
|
if (!impl::updateWindow(options, state)) {
|
||||||
|
open = false;
|
||||||
|
}
|
||||||
|
ImGui::EndPopup();
|
||||||
|
co_await mijin::c_suspend();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TFunc>
|
||||||
|
mijin::Task<> c_Dialog(const char* titleId, bool& open, TFunc renderFunc)
|
||||||
|
{
|
||||||
|
co_return co_await c_Dialog(titleId, open, kDefaultPopupOptions, std::move(renderFunc));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TFunc>
|
||||||
|
mijin::Task<> c_Dialog(const char* titleId, const WindowOptions& options, TFunc renderFunc)
|
||||||
|
{
|
||||||
|
bool open = true;
|
||||||
|
co_return co_await c_Dialog(titleId, open, options, std::move(renderFunc));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TFunc>
|
||||||
|
mijin::Task<> c_Dialog(const char* titleId, TFunc renderFunc)
|
||||||
|
{
|
||||||
|
co_return co_await c_Dialog(titleId, WindowOptions{}, std::move(renderFunc));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TFunc>
|
||||||
|
mijin::Task<> c_MessageBox(const char* titleId, const WindowOptions& options, TFunc renderFunc)
|
||||||
|
{
|
||||||
|
co_return co_await c_Dialog(titleId, options, std::move(renderFunc));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TFunc>
|
||||||
|
mijin::Task<> c_MessageBox(const char* titleId, TFunc renderFunc)
|
||||||
|
{
|
||||||
|
return c_MessageBox(titleId, kDefaultMessageBoxOptions, std::move(renderFunc));
|
||||||
|
}
|
||||||
|
|
||||||
template<typename... TFormatArgs>
|
template<typename... TFormatArgs>
|
||||||
mijin::Task<int> c_MessageBox(const char* titleId, std::span<const char*> buttons, std::format_string<TFormatArgs...> format, TFormatArgs&&... formatArgs)
|
mijin::Task<int> c_MessageBox(const char* titleId, std::span<const char* const> buttons, const WindowOptions& options, std::format_string<TFormatArgs...> format, TFormatArgs&&... formatArgs)
|
||||||
{
|
{
|
||||||
const std::string message = std::format(format, std::forward<TFormatArgs>(formatArgs)...);
|
const std::string message = std::format(format, std::forward<TFormatArgs>(formatArgs)...);
|
||||||
int buttonIdx = -1;
|
int buttonIdx = -1;
|
||||||
@@ -261,8 +741,8 @@ mijin::Task<int> c_MessageBox(const char* titleId, std::span<const char*> button
|
|||||||
}
|
}
|
||||||
buttonsWidth += static_cast<float>(buttons.size()) * 2.f * style.FramePadding.x;;
|
buttonsWidth += static_cast<float>(buttons.size()) * 2.f * style.FramePadding.x;;
|
||||||
buttonsWidth += static_cast<float>(buttons.size() - 1) * style.ItemSpacing.x;
|
buttonsWidth += static_cast<float>(buttons.size() - 1) * style.ItemSpacing.x;
|
||||||
|
|
||||||
co_await c_MessageBox(titleId, [&]()
|
co_await c_MessageBox(titleId, options, [&]()
|
||||||
{
|
{
|
||||||
ImGui::TextUnformatted(message.c_str());
|
ImGui::TextUnformatted(message.c_str());
|
||||||
|
|
||||||
@@ -283,6 +763,12 @@ mijin::Task<int> c_MessageBox(const char* titleId, std::span<const char*> button
|
|||||||
co_return buttonIdx;
|
co_return buttonIdx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename... TFormatArgs>
|
||||||
|
mijin::Task<int> c_MessageBox(const char* titleId, std::span<const char* const> buttons, std::format_string<TFormatArgs...> format, TFormatArgs&&... formatArgs)
|
||||||
|
{
|
||||||
|
return c_MessageBox(titleId, buttons, kDefaultMessageBoxOptions, format, std::forward<TFormatArgs>(formatArgs)...);
|
||||||
|
}
|
||||||
|
|
||||||
struct YesNo
|
struct YesNo
|
||||||
{
|
{
|
||||||
enum Value
|
enum Value
|
||||||
@@ -305,10 +791,10 @@ struct YesNo
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<YesNo::Value DefaultResult = YesNo::NO, typename... TFormatArgs>
|
template<YesNo::Value DefaultResult = YesNo::NO, typename... TFormatArgs>
|
||||||
mijin::Task<YesNo> c_MessageBoxYesNo(const char* titleId, std::format_string<TFormatArgs...> format, TFormatArgs&&... formatArgs)
|
mijin::Task<YesNo> c_MessageBoxYesNo(const char* titleId, const WindowOptions& options, std::format_string<TFormatArgs...> format, TFormatArgs&&... formatArgs)
|
||||||
{
|
{
|
||||||
static std::array<const char*, 2> BUTTONS = {"Yes", "No"};
|
static const std::array<const char*, 2> BUTTONS = {"Yes", "No"};
|
||||||
const int idx = co_await c_MessageBox(titleId, BUTTONS, format, std::forward<TFormatArgs>(formatArgs)...);
|
const int idx = co_await c_MessageBox(titleId, BUTTONS, options, format, std::forward<TFormatArgs>(formatArgs)...);
|
||||||
switch (idx)
|
switch (idx)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
@@ -319,6 +805,37 @@ mijin::Task<YesNo> c_MessageBoxYesNo(const char* titleId, std::format_string<TFo
|
|||||||
co_return DefaultResult;
|
co_return DefaultResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<YesNo::Value DefaultResult = YesNo::NO, typename... TFormatArgs>
|
||||||
|
mijin::Task<YesNo> c_MessageBoxYesNo(const char* titleId, std::format_string<TFormatArgs...> format, TFormatArgs&&... formatArgs)
|
||||||
|
{
|
||||||
|
return c_MessageBoxYesNo(titleId, kDefaultMessageBoxOptions, format, std::forward<TFormatArgs>(formatArgs)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... TFormatArgs>
|
||||||
|
mijin::Task<> c_MessageBoxText(const char* titleId, const WindowOptions& options, std::format_string<TFormatArgs...> format, TFormatArgs&&... formatArgs)
|
||||||
|
{
|
||||||
|
static const char* const BUTTON_TEXT = "OK";
|
||||||
|
co_await c_MessageBox(titleId, {&BUTTON_TEXT, 1}, options, format, std::forward<TFormatArgs>(formatArgs)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... TFormatArgs>
|
||||||
|
mijin::Task<> c_MessageBoxText(const char* titleId, std::format_string<TFormatArgs...> format, TFormatArgs&&... formatArgs)
|
||||||
|
{
|
||||||
|
return c_MessageBoxText(titleId, kDefaultMessageBoxOptions, format, std::forward<TFormatArgs>(formatArgs)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::integral T>
|
||||||
|
void InputScalar(const char* label, T* value, T step = T(0), T stepFast = T(100), ImGuiInputTextFlags flags = 0)
|
||||||
|
{
|
||||||
|
ImGui::InputScalar(label, raid::kImGuiDataType<T>, value, &step, &stepFast, /* format = */ nullptr, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::floating_point T>
|
||||||
|
void InputScalar(const char* label, T* value, T step = T(0), T stepFast = T(0), const char* format = "%.3f", ImGuiInputTextFlags flags = 0)
|
||||||
|
{
|
||||||
|
ImGui::InputScalar(label, raid::kImGuiDataType<T>, value, &step, &stepFast, format, flags);
|
||||||
|
}
|
||||||
} // namespace ImRaid
|
} // namespace ImRaid
|
||||||
|
|
||||||
#endif // !defined(RAID_PUBLIC_RAID_IMRAID_HPP_INCLUDED)
|
#endif // !defined(RAID_PUBLIC_RAID_IMRAID_HPP_INCLUDED)
|
||||||
|
|||||||
57
public/raid/imutil.hpp
Normal file
57
public/raid/imutil.hpp
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if !defined(RAID_PUBLIC_RAID_IMUTIL_HPP_INCLUDED)
|
||||||
|
#define RAID_PUBLIC_RAID_IMUTIL_HPP_INCLUDED 1
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <format>
|
||||||
|
#include <string>
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
namespace raid
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace impl
|
||||||
|
{
|
||||||
|
template<std::size_t I>
|
||||||
|
inline std::string gFormatBuffer;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct imgui_data_type;
|
||||||
|
|
||||||
|
template<> struct imgui_data_type<std::int8_t> : std::integral_constant<ImGuiDataType, ImGuiDataType_S8> {};
|
||||||
|
template<> struct imgui_data_type<std::uint8_t> : std::integral_constant<ImGuiDataType, ImGuiDataType_U8> {};
|
||||||
|
template<> struct imgui_data_type<std::int16_t> : std::integral_constant<ImGuiDataType, ImGuiDataType_S16> {};
|
||||||
|
template<> struct imgui_data_type<std::uint16_t> : std::integral_constant<ImGuiDataType, ImGuiDataType_U16> {};
|
||||||
|
template<> struct imgui_data_type<std::int32_t> : std::integral_constant<ImGuiDataType, ImGuiDataType_S32> {};
|
||||||
|
template<> struct imgui_data_type<std::uint32_t> : std::integral_constant<ImGuiDataType, ImGuiDataType_U32> {};
|
||||||
|
template<> struct imgui_data_type<std::int64_t> : std::integral_constant<ImGuiDataType, ImGuiDataType_S64> {};
|
||||||
|
template<> struct imgui_data_type<std::uint64_t> : std::integral_constant<ImGuiDataType, ImGuiDataType_U64> {};
|
||||||
|
template<> struct imgui_data_type<float> : std::integral_constant<ImGuiDataType, ImGuiDataType_Float> {};
|
||||||
|
template<> struct imgui_data_type<double> : std::integral_constant<ImGuiDataType, ImGuiDataType_Double> {};
|
||||||
|
template<> struct imgui_data_type<bool> : std::integral_constant<ImGuiDataType, ImGuiDataType_Bool> {};
|
||||||
|
template<> struct imgui_data_type<const char*> : std::integral_constant<ImGuiDataType, ImGuiDataType_String> {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... TArgs>
|
||||||
|
[[nodiscard]]
|
||||||
|
const char* formatTemp(std::string& formatBuffer, std::format_string<TArgs...> fmt, TArgs&&... args)
|
||||||
|
{
|
||||||
|
formatBuffer.clear();
|
||||||
|
std::format_to(std::back_inserter(formatBuffer), fmt, std::forward<TArgs>(args)...);
|
||||||
|
return formatBuffer.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t I = 0, typename... TArgs>
|
||||||
|
[[nodiscard]]
|
||||||
|
const char* formatTemp(std::format_string<TArgs...> fmt, TArgs&&... args)
|
||||||
|
{
|
||||||
|
return formatTemp(impl::gFormatBuffer<I>, fmt, std::forward<TArgs>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr ImGuiDataType kImGuiDataType = impl::imgui_data_type<T>::value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -19,17 +19,29 @@ namespace raid
|
|||||||
struct MixinVulkanApplication
|
struct MixinVulkanApplication
|
||||||
{
|
{
|
||||||
#if !RAID_USE_VULKAN_H
|
#if !RAID_USE_VULKAN_H
|
||||||
|
// basic types
|
||||||
|
using VkBool32 = std::uint32_t;
|
||||||
|
|
||||||
// flags
|
// flags
|
||||||
using VkFlags = std::uint32_t;
|
using VkFlags = std::uint32_t;
|
||||||
using VkInstanceCreateFlags = VkFlags;
|
using VkInstanceCreateFlags = VkFlags;
|
||||||
|
using VkDebugUtilsMessengerCreateFlagsEXT = VkFlags;
|
||||||
|
using VkDebugUtilsMessageSeverityFlagsEXT = VkFlags;
|
||||||
|
using VkDebugUtilsMessageTypeFlagsEXT = VkFlags;
|
||||||
|
using VkDebugUtilsMessengerCallbackDataFlagsEXT = VkFlags;
|
||||||
using VkQueueFlags = VkFlags;
|
using VkQueueFlags = VkFlags;
|
||||||
using VkDeviceCreateFlags = VkFlags;
|
using VkDeviceCreateFlags = VkFlags;
|
||||||
using VkDeviceQueueCreateFlags = VkFlags;
|
using VkDeviceQueueCreateFlags = VkFlags;
|
||||||
|
|
||||||
|
// constants
|
||||||
|
static constexpr std::uint32_t VK_MAX_EXTENSION_NAME_SIZE = 256;
|
||||||
|
static constexpr std::uint32_t VK_MAX_DESCRIPTION_SIZE = 256;
|
||||||
|
|
||||||
// enums
|
// enums
|
||||||
enum VkResult
|
enum VkResult
|
||||||
{
|
{
|
||||||
VK_SUCCESS = 0
|
VK_SUCCESS = 0,
|
||||||
|
VK_INCOMPLETE = 5
|
||||||
};
|
};
|
||||||
enum VkStructureType
|
enum VkStructureType
|
||||||
{
|
{
|
||||||
@@ -37,10 +49,28 @@ struct MixinVulkanApplication
|
|||||||
VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1,
|
VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1,
|
||||||
VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO = 2,
|
VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO = 2,
|
||||||
VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO = 3,
|
VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO = 3,
|
||||||
VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2 = 1000059005
|
VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2 = 1000059005,
|
||||||
|
VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT = 1000128000,
|
||||||
|
VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT = 1000128002,
|
||||||
|
VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT = 1000128003,
|
||||||
|
VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT = 1000128004
|
||||||
};
|
};
|
||||||
enum VkSystemAllocationScope {};
|
enum VkSystemAllocationScope {};
|
||||||
enum VkInternalAllocationType {};
|
enum VkInternalAllocationType {};
|
||||||
|
enum VkObjectType {};
|
||||||
|
enum VkDebugUtilsMessageSeverityFlagBitsEXT : VkFlags
|
||||||
|
{
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT = 0x00000001,
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT = 0x00000010,
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT = 0x00000100,
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT = 0x00001000
|
||||||
|
};
|
||||||
|
enum VkDebugUtilsMessageTypeFlagBitsEXT : VkFlags
|
||||||
|
{
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT = 0x00000001,
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT = 0x00000002,
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT = 0x00000004
|
||||||
|
};
|
||||||
enum VkQueueFlagBits : VkFlags
|
enum VkQueueFlagBits : VkFlags
|
||||||
{
|
{
|
||||||
VK_QUEUE_GRAPHICS_BIT = 0x00000001
|
VK_QUEUE_GRAPHICS_BIT = 0x00000001
|
||||||
@@ -49,6 +79,19 @@ struct MixinVulkanApplication
|
|||||||
// handles
|
// handles
|
||||||
using VkDevice = struct VkDevice_*;
|
using VkDevice = struct VkDevice_*;
|
||||||
using VkQueue = struct VkQueue_*;
|
using VkQueue = struct VkQueue_*;
|
||||||
|
using VkDebugUtilsMessengerEXT = struct VkDebugUtilsMessengerEXT_*;
|
||||||
|
|
||||||
|
struct VkDebugUtilsMessengerCallbackDataEXT;
|
||||||
|
|
||||||
|
// Vulkan function pointer types
|
||||||
|
using PFN_vkVoidFunction = void (*)();
|
||||||
|
// TODO: VKAPI_PTR?
|
||||||
|
using PFN_vkAllocationFunction = void* (*)(void* pUserData, std::size_t size, std::size_t alignment, VkSystemAllocationScope allocationScope);
|
||||||
|
using PFN_vkReallocationFunction = void* (*)(void* pUserData, void* pOriginal, std::size_t size, std::size_t alignment, VkSystemAllocationScope allocationScope);
|
||||||
|
using PFN_vkFreeFunction = void (*)(void* pUserData, void* pMemory);
|
||||||
|
using PFN_vkInternalAllocationNotification = void (*)(void* pUserData, std::size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope);
|
||||||
|
using PFN_vkInternalFreeNotification = void (*)(void* pUserData, std::size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope);
|
||||||
|
using PFN_vkDebugUtilsMessengerCallbackEXT = VkBool32 (*)(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData);
|
||||||
|
|
||||||
// structs
|
// structs
|
||||||
struct VkExtent3D
|
struct VkExtent3D
|
||||||
@@ -58,6 +101,20 @@ struct MixinVulkanApplication
|
|||||||
std::uint32_t depth = 0;
|
std::uint32_t depth = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct VkLayerProperties
|
||||||
|
{
|
||||||
|
char layerName[VK_MAX_EXTENSION_NAME_SIZE] = {0};
|
||||||
|
std::uint32_t specVersion = 0;
|
||||||
|
std::uint32_t implementationVersion = 0;
|
||||||
|
char description[VK_MAX_DESCRIPTION_SIZE] = {0};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VkExtensionProperties
|
||||||
|
{
|
||||||
|
char extensionName[VK_MAX_EXTENSION_NAME_SIZE] = {0};
|
||||||
|
std::uint32_t specVersion = 0;
|
||||||
|
};
|
||||||
|
|
||||||
struct VkApplicationInfo
|
struct VkApplicationInfo
|
||||||
{
|
{
|
||||||
VkStructureType sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
VkStructureType sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||||
@@ -80,6 +137,50 @@ struct MixinVulkanApplication
|
|||||||
const char* const* ppEnabledExtensionNames = nullptr;
|
const char* const* ppEnabledExtensionNames = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct VkDebugUtilsMessengerCreateInfoEXT
|
||||||
|
{
|
||||||
|
VkStructureType sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
||||||
|
const void* pNext = nullptr;
|
||||||
|
VkDebugUtilsMessengerCreateFlagsEXT flags = 0;
|
||||||
|
VkDebugUtilsMessageSeverityFlagsEXT messageSeverity = 0;
|
||||||
|
VkDebugUtilsMessageTypeFlagsEXT messageType = 0;
|
||||||
|
PFN_vkDebugUtilsMessengerCallbackEXT pfnUserCallback;
|
||||||
|
void* pUserData = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VkDebugUtilsLabelEXT
|
||||||
|
{
|
||||||
|
VkStructureType sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
|
||||||
|
const void* pNext = nullptr;
|
||||||
|
const char* pLabelName = nullptr;
|
||||||
|
float color[4] = {0.f, 0.f, 0.f, 0.f};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VkDebugUtilsObjectNameInfoEXT
|
||||||
|
{
|
||||||
|
VkStructureType sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
|
||||||
|
const void* pNext = nullptr;
|
||||||
|
VkObjectType objectType = static_cast<VkObjectType>(0);
|
||||||
|
std::uint64_t objectHandle = 0;
|
||||||
|
const char* pObjectName = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VkDebugUtilsMessengerCallbackDataEXT
|
||||||
|
{
|
||||||
|
VkStructureType sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
|
||||||
|
const void* pNext = nullptr;
|
||||||
|
VkDebugUtilsMessengerCallbackDataFlagsEXT flags = 0;
|
||||||
|
const char* pMessageIdName;
|
||||||
|
std::int32_t messageIdNumber;
|
||||||
|
const char* pMessage;
|
||||||
|
std::uint32_t queueLabelCount;
|
||||||
|
const VkDebugUtilsLabelEXT* pQueueLabels;
|
||||||
|
std::uint32_t cmdBufLabelCount;
|
||||||
|
const VkDebugUtilsLabelEXT* pCmdBufLabels;
|
||||||
|
std::uint32_t objectCount;
|
||||||
|
const VkDebugUtilsObjectNameInfoEXT* pObjects;
|
||||||
|
};
|
||||||
|
|
||||||
struct VkQueueFamilyProperties
|
struct VkQueueFamilyProperties
|
||||||
{
|
{
|
||||||
VkQueueFlags queueFlags = 0;
|
VkQueueFlags queueFlags = 0;
|
||||||
@@ -120,14 +221,6 @@ struct MixinVulkanApplication
|
|||||||
const VkPhysicalDeviceFeatures* pEnabledFeatures = nullptr;
|
const VkPhysicalDeviceFeatures* pEnabledFeatures = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Vulkan function pointer types
|
|
||||||
using PFN_vkVoidFunction = void (*)();
|
|
||||||
// TODO: VKAPI_PTR?
|
|
||||||
using PFN_vkAllocationFunction = void* (*)(void* pUserData, std::size_t size, std::size_t alignment, VkSystemAllocationScope allocationScope);
|
|
||||||
using PFN_vkReallocationFunction = void* (*)(void* pUserData, void* pOriginal, std::size_t size, std::size_t alignment, VkSystemAllocationScope allocationScope);
|
|
||||||
using PFN_vkFreeFunction = void (*)(void* pUserData, void* pMemory);
|
|
||||||
using PFN_vkInternalAllocationNotification = void (*)(void* pUserData, std::size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope);
|
|
||||||
using PFN_vkInternalFreeNotification = void (*)(void* pUserData, std::size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope);
|
|
||||||
struct VkAllocationCallbacks
|
struct VkAllocationCallbacks
|
||||||
{
|
{
|
||||||
void* pUserData = nullptr;
|
void* pUserData = nullptr;
|
||||||
@@ -138,27 +231,41 @@ struct MixinVulkanApplication
|
|||||||
PFN_vkInternalFreeNotification pfnInternalFree = nullptr;
|
PFN_vkInternalFreeNotification pfnInternalFree = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
// function pointers
|
// -- function pointers
|
||||||
|
// instance creation
|
||||||
using vkGetInstanceProcAddr_fn_t = PFN_vkVoidFunction (*)(VkInstance instance, const char* pName);
|
using vkGetInstanceProcAddr_fn_t = PFN_vkVoidFunction (*)(VkInstance instance, const char* pName);
|
||||||
|
using vkEnumerateInstanceLayerProperties_fn_t = VkResult (*)(std::uint32_t* pPropertyCount, VkLayerProperties* pProperties);
|
||||||
|
using vkEnumerateInstanceExtensionProperties_fn_t = VkResult (*)(const char* pLayerName, std::uint32_t* pPropertyCount, VkExtensionProperties* pProperties);
|
||||||
|
using vkCreateDebugUtilsMessengerEXT_fn_t = VkResult (*)(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pMessenger);
|
||||||
|
using vkDestroyDebugUtilsMessengerEXT_fn_t = void (*)(VkInstance instance, VkDebugUtilsMessengerEXT messenger, const VkAllocationCallbacks* pAllocator);
|
||||||
using vkCreateInstance_fn_t = VkResult (*)(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance);
|
using vkCreateInstance_fn_t = VkResult (*)(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance);
|
||||||
using vkDestroyInstance_fn_t = void (*)(VkInstance instance, const VkAllocationCallbacks* pAllocator);
|
using vkDestroyInstance_fn_t = void (*)(VkInstance instance, const VkAllocationCallbacks* pAllocator);
|
||||||
|
|
||||||
|
// device creation
|
||||||
using vkEnumeratePhysicalDevices_fn_t = VkResult (*)(VkInstance instance, std::uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices);
|
using vkEnumeratePhysicalDevices_fn_t = VkResult (*)(VkInstance instance, std::uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices);
|
||||||
using vkGetPhysicalDeviceQueueFamilyProperties2_fn_t = void (*)(VkPhysicalDevice physicalDevice, std::uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties);
|
using vkGetPhysicalDeviceQueueFamilyProperties2_fn_t = void (*)(VkPhysicalDevice physicalDevice, std::uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties);
|
||||||
using vkCreateDevice_fn_t = VkResult (*)(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice);
|
using vkCreateDevice_fn_t = VkResult (*)(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice);
|
||||||
using vkDestroyDevice_fn_t = void (*)(VkDevice device, const VkAllocationCallbacks* pAllocator);
|
using vkDestroyDevice_fn_t = void (*)(VkDevice device, const VkAllocationCallbacks* pAllocator);
|
||||||
using vkDeviceWaitIdle_fn_t = VkResult (*)(VkDevice device);
|
using vkDeviceWaitIdle_fn_t = VkResult (*)(VkDevice device);
|
||||||
|
|
||||||
|
// other creation
|
||||||
using vkGetDeviceQueue_fn_t = void (*)(VkDevice device, std::uint32_t queueFamilyIndex, std::uint32_t queueIndex, VkQueue* pQueue);
|
using vkGetDeviceQueue_fn_t = void (*)(VkDevice device, std::uint32_t queueFamilyIndex, std::uint32_t queueIndex, VkQueue* pQueue);
|
||||||
#endif // !RAID_USE_VULKAN_H
|
#endif // !RAID_USE_VULKAN_H
|
||||||
|
|
||||||
struct VulkanData
|
struct VulkanData
|
||||||
{
|
{
|
||||||
VkInstance instance;
|
VkInstance instance;
|
||||||
|
VkDebugUtilsMessengerEXT debugUtilsMessenger;
|
||||||
VkPhysicalDevice physicalDevice;
|
VkPhysicalDevice physicalDevice;
|
||||||
VkDevice device;
|
VkDevice device;
|
||||||
VkQueue queue;
|
VkQueue queue;
|
||||||
VkSurfaceKHR surface;
|
VkSurfaceKHR surface;
|
||||||
|
|
||||||
vkGetInstanceProcAddr_fn_t GetInstanceProc;
|
vkGetInstanceProcAddr_fn_t GetInstanceProc;
|
||||||
|
vkEnumerateInstanceLayerProperties_fn_t EnumerateInstanceLayerProperties;
|
||||||
|
vkEnumerateInstanceExtensionProperties_fn_t EnumerateInstanceExtensionProperties;
|
||||||
|
vkCreateDebugUtilsMessengerEXT_fn_t CreateDebugUtilsMessengerEXT;
|
||||||
|
vkDestroyDebugUtilsMessengerEXT_fn_t DestroyDebugUtilsMessengerEXT;
|
||||||
vkCreateInstance_fn_t CreateInstance;
|
vkCreateInstance_fn_t CreateInstance;
|
||||||
vkDestroyInstance_fn_t DestroyInstance;
|
vkDestroyInstance_fn_t DestroyInstance;
|
||||||
vkEnumeratePhysicalDevices_fn_t EnumeratePhysicalDevices;
|
vkEnumeratePhysicalDevices_fn_t EnumeratePhysicalDevices;
|
||||||
|
|||||||
Reference in New Issue
Block a user