纯core, 不带任何渲染功能

This commit is contained in:
Nanako 2024-03-05 21:48:35 +08:00
parent 0acf109ef2
commit c6a8e16393
41 changed files with 22 additions and 11462 deletions

View File

@ -58,38 +58,6 @@ endfunction()
set(SHADER_CPP_GENERATED_CMAKE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/GenerateShaderCPPFile.cmake" CACHE STRING "" FORCE)
function(compile_shader TARGET_NAME OUTPUT SHADER_INCLUDE_DIR)
set(working_dir "${CMAKE_CURRENT_SOURCE_DIR}")
set(GLSLANG_BIN $ENV{VULKAN_SDK}/Bin/glslangValidator.exe) # glslangValidator
set(ALL_SHADER_FILE "")
# get files in SHADER_INCLUDE_DIR
file(GLOB_RECURSE ALL_SHADER_FILE "${SHADER_INCLUDE_DIR}/*.vert" "${SHADER_INCLUDE_DIR}/*.frag" "${SHADER_INCLUDE_DIR}/*.comp" "${SHADER_INCLUDE_DIR}/*.tesc" "${SHADER_INCLUDE_DIR}/*.tese" "${SHADER_INCLUDE_DIR}/*.geom")
foreach(SHADER ${ALL_SHADER_FILE}) # shader
get_filename_component(SHADER_NAME ${SHADER} NAME) # shader
string(REPLACE "." "_" HEADER_NAME ${SHADER_NAME}) # .h'.''_'
string(TOUPPER ${HEADER_NAME} GLOBAL_SHADER_VAR) # vector
set(SPV_FILE "${OUTPUT}/spv/${SHADER_NAME}.spv") # .spv
set(CPP_FILE "${OUTPUT}/cpp/${HEADER_NAME}.h") # .h
add_custom_command(
OUTPUT ${SPV_FILE}
COMMAND ${GLSLANG_BIN} -I${SHADER_INCLUDE_DIR} -V100 -o ${SPV_FILE} ${SHADER}
DEPENDS ${SHADER}
WORKING_DIRECTORY "${working_dir}") #
list(APPEND ALL_GENERATED_SPV_FILES ${SPV_FILE})
add_custom_command(
OUTPUT ${CPP_FILE}
COMMAND ${CMAKE_COMMAND} -DPATH=${SPV_FILE} -DHEADER="${CPP_FILE}"
-DGLOBAL="${GLOBAL_SHADER_VAR}" -P "${SHADER_CPP_GENERATED_CMAKE}"
DEPENDS ${SPV_FILE}
WORKING_DIRECTORY "${working_dir}") # spvhcmake
list(APPEND ALL_GENERATED_CPP_FILES ${CPP_FILE})
endforeach()
add_custom_target(${TARGET_NAME} # 将上述过程添加到一个生成目标中
DEPENDS ${ALL_GENERATED_SPV_FILES} ${ALL_GENERATED_CPP_FILES} SOURCES ${SHADERS})
endfunction()
# setup portaudio
set(PA_USE_ASIO ON CACHE BOOL "" FORCE)
set(PA_BUILD_SHARED_LIBS ON CACHE BOOL "" FORCE)
@ -123,10 +91,8 @@ set(TF_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(TF_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
add_subdirectory(core)
add_subdirectory(third_party/imgui)
add_subdirectory(third_party/portaudio)
add_subdirectory(third_party/spdlog)
add_subdirectory(third_party/glfw)
add_subdirectory(third_party/mempool)
add_subdirectory(third_party/taskflow)

View File

@ -8,13 +8,13 @@ retrieve_files(ALL_FILES)
add_library(${PROJECT_NAME} SHARED ${ALL_FILES})
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} PortAudio spdlog imgui glfw mempool Taskflow)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} PortAudio spdlog mempool Taskflow)
target_link_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} PortAudio spdlog imgui glfw mempool Taskflow)
target_link_libraries(${PROJECT_NAME} PUBLIC PortAudio imgui spdlog glfw mempool Taskflow)
target_link_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} PortAudio spdlog mempool Taskflow)
target_link_libraries(${PROJECT_NAME} PUBLIC PortAudio spdlog mempool Taskflow)
target_precompile_headers(${PROJECT_NAME} PUBLIC extern.h)
add_definitions(-Dcore_EXPORTS -DSTB_IMAGE_IMPLEMENTATION -DSTBI_WINDOWS_UTF8)
add_definitions(-Dcore_EXPORTS)
if (MSVC)
add_custom_command(

View File

@ -3,12 +3,6 @@
#include <iostream>
#include "command_line.h"
#include "imgui_impl_sdl3.h"
#include "imgui_internal.h"
#include "window_manager.h"
#include "filesystem/stb_image.h"
#include "rhi/texture.h"
#include "rhi/renderer.h"
#include "spdlog/async.h"
#include "spdlog/spdlog.h"
#include "spdlog/sinks/basic_file_sink.h"
@ -18,10 +12,6 @@ bool g_is_running = true;
bool g_exit_requested = false;
application* g_app_instance = nullptr;
static void glfw_error_callback(int error, const char* description) {
spdlog::error("Glfw Error {}: {}", error, description);
}
void application::init(const window_params& in_window_params, int argc, char** argv) {
try {
async_spdlog_ = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/log.txt");
@ -30,103 +20,14 @@ void application::init(const window_params& in_window_params, int argc, char** a
}
command_line::instance().init(argc, argv);
init_glfw();
init_imgui();
renderer_ = new renderer();
renderer_->pre_init();
const auto window = g_window_manager.create_main_window(in_window_params.title.c_str(), in_window_params.width, in_window_params.height);
// new glfw window
if (!window) {
spdlog::error("Failed to create glfw window");
return;
}
renderer_->init(window);
g_is_running = true;
}
int application::run() {
const ImGuiIO& io = ImGui::GetIO();
while (!g_exit_requested) {
g_main_thread_hub.process_messages();
g_window_manager.tick();
g_exit_requested = g_exit_requested || g_window_manager.should_close();
tick(io.DeltaTime);
renderer_->new_frame(g_window_manager.get_main_window());
draw_gui();
renderer_->end_frame(g_window_manager.get_main_window());
}
shutdown();
return 0;
}
void application::shutdown() {
renderer_->shutdown();
destroy_imgui();
delete renderer_;
renderer_ = nullptr;
destroy_glfw();
g_is_running = false;
}
void application::request_exit() {
g_window_manager.request_exit();
g_exit_requested = true;
}
std::shared_ptr<texture> application::load_texture(const std::string& path, vk::Format format) {
int width = 0;
int height = 0;
uint8_t* image_data = stbi_load(path.c_str(), &width, &height, nullptr, 4);
if (!image_data) {
spdlog::error("Failed to load texture: {}", path.c_str());
return nullptr;
}
const auto texture = renderer::create_texture(image_data, width, height, format);
stbi_image_free(image_data);
return texture;
}
std::shared_ptr<texture> application::create_texture(const unsigned char* data, const int width, const int height, vk::Format format) {
return renderer::create_texture(data, width, height, format);
}
void application::init_glfw() {
glfwSetErrorCallback(glfw_error_callback);
if (!glfwInit()) {
spdlog::error("Failed to initialize GLFW");
return;
}
// glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
}
void application::init_imgui() {
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
init_imgui(ImGui::CreateContext());
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
// io.ConfigViewportsNoAutoMerge = true;
// io.ConfigViewportsNoTaskBarIcon = false;
ImGui::StyleColorsDark();
//ImGui::StyleColorsLight();
}
void application::destroy_glfw() {
glfwTerminate();
}
void application::destroy_imgui() {
init_imgui(nullptr);
ImGui::DestroyContext();
}

View File

@ -1,8 +1,5 @@
#pragma once
#include <string>
#include "imgui.h"
#include "GLFW/glfw3.h"
#include <vulkan/vulkan.hpp>
class renderer;
class render_target;
@ -44,37 +41,12 @@ public:
virtual void init(const window_params& in_window_params, int argc, char** argv);
virtual int run();
virtual void shutdown();
void request_exit();
virtual void draw_gui() = 0;
virtual void tick(float delta_time) {}
virtual const char* get_shader_path() = 0;
virtual void init_imgui(ImGuiContext* in_context) = 0;
[[nodiscard]] static std::shared_ptr<texture> load_texture(const std::string& path, vk::Format format = vk::Format::eR8G8B8A8Unorm);
[[nodiscard]] static std::shared_ptr<texture> create_texture(const unsigned char* data, int width, int height, vk::Format format);
[[nodiscard]] virtual const char* get_entry_model() const = 0;
[[nodiscard]] virtual const char* get_draw_ps_vertex_shader_entry() const = 0; // Vertex Shader used for drawing ps
[[nodiscard]] renderer* get_renderer() const { return renderer_; }
protected:
renderer* renderer_ = nullptr;
std::shared_ptr<spdlog::logger> async_spdlog_;
private:
static void init_glfw();
void init_imgui();
void destroy_glfw();
void destroy_imgui();
};

View File

@ -1,95 +0,0 @@
#include "window_manager.h"
#include <ranges>
#include "audio/plugin_host/plugin_host.h"
window_manager::window_manager() {
main_window_ = nullptr;
}
void window_manager::init(singleton_initliazer& initliazer) {
singleton_t<window_manager>::init(initliazer);
// start_idle_thread();
}
void window_manager::release(singleton_release_guard& release_guard) {
singleton_t<window_manager>::release(release_guard);
if (main_window_)
glfwDestroyWindow(main_window_);
}
void window_manager::tick() {
glfwPollEvents();
if (should_close()) {
destroy_all_plugin_host_window();
return;
}
update_host_window();
}
void window_manager::destroy_all_plugin_host_window() {
for (const auto& window: host_window_map_ | std::views::values) {
glfwDestroyWindow(window);
}
host_window_map_.clear();
}
GLFWwindow* window_manager::create_main_window(const char* title, int width, int height) {
if (!main_window_)
main_window_ = glfwCreateWindow(width, height, title, nullptr, nullptr);
return main_window_;
}
GLFWwindow* window_manager::create_plugin_host_window(plugin_host* host) {
if (!host->has_editor())
return nullptr;
if (host_window_map_.contains(host))
return host_window_map_[host];
auto editor_size = host->get_editor_size();
auto new_window = glfwCreateWindow(editor_size.x, editor_size.y, host->name.c_str(), nullptr, nullptr);
if (host_window_pos_map_.contains(host)) {
auto pos = host_window_pos_map_[host];
glfwSetWindowPos(new_window, pos.x, pos.y);
}else {
glfwSetWindowPos(new_window, 100, 100);
}
host_window_map_[host] = new_window;
glfwShowWindow(new_window);
return new_window;
}
void window_manager::destroy_plugin_host_window(plugin_host* host) {
if (!host_window_map_.contains(host))
return;
int x, y;
glfwGetWindowPos(host_window_map_[host], &x, &y);
glfwDestroyWindow(host_window_map_[host]);
host_window_map_.erase(host);
host_window_pos_map_[host] = ImVec2(x, y);
}
void window_manager::resize_plugin_host_window(plugin_host* host, int width, int height) {
if (!host_window_map_.contains(host))
return;
glfwSetWindowSize(host_window_map_[host], width, height);
}
void window_manager::idle_plugin_host_window() const {
for (const auto& window_map: host_window_map_) {
window_map.first->idle_editor();
}
}
void window_manager::update_host_window() {
std::vector<plugin_host*> host_editor_to_close;
for (const auto& [host, window]: host_window_map_) {
if (glfwWindowShouldClose(window)) {
host_editor_to_close.push_back(host);
}
}
for (auto host: host_editor_to_close) {
host->try_close_editor();
}
idle_plugin_host_window();
}

View File

@ -1,38 +0,0 @@
#pragma once
#include "GLFW/glfw3.h"
#include "misc/singleton/singleton.h"
#include <map>
#include "imgui.h"
class plugin_host;
class window_manager : public singleton_t<window_manager> {
public:
window_manager();
void init(singleton_initliazer& initliazer) override;
void release(singleton_release_guard& release_guard) override;
void tick();
bool should_close() const { return glfwWindowShouldClose(main_window_); }
void destroy_all_plugin_host_window();
GLFWwindow* create_main_window(const char* title, int width, int height);
void request_exit() const { glfwSetWindowShouldClose(main_window_, GLFW_TRUE); }
GLFWwindow* get_main_window() const { return main_window_; }
GLFWwindow* create_plugin_host_window(plugin_host* host);
void destroy_plugin_host_window(plugin_host* host);
void resize_plugin_host_window(plugin_host* host, int width, int height);
void idle_plugin_host_window() const;
const char* get_name() override { return "window_manager"; }
private:
void update_host_window();
GLFWwindow* main_window_;
std::map<plugin_host*, GLFWwindow*> host_window_map_;
std::map<plugin_host*, ImVec2> host_window_pos_map_;
};
DEFINE_SINGLETON_INSTANCE(window_manager)

View File

@ -1,6 +1,5 @@
#include "plugin_host.h"
#include "application/window_manager.h"
#include "audio/mixer/channel_interface.h"
plugin_host::~plugin_host() {
@ -12,8 +11,8 @@ void plugin_host::try_open_editor() {
return;
if (editor_opened)
return;
editor_window = g_window_manager.create_plugin_host_window(this);
open_editor(editor_window);
// editor_window = g_window_manager.create_plugin_host_window(this);
// open_editor(editor_window);
editor_opened = true;
}
@ -24,7 +23,7 @@ void plugin_host::try_close_editor() {
return;
close_editor();
editor_opened = false;
g_window_manager.destroy_plugin_host_window(this);
// g_window_manager.destroy_plugin_host_window(this);
}
void plugin_host::toggle_editor() {

View File

@ -1,6 +1,4 @@
#pragma once
#include "imgui.h"
#include "GLFW/glfw3.h"
class mixer_track;
class channel_interface;
@ -28,7 +26,7 @@ public:
virtual void idle_editor() {}
[[nodiscard]] virtual bool has_editor() const { return false; }
[[nodiscard]] virtual ImVec2 get_editor_size() const { return ImVec2(0, 0); }
// [[nodiscard]] virtual ImVec2 get_editor_size() const { return ImVec2(0, 0); }
[[nodiscard]] virtual std::string load_name() const { return ""; }
[[nodiscard]] virtual std::string load_vendor() const { return ""; }
@ -39,9 +37,8 @@ public:
std::string vendor;
channel_interface* channel = nullptr;
std::vector<mixer_track*> owner_tracks;
GLFWwindow* editor_window = nullptr;
bool editor_opened = false;
protected:
virtual void open_editor(GLFWwindow* window) = 0;
virtual void open_editor() = 0;
virtual void close_editor() = 0;
};

View File

@ -1,9 +1,7 @@
#include "vst2_plugin_host.h"
#include "application/window_manager.h"
#include "audio/device/audio_device_manager.h"
#include "audio/mixer/channel_interface.h"
#include "misc/glfw_misc.h"
std::map<std::string, std::weak_ptr<dynamic_library>> vst2_library_map;
VstTimeInfo vst2_plugin_host::vst_time_info{};
@ -65,7 +63,7 @@ VstIntPtr vst_master_callback(AEffect* effect, VstInt32 opcode, VstInt32 index,
case audioMasterSizeWindow:
{
// 设置插件窗口大小
g_window_manager.resize_plugin_host_window((plugin_host*)effect->user, index, value);
// g_window_manager.resize_plugin_host_window((plugin_host*)effect->user, index, value);
return 1;
}
case audioMasterGetTime:
@ -226,13 +224,13 @@ bool vst2_plugin_host::has_editor() const {
return effect_->flags & effFlagsHasEditor;
}
ImVec2 vst2_plugin_host::get_editor_size() const {
ERect* EditorRect = nullptr;
dispatch(effEditGetRect, 0, 0, &EditorRect);
if (EditorRect)
return ImVec2(EditorRect->right - EditorRect->left, EditorRect->bottom - EditorRect->top);
return ImVec2(0, 0);
}
// ImVec2 vst2_plugin_host::get_editor_size() const {
// ERect* EditorRect = nullptr;
// dispatch(effEditGetRect, 0, 0, &EditorRect);
// if (EditorRect)
// return ImVec2(EditorRect->right - EditorRect->left, EditorRect->bottom - EditorRect->top);
// return ImVec2(0, 0);
// }
std::string vst2_plugin_host::load_name() const {
char buffer[256];
@ -246,12 +244,12 @@ std::string vst2_plugin_host::load_vendor() const {
return buffer;
}
void vst2_plugin_host::open_editor(GLFWwindow* window) {
void vst2_plugin_host::open_editor() {
if (!has_editor())
return;
void* window_handle = glfwGetWindowHandle(window);
// void* window_handle = glfwGetWindowHandle(window);
dispatch(effEditOpen, 0, 0, window_handle);
// dispatch(effEditOpen, 0, 0, window_handle);
}
void vst2_plugin_host::close_editor() {

View File

@ -24,12 +24,12 @@ public:
void idle_editor() override;
[[nodiscard]] bool has_editor() const override;
[[nodiscard]] ImVec2 get_editor_size() const override;
// [[nodiscard]] ImVec2 get_editor_size() const override;
[[nodiscard]] std::string load_name() const override;
[[nodiscard]] std::string load_vendor() const override;
protected:
void open_editor(GLFWwindow* window) override;
void open_editor() override;
void close_editor() override;
private:
VstIntPtr dispatch(VstInt32 opcode, VstInt32 index = 0, VstIntPtr value = 0, void* ptr = nullptr, float opt = 0) const;

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +0,0 @@
#include "glfw_misc.h"
#ifdef WIN32
#define GLFW_EXPOSE_NATIVE_WIN32
#elif defined(__APPLE__)
#define GLFW_EXPOSE_NATIVE_COCOA
#else
#define GLFW_EXPOSE_NATIVE_X11
#endif
#include <GLFW/glfw3native.h>
void* glfwGetWindowHandle(GLFWwindow* window) {
#ifdef WIN32
return glfwGetWin32Window(window);
#elif defined(__APPLE__)
return glfwGetCocoaWindow(window);
#else
return glfwGetX11Window(window);
#endif
}

View File

@ -1,7 +0,0 @@
#pragma once
#include "GLFW/glfw3.h"
extern "C"
{
CORE_API void* glfwGetWindowHandle(GLFWwindow* window);
}

View File

@ -1,65 +0,0 @@
#include "buffer_vk.h"
#include "utils/utils.hpp"
buffer_vk::buffer_vk() {
buffer = nullptr;
memory = nullptr;
descriptor_type = vk::DescriptorType::eUniformBuffer;
}
void buffer_vk::create(uint32_t size, vk::BufferUsageFlagBits in_usage, vk::DescriptorType in_descriptor_type) {
destroy();
buffer_size = size;
descriptor_type = in_descriptor_type;
const renderer* render_vk = application::get()->get_renderer();
const vk::Device& device = render_vk->device;
vk::BufferCreateInfo buffer_create_info;
buffer_create_info.setSize(size);
buffer_create_info.setUsage(in_usage);
buffer_create_info.setSharingMode(vk::SharingMode::eExclusive);
buffer = device.createBuffer(buffer_create_info);
const vk::PhysicalDeviceMemoryProperties memory_properties = render_vk->physical_device.getMemoryProperties();
const vk::MemoryRequirements memory_requirements = device.getBufferMemoryRequirements(buffer);
const auto memory_type = vk::su::findMemoryType(memory_properties, memory_requirements.memoryTypeBits, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
vk::MemoryAllocateInfo memory_allocate_info;
memory_allocate_info.setAllocationSize(memory_requirements.size);
memory_allocate_info.setMemoryTypeIndex(memory_type);
memory = device.allocateMemory(memory_allocate_info);
device.bindBufferMemory(buffer, memory, 0);
}
void buffer_vk::create_storage(uint32_t size) {
create(size, vk::BufferUsageFlagBits::eStorageBuffer, vk::DescriptorType::eStorageBuffer);
}
void buffer_vk::create_uniform(uint32_t size) {
create(size, vk::BufferUsageFlagBits::eUniformBuffer, vk::DescriptorType::eUniformBuffer);
}
void buffer_vk::create_staging(uint32_t size) {
create(size, vk::BufferUsageFlagBits::eTransferSrc, vk::DescriptorType::eUniformBuffer);
}
void buffer_vk::destroy() {
if (!buffer) {
return;
}
const renderer* render_vk = application::get()->get_renderer();
const vk::Device& device = render_vk->device;
device.destroyBuffer(buffer);
device.freeMemory(memory);
buffer = nullptr;
memory = nullptr;
}
void buffer_vk::update(const void* data, uint32_t size) {
const auto p = map<void>();
memcpy(p, data, size);
unmap();
}

View File

@ -1,53 +0,0 @@
#pragma once
#include <application/application.h>
#include <vulkan/vulkan.hpp>
#include "renderer.h"
class CORE_API buffer_vk {
public:
buffer_vk();
~buffer_vk() { destroy(); }
void create(uint32_t size, vk::BufferUsageFlagBits in_usage, vk::DescriptorType in_descriptor_type);
void create_storage(uint32_t size);
void create_uniform(uint32_t size);
void create_staging(uint32_t size);
void destroy();
template <typename T>
T* map() {
const auto& device = application::get()->get_renderer()->device;
void* mapped;
const auto err = device.mapMemory(memory, 0, buffer_size, vk::MemoryMapFlags(), &mapped);
check_vk_result(err);
return static_cast<T*>(mapped);
}
void unmap() const {
const auto& device = application::get()->get_renderer()->device;
device.unmapMemory(memory);
}
void update(const void* data, uint32_t size);
template <typename T>
void update(const T& data) {
update(&data, sizeof(T));
}
template <typename T>
void update(const std::vector<T>& data) {
update(data.data(), data.size() * sizeof(T));
}
[[nodiscard]] vk::DescriptorBufferInfo get_descriptor_info() const {
vk::DescriptorBufferInfo descriptor_buffer_info;
descriptor_buffer_info.setBuffer(buffer);
descriptor_buffer_info.setOffset(0);
descriptor_buffer_info.setRange(buffer_size);
return descriptor_buffer_info;
}
vk::Buffer buffer;
vk::DeviceMemory memory;
vk::DescriptorType descriptor_type;
uint32_t buffer_size;
};

View File

@ -1,73 +0,0 @@
#include "compute_pipeline.h"
#include "renderer.h"
#include <vulkan/vulkan.hpp>
compute_pipeline::~compute_pipeline() {
const renderer* render_vk = application::get()->get_renderer();
const vk::Device& device = render_vk->device;
device.destroyShaderModule(shader_module_);
}
void compute_pipeline::add_binding(uint32_t binding, vk::DescriptorType descriptor_type, uint32_t descriptor_count,
vk::Sampler immutable_samplers) {
const vk::ShaderStageFlags flag = vk::ShaderStageFlagBits::eCompute;
vk::DescriptorSetLayoutBinding descriptor_set_layout_binding;
descriptor_set_layout_binding.setBinding(binding);
descriptor_set_layout_binding.setDescriptorType(descriptor_type);
descriptor_set_layout_binding.setDescriptorCount(descriptor_count);
descriptor_set_layout_binding.setStageFlags(flag);
if (immutable_samplers)
descriptor_set_layout_binding.setImmutableSamplers(immutable_samplers);
descriptor_set_layout_bindings_.push_back(descriptor_set_layout_binding);
}
void compute_pipeline::create() {
const renderer* render_vk = application::get()->get_renderer();
const vk::Device& device = render_vk->device;
create_pipeline_layout();
vk::PipelineShaderStageCreateInfo pipeline_shader_stage_create_info;
pipeline_shader_stage_create_info.setStage(vk::ShaderStageFlagBits::eCompute);
pipeline_shader_stage_create_info.setModule(shader_module_);
pipeline_shader_stage_create_info.setPName("main");
vk::ComputePipelineCreateInfo pipeline_create_info;
pipeline_create_info.setLayout(pipeline_layout_);
pipeline_create_info.setStage(pipeline_shader_stage_create_info);
const auto pipeline_result = device.createComputePipeline(VK_NULL_HANDLE, pipeline_create_info);
check_vk_result(pipeline_result.result);
pipeline_ = pipeline_result.value;
}
void compute_pipeline::dispatch(uint32_t group_count_x, uint32_t group_count_y, uint32_t group_count_z) const {
#ifdef _DEBUG
if (pipeline_ == vk::Pipeline()) {
throw std::runtime_error("Pipeline not created");
}
#endif
renderer* render_vk = application::get()->get_renderer();
const vk::CommandBuffer command_buffer = render_vk->create_command_buffer(vk::CommandBufferLevel::ePrimary, true);
command_buffer.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline_);
command_buffer.bindDescriptorSets(vk::PipelineBindPoint::eCompute, pipeline_layout_, 0, descriptor_set_, nullptr);
command_buffer.dispatch(group_count_x, group_count_y, group_count_z);
render_vk->end_command_buffer(command_buffer, true);
}
void compute_pipeline::set_shader(const uint8_t* shader_code, size_t shader_code_size) {
const renderer* render_vk = application::get()->get_renderer();
const vk::Device& device = render_vk->device;
vk::ShaderModuleCreateInfo shader_module_create_info;
shader_module_create_info.setCodeSize(shader_code_size);
shader_module_create_info.setPCode(reinterpret_cast<const uint32_t*>(shader_code));
shader_module_ = device.createShaderModule(shader_module_create_info);
}

View File

@ -1,15 +0,0 @@
#pragma once
#include "pipeline.h"
class CORE_API compute_pipeline : public pipeline {
public:
~compute_pipeline() override;
void add_binding(uint32_t binding, vk::DescriptorType descriptor_type, uint32_t descriptor_count, vk::Sampler immutable_samplers) override;
void create() override;
void dispatch(uint32_t group_count_x, uint32_t group_count_y, uint32_t group_count_z) const;
void set_shader(const uint8_t *shader_code, size_t shader_code_size);
private:
vk::ShaderModule shader_module_;
};

View File

@ -1,119 +0,0 @@
#include "pipeline.h"
#include "renderer.h"
#include "texture.h"
pipeline::~pipeline() {
const renderer* render_vk = application::get()->get_renderer();
const vk::Device& device = render_vk->device;
device.destroyDescriptorPool(descriptor_pool_);
device.destroyDescriptorSetLayout(descriptor_set_layout_);
device.destroyPipelineLayout(pipeline_layout_);
device.destroyPipeline(pipeline_);
}
void pipeline::add_uniform_buffer(uint32_t binding, std::shared_ptr<buffer_vk> buf) {
add_binding(binding, vk::DescriptorType::eUniformBuffer, 1, nullptr);
buffers_[binding] = buf;
}
void pipeline::add_storage_buffer(uint32_t binding, std::shared_ptr<buffer_vk> buf) {
add_binding(binding, vk::DescriptorType::eStorageBuffer, 1, nullptr);
buffers_[binding] = buf;
}
void pipeline::add_sampled_image(uint32_t binding, std::shared_ptr<render_resource> in_texture) {
add_binding(binding, vk::DescriptorType::eSampledImage, 1, in_texture->sampler);
textures_[binding] = in_texture;
}
void pipeline::add_storage_image(uint32_t binding, std::shared_ptr<render_resource> in_texture) {
add_binding(binding, vk::DescriptorType::eStorageImage, 1, in_texture->sampler);
textures_[binding] = in_texture;
}
void pipeline::add_input_attachment(uint32_t binding) {
add_binding(binding, vk::DescriptorType::eInputAttachment, 1, nullptr);
}
void pipeline::add_sampler(uint32_t binding, vk::Sampler immutable_samplers) {
add_binding(binding, vk::DescriptorType::eSampler, 1, immutable_samplers);
}
void pipeline::add_combined_image(uint32_t binding, std::shared_ptr<render_resource> in_texture) {
add_binding(binding, vk::DescriptorType::eCombinedImageSampler, 1, in_texture->sampler);
textures_[binding] = in_texture;
}
void pipeline::create_pipeline_layout() {
const renderer* render_vk = application::get()->get_renderer();
const vk::Device& device = render_vk->device;
vk::DescriptorSetLayoutCreateInfo descriptor_set_layout_create_info;
descriptor_set_layout_create_info.setBindings(descriptor_set_layout_bindings_);
descriptor_set_layout_ = device.createDescriptorSetLayout(descriptor_set_layout_create_info);
std::vector<vk::DescriptorPoolSize> pool_sizes;
{
std::map<vk::DescriptorType, uint32_t> temp_pool_sizes;
for (const auto& binding: descriptor_set_layout_bindings_) {
temp_pool_sizes[binding.descriptorType]++;
}
for (const auto& pair: temp_pool_sizes) {
pool_sizes.emplace_back(pair.first, pair.second);
}
}
vk::DescriptorPoolCreateInfo descriptor_pool_create_info;
descriptor_pool_create_info.setMaxSets(1);
descriptor_pool_create_info.setPoolSizes(pool_sizes);
descriptor_pool_ = device.createDescriptorPool(descriptor_pool_create_info);
vk::DescriptorSetAllocateInfo descriptor_set_allocate_info;
descriptor_set_allocate_info.setDescriptorPool(descriptor_pool_);
descriptor_set_allocate_info.setDescriptorSetCount(1);
descriptor_set_allocate_info.setSetLayouts(descriptor_set_layout_);
const std::vector<vk::DescriptorSet>& sets = device.allocateDescriptorSets(descriptor_set_allocate_info);
descriptor_set_ = sets.front();
std::vector<vk::WriteDescriptorSet> write_descriptor_sets;
std::vector<std::vector<vk::DescriptorBufferInfo>> temp_buffer_infos;
std::vector<std::vector<vk::DescriptorImageInfo>> temp_image_infoses;
for (const auto& binding_info: descriptor_set_layout_bindings_) {
vk::WriteDescriptorSet write_descriptor_set;
write_descriptor_set.setDstSet(descriptor_set_);
write_descriptor_set.setDstBinding(binding_info.binding);
write_descriptor_set.setDescriptorType(binding_info.descriptorType);
switch (binding_info.descriptorType) {
case vk::DescriptorType::eCombinedImageSampler:
case vk::DescriptorType::eSampledImage:
case vk::DescriptorType::eStorageImage: {
const auto& t = textures_[binding_info.binding];
vk::DescriptorImageInfo image_info = t->get_descriptor_info();
temp_image_infoses.push_back({image_info});
write_descriptor_set.setImageInfo(temp_image_infoses.back());
}
break;
case vk::DescriptorType::eUniformBuffer:
case vk::DescriptorType::eStorageBuffer: {
const auto& b = buffers_[binding_info.binding];
vk::DescriptorBufferInfo buffer_info = b->get_descriptor_info();
temp_buffer_infos.push_back( {buffer_info} );
write_descriptor_set.setBufferInfo(temp_buffer_infos.back());
}
break;
default:
continue;
}
write_descriptor_sets.push_back(write_descriptor_set);
}
device.updateDescriptorSets(write_descriptor_sets, nullptr);
vk::PipelineLayoutCreateInfo pipeline_layout_create_info;
pipeline_layout_create_info.setSetLayouts(descriptor_set_layout_);
pipeline_layout_ = device.createPipelineLayout(pipeline_layout_create_info);
}

View File

@ -1,47 +0,0 @@
#pragma once
#include <vulkan/vulkan.hpp>
#include <map>
#include "buffer_vk.h"
class render_resource;
class texture;
/// 1. add_binding
/// 2. create();
/// 3. dispatch();
class CORE_API pipeline {
public:
virtual ~pipeline();
virtual void add_binding(uint32_t binding, vk::DescriptorType descriptor_type, uint32_t descriptor_count, vk::Sampler immutable_samplers) = 0;
void add_uniform_buffer(uint32_t binding, std::shared_ptr<buffer_vk> buf);
void add_storage_buffer(uint32_t binding, std::shared_ptr<buffer_vk> buf);
void add_sampled_image(uint32_t binding, std::shared_ptr<render_resource> in_texture);
void add_storage_image(uint32_t binding, std::shared_ptr<render_resource> in_texture);
void add_input_attachment(uint32_t binding);
void add_sampler(uint32_t binding, vk::Sampler immutable_samplers = nullptr);
void add_combined_image(uint32_t binding, std::shared_ptr<render_resource> in_texture);
virtual void create() = 0;
protected:
vk::Pipeline pipeline_;
vk::PipelineLayout pipeline_layout_;
vk::DescriptorSetLayout descriptor_set_layout_;
vk::DescriptorSet descriptor_set_;
vk::DescriptorPool descriptor_pool_;
std::vector<vk::DescriptorSetLayoutBinding> descriptor_set_layout_bindings_;
std::map<uint32_t, std::shared_ptr<buffer_vk>> buffers_;
std::map<uint32_t, std::shared_ptr<render_resource>> textures_;
protected:
void create_pipeline_layout();
};

View File

@ -1,74 +0,0 @@
#pragma once
#include "imgui.h"
#include "renderer.h"
#include "application/application.h"
class render_resource : public std::enable_shared_from_this<render_resource> {
public:
render_resource() {
format = vk::Format::eUndefined;
width_ = 0;
height_ = 0;
image = nullptr;
image_view = nullptr;
sampler = nullptr;
memory = nullptr;
descriptor_set = nullptr;
}
virtual ~render_resource() {
render_resource::destroy();
}
[[nodiscard]] int get_width() const { return width_; }
[[nodiscard]] int get_height() const { return height_; }
[[nodiscard]] ImTextureID get_texture_id() const { return descriptor_set; }
[[nodiscard]] vk::DescriptorImageInfo get_descriptor_info() const {
vk::DescriptorImageInfo info;
info.setImageLayout(vk::ImageLayout::eShaderReadOnlyOptimal);
info.setImageView(image_view);
info.setSampler(sampler);
return info;
}
void init(uint32_t width, uint32_t height, vk::Format in_format) {
width_ = width;
height_ = height;
format = in_format;
on_init();
}
void resize(uint32_t width, uint32_t height) {
if (width_ == width && height_ == height) {
return;
}
destroy();
init(width, height, format);
}
void draw() const {
ImGui::Image(get_texture_id(), ImVec2(static_cast<float>(get_width()), static_cast<float>(get_height())));
}
virtual void destroy() {
const auto r = application::get()->get_renderer();
const auto& device = r->device;
device.destroySampler(sampler);
device.destroyImageView(image_view);
device.destroyImage(image);
device.freeMemory(memory);
ImGui_ImplVulkan_RemoveTexture(descriptor_set);
sampler = nullptr;
image_view = nullptr;
image = nullptr;
memory = nullptr;
descriptor_set = nullptr;
}
vk::Image image;
vk::ImageView image_view;
vk::Sampler sampler;
vk::DescriptorSet descriptor_set;
vk::DeviceMemory memory;
vk::Format format;
protected:
virtual void on_init() = 0;
uint32_t width_;
uint32_t height_;
};

View File

@ -1,464 +0,0 @@
#include "renderer.h"
#include "imgui_impl_glfw.h"
#include "application/application.h"
#include "texture.h"
#ifdef APP_USE_VULKAN_DEBUG_REPORT
static VKAPI_ATTR VkBool32 VKAPI_CALL on_debug_report(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage, void* pUserData)
{
(void)flags; (void)object; (void)location; (void)messageCode; (void)pUserData; (void)pLayerPrefix; // Unused arguments
fprintf(stderr, "[vulkan] Debug report from ObjectType: %i\nMessage: %s\n\n", objectType, pMessage);
return VK_FALSE;
}
#endif // APP_USE_VULKAN_DEBUG_REPORT
static bool is_extension_available(const std::vector<vk::ExtensionProperties>& properties, const char* extension) {
return std::ranges::any_of(properties, [extension](const vk::ExtensionProperties& p) {
return strcmp(p.extensionName, extension) == 0;
});
}
vk::CommandPool renderer::get_command_pool() const {
return main_window_data.Frames[main_window_data.FrameIndex].CommandPool;
}
vk::CommandBuffer renderer::create_command_buffer(vk::CommandBufferLevel level, bool begin) const {
vk::CommandBufferAllocateInfo alloc_info;
alloc_info.setCommandPool(get_command_pool());
alloc_info.setLevel(level);
alloc_info.setCommandBufferCount(1);
vk::CommandBuffer command_buffer;
auto err = device.allocateCommandBuffers(&alloc_info, &command_buffer);
check_vk_result(err);
// If requested, also start the new command buffer
if (begin) {
vk::CommandBufferBeginInfo begin_info;
begin_info.setFlags(vk::CommandBufferUsageFlagBits::eOneTimeSubmit);
command_buffer.begin(begin_info);
}
return command_buffer;
}
void renderer::end_command_buffer(vk::CommandBuffer command_buffer, bool use_fence) const {
command_buffer.end();
if (use_fence) {
vk::FenceCreateInfo fence_create_info = {};
vk::Fence fence = device.createFence(fence_create_info);
vk::SubmitInfo submit_info;
submit_info.setCommandBuffers(command_buffer);
queue.submit(submit_info, fence);
const auto err = device.waitForFences(1, &fence, VK_TRUE, 100000000000);
check_vk_result(err);
device.destroyFence(fence);
}
else {
vk::SubmitInfo submit_info;
submit_info.setCommandBuffers(command_buffer);
queue.submit(submit_info, nullptr);
}
}
void renderer::init_vulkan(GLFWwindow* window_handle) {
std::vector<const char*> extensions;
uint32_t extensions_count = 0;
const char** glfw_extensions = glfwGetRequiredInstanceExtensions(&extensions_count);
for (uint32_t i = 0; i < extensions_count; i++)
extensions.push_back(glfw_extensions[i]);
setup_vulkan(extensions);
// Create Window Surface
VkSurfaceKHR surface;
VkResult err = glfwCreateWindowSurface(instance, window_handle, reinterpret_cast<VkAllocationCallbacks*>(allocator), &surface);
check_vk_result(err);
// Create Framebuffers
int w, h;
glfwGetFramebufferSize(window_handle, &w, &h);
setup_vulkan_window(surface, w, h);
ImGui_ImplGlfw_InitForVulkan(window_handle, true);
ImGui_ImplVulkan_InitInfo init_info = {};
init_info.Instance = instance;
init_info.PhysicalDevice = physical_device;
init_info.Device = device;
init_info.QueueFamily = queue_family;
init_info.Queue = queue;
init_info.PipelineCache = VK_NULL_HANDLE;
init_info.DescriptorPool = descriptor_pool;
init_info.RenderPass = main_window_data.RenderPass;
init_info.Subpass = 0;
init_info.MinImageCount = min_image_count;
init_info.ImageCount = main_window_data.ImageCount;
init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
init_info.Allocator = reinterpret_cast<VkAllocationCallbacks*>(allocator);
init_info.CheckVkResultFn = check_vk_result;
ImGui_ImplVulkan_Init(&init_info);
}
vk::PhysicalDevice renderer::setup_vulkan_select_physical_device() const {
const std::vector<vk::PhysicalDevice> gpus = instance.enumeratePhysicalDevices();
IM_ASSERT(!gpus.empty());
// If a number >1 of GPUs got reported, find discrete GPU if present, or use first one available. This covers
// most common cases (multi-gpu/integrated+dedicated graphics). Handling more complicated setups (multiple
// dedicated GPUs) is out of scope of this sample.
for (auto& device: gpus) {
if (const auto properties = device.getProperties(); properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu)
return device;
}
// Use first GPU (Integrated) is a Discrete one is not available.
if (!gpus.empty())
return gpus[0];
return VK_NULL_HANDLE;
}
void renderer::setup_vulkan(std::vector<const char*> instance_extensions) {
// Create Vulkan Instance
{
vk::InstanceCreateInfo create_info;
// VkInstanceCreateInfo create_info = {};
// create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
// Enumerate available extensions
auto properties = vk::enumerateInstanceExtensionProperties();
// Enable required extensions
if (is_extension_available(properties, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME))
instance_extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
#ifdef VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME
if (is_extension_available(properties, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME)) {
instance_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
create_info.flags |= vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR;
}
#endif
// Enabling validation layers
#ifdef APP_USE_VULKAN_DEBUG_REPORT
const char* layers[] = { "VK_LAYER_KHRONOS_validation" };
create_info.enabledLayerCount = 1;
create_info.ppEnabledLayerNames = layers;
instance_extensions.push_back("VK_EXT_debug_report");
#endif
// Create Vulkan Instance
create_info.setPEnabledExtensionNames(instance_extensions);
instance = vk::createInstance(create_info, allocator);
// Setup the debug report callback
#ifdef APP_USE_VULKAN_DEBUG_REPORT
auto vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT");
IM_ASSERT(vkCreateDebugReportCallbackEXT != nullptr);
VkDebugReportCallbackCreateInfoEXT debug_report_ci = {};
debug_report_ci.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
debug_report_ci.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
debug_report_ci.pfnCallback = on_debug_report;
debug_report_ci.pUserData = nullptr;
auto err = vkCreateDebugReportCallbackEXT(instance, &debug_report_ci, (VkAllocationCallbacks*)allocator, &debug_report);
check_vk_result(err);
#endif
}
// Select Physical Device (GPU)
physical_device = setup_vulkan_select_physical_device();
// Select graphics queue family
{
const auto queues = physical_device.getQueueFamilyProperties();
for (uint32_t i = 0; i < queues.size(); i++) {
if (queues[i].queueFlags & vk::QueueFlagBits::eGraphics) {
queue_family = i;
break;
}
}
IM_ASSERT(queue_family != static_cast<uint32_t>(-1));
}
// Create Logical Device (with 1 queue)
{
std::vector<const char*> device_extensions;
device_extensions.emplace_back("VK_KHR_swapchain");
// Enumerate physical device extension
auto properties = physical_device.enumerateDeviceExtensionProperties();
#ifdef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME
if (is_extension_available(properties, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME))
device_extensions.push_back(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME);
#endif
std::vector<float> queue_priority = {1.0f};
vk::DeviceQueueCreateInfo queue_info;
queue_info.setQueueFamilyIndex(queue_family);
queue_info.setQueuePriorities(queue_priority);
vk::DeviceCreateInfo create_info;
create_info.setQueueCreateInfos(queue_info);
create_info.setPEnabledExtensionNames(device_extensions);
device = physical_device.createDevice(create_info, allocator);
queue = device.getQueue(queue_family, 0);
}
// Create Descriptor Pool
// The example only requires a single combined image sampler descriptor for the font image and only uses one descriptor set (for that)
// If you wish to load e.g. additional textures you may need to alter pools sizes.
{
std::vector<vk::DescriptorPoolSize> pool_sizes;
pool_sizes.emplace_back(vk::DescriptorType::eCombinedImageSampler, 1);
vk::DescriptorPoolCreateInfo descriptor_pool_create_info;
descriptor_pool_create_info.setMaxSets(16);
descriptor_pool_create_info.setPoolSizes(pool_sizes);
descriptor_pool = device.createDescriptorPool(descriptor_pool_create_info);
}
}
// All the ImGui_ImplVulkanH_XXX structures/functions are optional helpers used by the demo.
// Your real engine/app may not use them.
void renderer::setup_vulkan_window(VkSurfaceKHR surface, int width,
int height) {
main_window_data.Surface = surface;
// Check for WSI support
vk::Bool32 res;
const auto err = physical_device.getSurfaceSupportKHR(queue_family, main_window_data.Surface, &res);
check_vk_result(err);
if (res != VK_TRUE) {
fprintf(stderr, "Error no WSI support on physical device 0\n");
exit(-1);
}
// Select Surface Format
constexpr VkFormat requestSurfaceImageFormat[] = {
VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM
};
constexpr VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
main_window_data.SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(physical_device, main_window_data.Surface, requestSurfaceImageFormat,
(size_t) IM_ARRAYSIZE(requestSurfaceImageFormat),
requestSurfaceColorSpace);
// Select Present Mode
#ifdef APP_USE_UNLIMITED_FRAME_RATE
VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR };
#else
VkPresentModeKHR present_modes[] = {VK_PRESENT_MODE_FIFO_KHR};
#endif
main_window_data.PresentMode = ImGui_ImplVulkanH_SelectPresentMode(physical_device, main_window_data.Surface, &present_modes[0],
IM_ARRAYSIZE(present_modes));
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
IM_ASSERT(min_image_count >= 2);
ImGui_ImplVulkanH_CreateOrResizeWindow(instance, physical_device, device, &main_window_data, queue_family,
reinterpret_cast<VkAllocationCallbacks*>(allocator), width,
height, min_image_count);
}
void renderer::cleanup_vulkan() const {
device.destroyDescriptorPool(descriptor_pool);
#ifdef APP_USE_VULKAN_DEBUG_REPORT
// Remove the debug report callback
auto vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT");
vkDestroyDebugReportCallbackEXT(instance, debug_report, (VkAllocationCallbacks*)allocator);
#endif // APP_USE_VULKAN_DEBUG_REPORT
device.destroy();
instance.destroy();
}
void renderer::cleanup_vulkan_window() {
ImGui_ImplVulkanH_DestroyWindow(instance, device, &main_window_data,
reinterpret_cast<VkAllocationCallbacks*>(allocator));
}
void renderer::frame_render(ImDrawData* draw_data) {
vk::Semaphore image_acquired_semaphore = main_window_data.FrameSemaphores[main_window_data.SemaphoreIndex].ImageAcquiredSemaphore;
vk::Semaphore render_complete_semaphore = main_window_data.FrameSemaphores[main_window_data.SemaphoreIndex].RenderCompleteSemaphore;
vk::Result err = device.acquireNextImageKHR(main_window_data.Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE,
&main_window_data.FrameIndex);
if (err == vk::Result::eErrorOutOfDateKHR || err == vk::Result::eSuboptimalKHR) {
swap_chain_rebuild_ = true;
return;
}
check_vk_result(err);
ImGui_ImplVulkanH_Frame* fd = &main_window_data.Frames[main_window_data.FrameIndex];
const vk::CommandBuffer cmd_buf = fd->CommandBuffer;
const vk::Fence fence = fd->Fence; {
err = device.waitForFences(1, &fence, VK_TRUE, UINT64_MAX);
// wait indefinitely instead of periodically checking
check_vk_result(err);
err = device.resetFences(1, &fence);
check_vk_result(err);
} {
const vk::CommandPool command_pool = fd->CommandPool;
device.resetCommandPool(command_pool);
vk::CommandBufferBeginInfo info = {};
info.setFlags(vk::CommandBufferUsageFlagBits::eOneTimeSubmit);
cmd_buf.begin(info);
} {
const vk::Framebuffer framebuffer = fd->Framebuffer;
const vk::RenderPass render_pass = main_window_data.RenderPass;
const auto clear_color = main_window_data.ClearValue.color.float32;
const auto clear_depth = main_window_data.ClearValue.depthStencil.depth;
const auto clear_stencil = main_window_data.ClearValue.depthStencil.stencil;
vk::ClearValue clear_value;
clear_value.color = vk::ClearColorValue(std::array<float, 4>{
clear_color[0], clear_color[1], clear_color[2], clear_color[3]
});
clear_value.depthStencil = vk::ClearDepthStencilValue(clear_depth, clear_stencil);
std::vector<vk::ClearValue> clear_values;
clear_values.emplace_back(clear_value);
vk::RenderPassBeginInfo info;
info.setRenderPass(render_pass);
info.setFramebuffer(framebuffer);
info.renderArea.extent.width = main_window_data.Width;
info.renderArea.extent.height = main_window_data.Height;
info.setClearValues(clear_values);
cmd_buf.beginRenderPass(info, vk::SubpassContents::eInline);
}
// Record dear imgui primitives into command buffer
ImGui_ImplVulkan_RenderDrawData(draw_data, fd->CommandBuffer);
// Submit command buffer
vkCmdEndRenderPass(fd->CommandBuffer); {
vk::PipelineStageFlags wait_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput;
vk::SubmitInfo info;
info.setWaitSemaphores(image_acquired_semaphore);
info.setWaitDstStageMask(wait_stage);
info.setCommandBuffers(cmd_buf);
info.setSignalSemaphores(render_complete_semaphore);
cmd_buf.end();
err = queue.submit(1, &info, fence);
check_vk_result(err);
}
}
void renderer::frame_present() {
if (swap_chain_rebuild_)
return;
vk::Semaphore render_complete_semaphore = main_window_data.FrameSemaphores[main_window_data.SemaphoreIndex].RenderCompleteSemaphore;
vk::SwapchainKHR swapchain = main_window_data.Swapchain;
uint32_t frame_index = main_window_data.FrameIndex;
vk::PresentInfoKHR info;
info.setWaitSemaphores(render_complete_semaphore);
info.setSwapchains(swapchain);
info.setImageIndices(frame_index);
try {
(void)queue.presentKHR(info);
} catch (const vk::OutOfDateKHRError& e) {
swap_chain_rebuild_ = true;
return;
}
main_window_data.SemaphoreIndex = (main_window_data.SemaphoreIndex + 1) % main_window_data.SemaphoreCount; // Now we can use the next set of semaphores
}
void renderer::pre_init() {
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
}
bool renderer::init(GLFWwindow* window_handle) {
if (has_initialized_)
return true;
if (!glfwVulkanSupported()) {
throw std::runtime_error("Vulkan not supported");
}
init_vulkan(window_handle);
has_initialized_ = true;
return true;
}
void renderer::shutdown() {
ImGui_ImplGlfw_Shutdown();
ImGui_ImplVulkan_Shutdown();
cleanup_vulkan_window();
cleanup_vulkan();
}
void renderer::new_frame(GLFWwindow* window_handle) {
// Resize swap chain?
if (swap_chain_rebuild_)
{
int width, height;
glfwGetFramebufferSize(window_handle, &width, &height);
if (width > 0 && height > 0)
{
ImGui_ImplVulkan_SetMinImageCount(min_image_count);
ImGui_ImplVulkanH_CreateOrResizeWindow(instance, physical_device, device, &main_window_data, queue_family, reinterpret_cast<VkAllocationCallbacks*>(allocator), width, height, min_image_count);
main_window_data.FrameIndex = 0;
swap_chain_rebuild_ = false;
}
}
// Start the Dear ImGui frame
ImGui_ImplVulkan_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
}
void renderer::end_frame(GLFWwindow* window_handle) {
ImGuiIO& io = ImGui::GetIO();
// Rendering
ImGui::Render();
ImDrawData* main_draw_data = ImGui::GetDrawData();
const bool main_is_minimized = (main_draw_data->DisplaySize.x <= 0.0f || main_draw_data->DisplaySize.y <= 0.0f);
main_window_data.ClearValue.color.float32[0] = clear_color.x * clear_color.w;
main_window_data.ClearValue.color.float32[1] = clear_color.y * clear_color.w;
main_window_data.ClearValue.color.float32[2] = clear_color.z * clear_color.w;
main_window_data.ClearValue.color.float32[3] = clear_color.w;
if (!main_is_minimized)
frame_render(main_draw_data);
// Update and Render additional Platform Windows
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
}
// Present Main Platform Window
if (!main_is_minimized)
frame_present();
}
std::shared_ptr<texture> renderer::create_texture(const uint8_t* data, int width, int height, vk::Format format) {
auto out = std::make_shared<texture>();
out->init(width, height, format);
if (data)
out->upload(data, width * height * 4);
return out;
}

View File

@ -1,88 +0,0 @@
#pragma once
#include "imgui_impl_vulkan.h"
#include "imgui.h"
#include "GLFW/glfw3.h"
#include <vulkan/vulkan.hpp>
// #ifdef _DEBUG
// #define APP_USE_VULKAN_DEBUG_REPORT
// #endif
#define APP_USE_UNLIMITED_FRAME_RATE
class render_target;
class texture;
constexpr ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
constexpr float clear_color_with_alpha[4] = {
clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w
};
static void check_vk_result(vk::Result err) {
if (err == vk::Result::eSuccess)
return;
spdlog::error("[vulkan] Error: VkResult = {}", vk::to_string(err));
abort();
}
static void check_vk_result(VkResult err) {
if (err == VK_SUCCESS)
return;
if (err < 0) {
spdlog::error("[vulkan] Error: VkResult = {}", (int)err);
abort();
}
}
class renderer {
public:
virtual ~renderer() = default;
void pre_init();
bool init(GLFWwindow* window_handle);
virtual void shutdown();
void new_frame(GLFWwindow* window_handle);
void end_frame(GLFWwindow* window_handle);
static CORE_API std::shared_ptr<texture> create_texture(const uint8_t* data, int width, int height, vk::Format format);
void set_vsync(const bool vsync) { vsync_ = vsync; }
vk::AllocationCallbacks* allocator = nullptr;
vk::Instance instance = VK_NULL_HANDLE;
vk::PhysicalDevice physical_device = VK_NULL_HANDLE;
vk::Device device = VK_NULL_HANDLE;
uint32_t queue_family = (uint32_t) -1;
vk::Queue queue = VK_NULL_HANDLE;
vk::DescriptorPool descriptor_pool = VK_NULL_HANDLE;
#ifdef APP_USE_VULKAN_DEBUG_REPORT
VkDebugReportCallbackEXT debug_report = VK_NULL_HANDLE;
#endif
[[nodiscard]] vk::CommandPool get_command_pool() const;
[[nodiscard]] vk::CommandBuffer create_command_buffer(vk::CommandBufferLevel level, bool begin) const;
void end_command_buffer(vk::CommandBuffer command_buffer, bool use_fence = false) const;
ImGui_ImplVulkanH_Window main_window_data;
int min_image_count = 2;
protected:
void init_vulkan(GLFWwindow* window_handle);
[[nodiscard]] vk::PhysicalDevice setup_vulkan_select_physical_device() const;
void setup_vulkan(std::vector<const char*> instance_extensions);
void setup_vulkan_window(VkSurfaceKHR surface, int width, int height);
void cleanup_vulkan() const;
void cleanup_vulkan_window();
void frame_render(ImDrawData* draw_data);
void frame_present();
bool has_initialized_ = false;
bool swap_chain_rebuild_ = false;
bool vsync_ = true;
};

View File

@ -1,130 +0,0 @@
#include "texture.h"
#include "buffer_vk.h"
#include "application/application.h"
#include "renderer.h"
#include "utils/utils.hpp"
texture::texture() {
memory = nullptr;
}
void texture::upload(const void* data, size_t size) {
renderer* r = application::get()->get_renderer();
const vk::Device& device = r->device;
// Create Upload Buffer
vk::BufferCreateInfo buffer_info;
buffer_info.setSize(size);
buffer_info.setUsage(vk::BufferUsageFlagBits::eTransferSrc);
buffer_info.setSharingMode(vk::SharingMode::eExclusive);
vk::Buffer upload_buffer = device.createBuffer(buffer_info);
vk::MemoryRequirements req = device.getBufferMemoryRequirements(upload_buffer);
uint32_t upload_memory_type = vk::su::findMemoryType(r->physical_device.getMemoryProperties(), req.memoryTypeBits,
vk::MemoryPropertyFlagBits::eHostVisible);
vk::MemoryAllocateInfo alloc_info;
alloc_info.setAllocationSize(req.size);
alloc_info.setMemoryTypeIndex(upload_memory_type);
vk::DeviceMemory upload_memory = device.allocateMemory(alloc_info);
device.bindBufferMemory(upload_buffer, upload_memory, 0);
void* p = device.mapMemory(upload_memory, 0, size);
memcpy(p, data, size);
vk::MappedMemoryRange memory_range;
memory_range.setMemory(upload_memory);
memory_range.setSize(size);
device.flushMappedMemoryRanges(memory_range);
device.unmapMemory(upload_memory);
const vk::CommandBuffer command_buffer = r->create_command_buffer(vk::CommandBufferLevel::ePrimary, true);
vk::ImageMemoryBarrier copy_barrier;
copy_barrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite);
copy_barrier.setOldLayout(vk::ImageLayout::eUndefined);
copy_barrier.setNewLayout(vk::ImageLayout::eTransferDstOptimal);
copy_barrier.setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED);
copy_barrier.setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED);
copy_barrier.setImage(image);
copy_barrier.setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1});
command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eHost, vk::PipelineStageFlagBits::eTransfer, {}, {}, {},
copy_barrier);
vk::BufferImageCopy region;
region.setImageSubresource({vk::ImageAspectFlagBits::eColor, 0, 0, 1});
region.setImageExtent({static_cast<uint32_t>(width_), static_cast<uint32_t>(height_), 1});
command_buffer.copyBufferToImage(upload_buffer, image, vk::ImageLayout::eTransferDstOptimal, region);
vk::ImageMemoryBarrier use_barrier;
use_barrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite);
use_barrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead);
use_barrier.setOldLayout(vk::ImageLayout::eTransferDstOptimal);
use_barrier.setNewLayout(vk::ImageLayout::eShaderReadOnlyOptimal);
use_barrier.setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED);
use_barrier.setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED);
use_barrier.setImage(image);
use_barrier.setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1});
command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {},
{}, {}, use_barrier);
r->end_command_buffer(command_buffer);
device.waitIdle();
device.destroyBuffer(upload_buffer);
device.freeMemory(upload_memory);
// device.freeCommandBuffers(command_pool, command_buffer);
}
void texture::on_init() {
const renderer* r = application::get()->get_renderer();
const vk::Device& device = r->device;
const vk::PhysicalDevice& physical_device = r->physical_device;
vk::ImageCreateInfo image_info;
image_info.setImageType(vk::ImageType::e2D);
image_info.setFormat(format);
image_info.setExtent({ width_, height_, 1 });
image_info.setMipLevels(1);
image_info.setArrayLayers(1);
image_info.setSamples(vk::SampleCountFlagBits::e1);
image_info.setTiling(vk::ImageTiling::eOptimal);
image_info.setUsage(vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eStorage);
image_info.setSharingMode(vk::SharingMode::eExclusive);
image_info.setInitialLayout(vk::ImageLayout::eUndefined);
image = device.createImage(image_info);
const vk::PhysicalDeviceMemoryProperties memory_properties = physical_device.getMemoryProperties();
const vk::MemoryRequirements memory_requirements = device.getImageMemoryRequirements(image);
const uint32_t memory_type = vk::su::findMemoryType(memory_properties, memory_requirements.memoryTypeBits,
vk::MemoryPropertyFlagBits::eDeviceLocal);
vk::MemoryAllocateInfo memory_allocate_info;
memory_allocate_info.setAllocationSize(memory_requirements.size);
memory_allocate_info.setMemoryTypeIndex(memory_type);
memory = device.allocateMemory(memory_allocate_info);
device.bindImageMemory(image, memory, 0);
vk::ImageViewCreateInfo view_info;
view_info.setImage(image);
view_info.setViewType(vk::ImageViewType::e2D);
view_info.setFormat(format);
view_info.setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1});
image_view = device.createImageView(view_info);
vk::SamplerCreateInfo sampler_info;
sampler_info.setMagFilter(vk::Filter::eLinear);
sampler_info.setMinFilter(vk::Filter::eLinear);
sampler_info.setMipmapMode(vk::SamplerMipmapMode::eLinear);
sampler_info.setAddressModeU(vk::SamplerAddressMode::eRepeat);
sampler_info.setAddressModeV(vk::SamplerAddressMode::eRepeat);
sampler_info.setAddressModeW(vk::SamplerAddressMode::eRepeat);
sampler_info.setMinLod(-1000);
sampler_info.setMaxLod(1000);
sampler_info.setMaxAnisotropy(1);
sampler = device.createSampler(sampler_info);
descriptor_set = ImGui_ImplVulkan_AddTexture(sampler, image_view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}

View File

@ -1,17 +0,0 @@
#pragma once
#include "imgui.h"
#include <vulkan/vulkan.hpp>
#include "buffer_vk.h"
#include "render_resource.h"
class texture : public render_resource {
public:
texture();
bool is_valid() const { return image_view; }
void upload(const void* data, size_t size);
protected:
void on_init() override;
};

File diff suppressed because it is too large Load Diff

View File

@ -1,439 +0,0 @@
#pragma once
// Copyright(c) 2019, NVIDIA CORPORATION. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include <vulkan/vulkan.hpp>
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <iostream>
#include <limits>
#include <map>
#include <memory> // std::unique_ptr
namespace vk
{
namespace su
{
const uint64_t FenceTimeout = 100000000;
template <typename Func>
void oneTimeSubmit( vk::Device const & device, vk::CommandPool const & commandPool, vk::Queue const & queue, Func const & func )
{
vk::CommandBuffer commandBuffer =
device.allocateCommandBuffers( vk::CommandBufferAllocateInfo( commandPool, vk::CommandBufferLevel::ePrimary, 1 ) ).front();
commandBuffer.begin( vk::CommandBufferBeginInfo( vk::CommandBufferUsageFlagBits::eOneTimeSubmit ) );
func( commandBuffer );
commandBuffer.end();
queue.submit( vk::SubmitInfo( 0, nullptr, nullptr, 1, &commandBuffer ), nullptr );
queue.waitIdle();
}
template <class T>
void copyToDevice( vk::Device const & device, vk::DeviceMemory const & deviceMemory, T const * pData, size_t count, vk::DeviceSize stride = sizeof( T ) )
{
assert( sizeof( T ) <= stride );
uint8_t * deviceData = static_cast<uint8_t *>( device.mapMemory( deviceMemory, 0, count * stride ) );
if ( stride == sizeof( T ) )
{
memcpy( deviceData, pData, count * sizeof( T ) );
}
else
{
for ( size_t i = 0; i < count; i++ )
{
memcpy( deviceData, &pData[i], sizeof( T ) );
deviceData += stride;
}
}
device.unmapMemory( deviceMemory );
}
template <class T>
void copyToDevice( vk::Device const & device, vk::DeviceMemory const & deviceMemory, T const & data )
{
copyToDevice<T>( device, deviceMemory, &data, 1 );
}
template <class T>
VULKAN_HPP_INLINE constexpr const T & clamp( const T & v, const T & lo, const T & hi )
{
return v < lo ? lo : hi < v ? hi : v;
}
void setImageLayout(
vk::CommandBuffer const & commandBuffer, vk::Image image, vk::Format format, vk::ImageLayout oldImageLayout, vk::ImageLayout newImageLayout );
struct WindowData
{
WindowData( GLFWwindow * wnd, std::string const & name, vk::Extent2D const & extent );
WindowData( const WindowData & ) = delete;
WindowData( WindowData && other );
~WindowData() noexcept;
GLFWwindow * handle;
std::string name;
vk::Extent2D extent;
};
WindowData createWindow( std::string const & windowName, vk::Extent2D const & extent );
struct BufferData
{
BufferData( vk::PhysicalDevice const & physicalDevice,
vk::Device const & device,
vk::DeviceSize size,
vk::BufferUsageFlags usage,
vk::MemoryPropertyFlags propertyFlags = vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent );
void clear( vk::Device const & device )
{
device.destroyBuffer( buffer ); // to prevent some validation layer warning, the Buffer needs to be destroyed before the bound DeviceMemory
device.freeMemory( deviceMemory );
}
template <typename DataType>
void upload( vk::Device const & device, DataType const & data ) const
{
assert( ( m_propertyFlags & vk::MemoryPropertyFlagBits::eHostCoherent ) && ( m_propertyFlags & vk::MemoryPropertyFlagBits::eHostVisible ) );
assert( sizeof( DataType ) <= m_size );
void * dataPtr = device.mapMemory( deviceMemory, 0, sizeof( DataType ) );
memcpy( dataPtr, &data, sizeof( DataType ) );
device.unmapMemory( deviceMemory );
}
template <typename DataType>
void upload( vk::Device const & device, std::vector<DataType> const & data, size_t stride = 0 ) const
{
assert( m_propertyFlags & vk::MemoryPropertyFlagBits::eHostVisible );
size_t elementSize = stride ? stride : sizeof( DataType );
assert( sizeof( DataType ) <= elementSize );
copyToDevice( device, deviceMemory, data.data(), data.size(), elementSize );
}
template <typename DataType>
void upload( vk::PhysicalDevice const & physicalDevice,
vk::Device const & device,
vk::CommandPool const & commandPool,
vk::Queue queue,
std::vector<DataType> const & data,
size_t stride ) const
{
assert( m_usage & vk::BufferUsageFlagBits::eTransferDst );
assert( m_propertyFlags & vk::MemoryPropertyFlagBits::eDeviceLocal );
size_t elementSize = stride ? stride : sizeof( DataType );
assert( sizeof( DataType ) <= elementSize );
size_t dataSize = data.size() * elementSize;
assert( dataSize <= m_size );
vk::su::BufferData stagingBuffer( physicalDevice, device, dataSize, vk::BufferUsageFlagBits::eTransferSrc );
copyToDevice( device, stagingBuffer.deviceMemory, data.data(), data.size(), elementSize );
vk::su::oneTimeSubmit( device,
commandPool,
queue,
[&]( vk::CommandBuffer const & commandBuffer )
{ commandBuffer.copyBuffer( stagingBuffer.buffer, buffer, vk::BufferCopy( 0, 0, dataSize ) ); } );
stagingBuffer.clear( device );
}
vk::Buffer buffer;
vk::DeviceMemory deviceMemory;
#if !defined( NDEBUG )
private:
vk::DeviceSize m_size;
vk::BufferUsageFlags m_usage;
vk::MemoryPropertyFlags m_propertyFlags;
#endif
};
struct ImageData
{
ImageData( vk::PhysicalDevice const & physicalDevice,
vk::Device const & device,
vk::Format format,
vk::Extent2D const & extent,
vk::ImageTiling tiling,
vk::ImageUsageFlags usage,
vk::ImageLayout initialLayout,
vk::MemoryPropertyFlags memoryProperties,
vk::ImageAspectFlags aspectMask );
void clear( vk::Device const & device )
{
device.destroyImageView( imageView );
device.destroyImage( image ); // the Image should to be destroyed before the bound DeviceMemory is freed
device.freeMemory( deviceMemory );
}
vk::Format format;
vk::Image image;
vk::DeviceMemory deviceMemory;
vk::ImageView imageView;
};
struct DepthBufferData : public ImageData
{
DepthBufferData( vk::PhysicalDevice const & physicalDevice, vk::Device const & device, vk::Format format, vk::Extent2D const & extent );
};
struct SurfaceData
{
SurfaceData( vk::Instance const & instance, std::string const & windowName, vk::Extent2D const & extent );
vk::Extent2D extent;
WindowData window;
vk::SurfaceKHR surface;
};
struct SwapChainData
{
SwapChainData( vk::PhysicalDevice const & physicalDevice,
vk::Device const & device,
vk::SurfaceKHR const & surface,
vk::Extent2D const & extent,
vk::ImageUsageFlags usage,
vk::SwapchainKHR const & oldSwapChain,
uint32_t graphicsFamilyIndex,
uint32_t presentFamilyIndex );
void clear( vk::Device const & device )
{
for ( auto & imageView : imageViews )
{
device.destroyImageView( imageView );
}
imageViews.clear();
images.clear();
device.destroySwapchainKHR( swapChain );
}
vk::Format colorFormat;
vk::SwapchainKHR swapChain;
std::vector<vk::Image> images;
std::vector<vk::ImageView> imageViews;
};
class CheckerboardImageGenerator
{
public:
CheckerboardImageGenerator( std::array<uint8_t, 3> const & rgb0 = { { 0, 0, 0 } }, std::array<uint8_t, 3> const & rgb1 = { { 255, 255, 255 } } );
void operator()( void * data, vk::Extent2D & extent ) const;
private:
std::array<uint8_t, 3> const & m_rgb0;
std::array<uint8_t, 3> const & m_rgb1;
};
class MonochromeImageGenerator
{
public:
MonochromeImageGenerator( std::array<unsigned char, 3> const & rgb );
void operator()( void * data, vk::Extent2D const & extent ) const;
private:
std::array<unsigned char, 3> const & m_rgb;
};
class PixelsImageGenerator
{
public:
PixelsImageGenerator( vk::Extent2D const & extent, size_t channels, unsigned char const * pixels );
void operator()( void * data, vk::Extent2D const & extent ) const;
private:
vk::Extent2D m_extent;
size_t m_channels;
unsigned char const * m_pixels;
};
struct TextureData
{
TextureData( vk::PhysicalDevice const & physicalDevice,
vk::Device const & device,
vk::Extent2D const & extent_ = { 256, 256 },
vk::ImageUsageFlags usageFlags = {},
vk::FormatFeatureFlags formatFeatureFlags = {},
bool anisotropyEnable = false,
bool forceStaging = false );
void clear( vk::Device const & device )
{
if ( stagingBufferData )
{
stagingBufferData->clear( device );
}
imageData->clear( device );
device.destroySampler( sampler );
}
template <typename ImageGenerator>
void setImage( vk::Device const & device, vk::CommandBuffer const & commandBuffer, ImageGenerator const & imageGenerator )
{
void * data = needsStaging
? device.mapMemory( stagingBufferData->deviceMemory, 0, device.getBufferMemoryRequirements( stagingBufferData->buffer ).size )
: device.mapMemory( imageData->deviceMemory, 0, device.getImageMemoryRequirements( imageData->image ).size );
imageGenerator( data, extent );
device.unmapMemory( needsStaging ? stagingBufferData->deviceMemory : imageData->deviceMemory );
if ( needsStaging )
{
// Since we're going to blit to the texture image, set its layout to eTransferDstOptimal
vk::su::setImageLayout( commandBuffer, imageData->image, imageData->format, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal );
vk::BufferImageCopy copyRegion( 0,
extent.width,
extent.height,
vk::ImageSubresourceLayers( vk::ImageAspectFlagBits::eColor, 0, 0, 1 ),
vk::Offset3D( 0, 0, 0 ),
vk::Extent3D( extent, 1 ) );
commandBuffer.copyBufferToImage( stagingBufferData->buffer, imageData->image, vk::ImageLayout::eTransferDstOptimal, copyRegion );
// Set the layout for the texture image from eTransferDstOptimal to SHADER_READ_ONLY
vk::su::setImageLayout(
commandBuffer, imageData->image, imageData->format, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal );
}
else
{
// If we can use the linear tiled image as a texture, just do it
vk::su::setImageLayout(
commandBuffer, imageData->image, imageData->format, vk::ImageLayout::ePreinitialized, vk::ImageLayout::eShaderReadOnlyOptimal );
}
}
vk::Format format;
vk::Extent2D extent;
bool needsStaging;
std::unique_ptr<BufferData> stagingBufferData;
std::unique_ptr<ImageData> imageData;
vk::Sampler sampler;
};
struct UUID
{
public:
UUID( uint8_t const data[VK_UUID_SIZE] );
uint8_t m_data[VK_UUID_SIZE];
};
template <typename TargetType, typename SourceType>
VULKAN_HPP_INLINE TargetType checked_cast( SourceType value )
{
static_assert( sizeof( TargetType ) <= sizeof( SourceType ), "No need to cast from smaller to larger type!" );
static_assert( std::numeric_limits<SourceType>::is_integer, "Only integer types supported!" );
static_assert( !std::numeric_limits<SourceType>::is_signed, "Only unsigned types supported!" );
static_assert( std::numeric_limits<TargetType>::is_integer, "Only integer types supported!" );
static_assert( !std::numeric_limits<TargetType>::is_signed, "Only unsigned types supported!" );
assert( value <= std::numeric_limits<TargetType>::max() );
return static_cast<TargetType>( value );
}
vk::DeviceMemory allocateDeviceMemory( vk::Device const & device,
vk::PhysicalDeviceMemoryProperties const & memoryProperties,
vk::MemoryRequirements const & memoryRequirements,
vk::MemoryPropertyFlags memoryPropertyFlags );
bool contains( std::vector<vk::ExtensionProperties> const & extensionProperties, std::string const & extensionName );
vk::DescriptorPool createDescriptorPool( vk::Device const & device, std::vector<vk::DescriptorPoolSize> const & poolSizes );
vk::DescriptorSetLayout createDescriptorSetLayout( vk::Device const & device,
std::vector<std::tuple<vk::DescriptorType, uint32_t, vk::ShaderStageFlags>> const & bindingData,
vk::DescriptorSetLayoutCreateFlags flags = {} );
vk::Device createDevice( vk::PhysicalDevice const & physicalDevice,
uint32_t queueFamilyIndex,
std::vector<std::string> const & extensions = {},
vk::PhysicalDeviceFeatures const * physicalDeviceFeatures = nullptr,
void const * pNext = nullptr );
std::vector<vk::Framebuffer> createFramebuffers( vk::Device const & device,
vk::RenderPass & renderPass,
std::vector<vk::ImageView> const & imageViews,
vk::ImageView const & depthImageView,
vk::Extent2D const & extent );
vk::Pipeline createGraphicsPipeline( vk::Device const & device,
vk::PipelineCache const & pipelineCache,
std::pair<vk::ShaderModule, vk::SpecializationInfo const *> const & vertexShaderData,
std::pair<vk::ShaderModule, vk::SpecializationInfo const *> const & fragmentShaderData,
uint32_t vertexStride,
std::vector<std::pair<vk::Format, uint32_t>> const & vertexInputAttributeFormatOffset,
vk::FrontFace frontFace,
bool depthBuffered,
vk::PipelineLayout const & pipelineLayout,
vk::RenderPass const & renderPass );
vk::Instance createInstance( std::string const & appName,
std::string const & engineName,
std::vector<std::string> const & layers = {},
std::vector<std::string> const & extensions = {},
uint32_t apiVersion = VK_API_VERSION_1_0 );
vk::RenderPass createRenderPass( vk::Device const & device,
vk::Format colorFormat,
vk::Format depthFormat,
vk::AttachmentLoadOp loadOp = vk::AttachmentLoadOp::eClear,
vk::ImageLayout colorFinalLayout = vk::ImageLayout::ePresentSrcKHR );
VKAPI_ATTR VkBool32 VKAPI_CALL debugUtilsMessengerCallback( VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageTypes,
VkDebugUtilsMessengerCallbackDataEXT const * pCallbackData,
void * /*pUserData*/ );
uint32_t findGraphicsQueueFamilyIndex( std::vector<vk::QueueFamilyProperties> const & queueFamilyProperties );
std::pair<uint32_t, uint32_t> findGraphicsAndPresentQueueFamilyIndex( vk::PhysicalDevice physicalDevice, vk::SurfaceKHR const & surface );
uint32_t findMemoryType( vk::PhysicalDeviceMemoryProperties const & memoryProperties, uint32_t typeBits, vk::MemoryPropertyFlags requirementsMask );
std::vector<char const *> gatherExtensions( std::vector<std::string> const & extensions
#if !defined( NDEBUG )
,
std::vector<vk::ExtensionProperties> const & extensionProperties
#endif
);
std::vector<char const *> gatherLayers( std::vector<std::string> const & layers
#if !defined( NDEBUG )
,
std::vector<vk::LayerProperties> const & layerProperties
#endif
);
std::vector<std::string> getDeviceExtensions();
std::vector<std::string> getInstanceExtensions();
vk::DebugUtilsMessengerCreateInfoEXT makeDebugUtilsMessengerCreateInfoEXT();
#if defined( NDEBUG )
vk::StructureChain<vk::InstanceCreateInfo>
#else
vk::StructureChain<vk::InstanceCreateInfo, vk::DebugUtilsMessengerCreateInfoEXT>
#endif
makeInstanceCreateInfoChain( vk::ApplicationInfo const & applicationInfo,
std::vector<char const *> const & layers,
std::vector<char const *> const & extensions );
vk::Format pickDepthFormat( vk::PhysicalDevice const & physicalDevice );
vk::PresentModeKHR pickPresentMode( std::vector<vk::PresentModeKHR> const & presentModes );
vk::SurfaceFormatKHR pickSurfaceFormat( std::vector<vk::SurfaceFormatKHR> const & formats );
void submitAndWait( vk::Device const & device, vk::Queue const & queue, vk::CommandBuffer const & commandBuffer );
void updateDescriptorSets( vk::Device const & device,
vk::DescriptorSet const & descriptorSet,
std::vector<std::tuple<vk::DescriptorType, vk::Buffer const &, vk::DeviceSize, vk::BufferView const &>> const & bufferData,
vk::su::TextureData const & textureData,
uint32_t bindingOffset = 0 );
void updateDescriptorSets( vk::Device const & device,
vk::DescriptorSet const & descriptorSet,
std::vector<std::tuple<vk::DescriptorType, vk::Buffer const &, vk::DeviceSize, vk::BufferView const &>> const & bufferData,
std::vector<vk::su::TextureData> const & textureData,
uint32_t bindingOffset = 0 );
} // namespace su
} // namespace vk
std::ostream & operator<<( std::ostream & os, vk::su::UUID const & uuid );

View File

@ -1,8 +0,0 @@
#include "compound_widget.h"
void compound_widget::set_content(const std::shared_ptr<widget>& content) {
child_ = content;
}
void compound_widget::on_paint(ImGuiIO& io) {
}

View File

@ -1,10 +0,0 @@
#pragma once
#include "widget.h"
class compound_widget : public widget {
public:
void set_content(const std::shared_ptr<widget>& content);
void on_paint(ImGuiIO& io) override;
private:
std::shared_ptr<widget> child_;
};

View File

@ -1 +0,0 @@
#include "leaf_widget.h"

View File

@ -1,7 +0,0 @@
#pragma once
#include "widget.h"
class leaf_widget : public widget {
public:
};

View File

@ -1 +0,0 @@
#include "panel_widget.h"

View File

@ -1,7 +0,0 @@
#pragma once
#include "widget.h"
class panel_widget : public widget {
public:
};

View File

@ -1,18 +0,0 @@
#pragma once
#include "extern.h"
#include "imgui.h"
#include "imgui_internal.h"
extern "C" {
void HideTabBar();
}
namespace ImGui {
inline void HideTabBar()
{
ImGuiWindowClass window_class;
window_class.DockNodeFlagsOverrideSet = ImGuiDockNodeFlags_NoWindowMenuButton;
// window_class.DockNodeFlagsOverrideSet = ImGuiDockNodeFlags_NoTabBar;
SetNextWindowClass(&window_class);
}
}

View File

@ -1,11 +0,0 @@
#include "widget.h"
#include <random>
ImGuiID widget::generate_widget_id() {
// random number generator
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<ImGuiID> dis(0, std::numeric_limits<ImGuiID>::max());
return dis(gen);
}

View File

@ -1,16 +0,0 @@
#pragma once
#include "imgui.h"
class geometry;
class CORE_API widget : public std::enable_shared_from_this<widget> {
public:
virtual ~widget() = default;
virtual void tick() {}
virtual void on_paint(ImGuiIO& io) = 0;
virtual void on_arrange_children(const geometry& allotted_geometry) {}
[[nodiscard]] virtual ImVec2 compute_desired_size() const { return {0, 0}; }
static ImGuiID generate_widget_id();
};

1
third_party/glfw vendored

@ -1 +0,0 @@
Subproject commit 64b4f0f30c60f11aee715214a9d8faef4372d946

View File

@ -1,40 +0,0 @@
project(imgui)
set(CMAKE_CXX_STANDARD 23)
add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>")
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
add_library(${PROJECT_NAME} STATIC
imgui/imgui.cpp
imgui/imgui.h
imgui/imgui_draw.cpp
imgui/imgui_internal.h
imgui/imconfig.h
imgui/imgui_widgets.cpp
imgui/imstb_rectpack.h
imgui/imstb_textedit.h
imgui/imstb_truetype.h
imgui/imgui_tables.cpp
imgui-knobs/imgui-knobs.h
imgui-knobs/imgui-knobs.cpp
)
find_package(Vulkan REQUIRED)
target_sources(${PROJECT_NAME} PRIVATE
imgui/backends/imgui_impl_glfw.cpp
imgui/backends/imgui_impl_glfw.h
imgui/backends/imgui_impl_vulkan.cpp
imgui/backends/imgui_impl_vulkan.h
)
target_link_libraries(${PROJECT_NAME} PUBLIC glfw ${Vulkan_LIBRARIES})
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/imgui)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/imgui/backends)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/imgui-knobs)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} glfw ${Vulkan_INCLUDE_DIRS})
target_precompile_headers(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/pch.h)
add_definitions(-DIMGUI_IMPL_OPENGL_LOADER_CUSTOM)
add_compile_definitions(-DIMGUI_DEFINE_MATH_OPERATORS)

@ -1 +0,0 @@
Subproject commit 8048b52498a9bf2a9f87b080d43b0bfd7a5d51d8

View File

@ -1,303 +0,0 @@
#include "imgui-knobs.h"
#include <cmath>
#include <cstdlib>
#include <imgui.h>
#include <imgui_internal.h>
#define IMGUIKNOBS_PI 3.14159265358979323846f
namespace ImGuiKnobs {
namespace detail {
void draw_arc1(ImVec2 center, float radius, float start_angle, float end_angle, float thickness, ImColor color, int num_segments) {
ImVec2 start = {
center[0] + cosf(start_angle) * radius,
center[1] + sinf(start_angle) * radius,
};
ImVec2 end = {
center[0] + cosf(end_angle) * radius,
center[1] + sinf(end_angle) * radius,
};
// Calculate bezier arc points
auto ax = start[0] - center[0];
auto ay = start[1] - center[1];
auto bx = end[0] - center[0];
auto by = end[1] - center[1];
auto q1 = ax * ax + ay * ay;
auto q2 = q1 + ax * bx + ay * by;
auto k2 = (4.0f / 3.0f) * (sqrtf((2.0f * q1 * q2)) - q2) / (ax * by - ay * bx);
auto arc1 = ImVec2{center[0] + ax - k2 * ay, center[1] + ay + k2 * ax};
auto arc2 = ImVec2{center[0] + bx + k2 * by, center[1] + by - k2 * bx};
auto *draw_list = ImGui::GetWindowDrawList();
#if IMGUI_VERSION_NUM <= 18000
draw_list->AddBezierCurve(start, arc1, arc2, end, color, thickness, num_segments);
#else
draw_list->AddBezierCubic(start, arc1, arc2, end, color, thickness, num_segments);
#endif
}
void draw_arc(ImVec2 center, float radius, float start_angle, float end_angle, float thickness, ImColor color, int num_segments, int bezier_count) {
// Overlap and angle of ends of bezier curves needs work, only looks good when not transperant
auto overlap = thickness * radius * 0.00001f * IMGUIKNOBS_PI;
auto delta = end_angle - start_angle;
auto bez_step = 1.0f / bezier_count;
auto mid_angle = start_angle + overlap;
for (auto i = 0; i < bezier_count - 1; i++) {
auto mid_angle2 = delta * bez_step + mid_angle;
draw_arc1(center, radius, mid_angle - overlap, mid_angle2 + overlap, thickness, color, num_segments);
mid_angle = mid_angle2;
}
draw_arc1(center, radius, mid_angle - overlap, end_angle, thickness, color, num_segments);
}
template<typename DataType>
struct knob {
float radius;
bool value_changed;
ImVec2 center;
bool is_active;
bool is_hovered;
float angle_min;
float angle_max;
float t;
float angle;
float angle_cos;
float angle_sin;
knob(const char *_label, ImGuiDataType data_type, DataType *p_value, DataType v_min, DataType v_max, float speed, float _radius, const char *format, ImGuiKnobFlags flags) {
radius = _radius;
t = ((float) *p_value - v_min) / (v_max - v_min);
auto screen_pos = ImGui::GetCursorScreenPos();
// Handle dragging
ImGui::InvisibleButton(_label, {radius * 2.0f, radius * 2.0f});
auto gid = ImGui::GetID(_label);
ImGuiSliderFlags drag_flags = 0;
if (!(flags & ImGuiKnobFlags_DragHorizontal)) {
drag_flags |= ImGuiSliderFlags_Vertical;
}
value_changed = ImGui::DragBehavior(gid, data_type, p_value, speed, &v_min, &v_max, format, drag_flags);
angle_min = IMGUIKNOBS_PI * 0.75f;
angle_max = IMGUIKNOBS_PI * 2.25f;
center = {screen_pos[0] + radius, screen_pos[1] + radius};
is_active = ImGui::IsItemActive();
is_hovered = ImGui::IsItemHovered();
angle = angle_min + (angle_max - angle_min) * t;
angle_cos = cosf(angle);
angle_sin = sinf(angle);
}
void draw_dot(float size, float radius, float angle, color_set color, bool filled, int segments) {
auto dot_size = size * this->radius;
auto dot_radius = radius * this->radius;
ImGui::GetWindowDrawList()->AddCircleFilled(
{center[0] + cosf(angle) * dot_radius, center[1] + sinf(angle) * dot_radius},
dot_size,
is_active ? color.active : (is_hovered ? color.hovered : color.base),
segments);
}
void draw_tick(float start, float end, float width, float angle, color_set color) {
auto tick_start = start * radius;
auto tick_end = end * radius;
auto angle_cos = cosf(angle);
auto angle_sin = sinf(angle);
ImGui::GetWindowDrawList()->AddLine(
{center[0] + angle_cos * tick_end, center[1] + angle_sin * tick_end},
{center[0] + angle_cos * tick_start, center[1] + angle_sin * tick_start},
is_active ? color.active : (is_hovered ? color.hovered : color.base),
width * radius);
}
void draw_circle(float size, color_set color, bool filled, int segments) {
auto circle_radius = size * radius;
ImGui::GetWindowDrawList()->AddCircleFilled(
center,
circle_radius,
is_active ? color.active : (is_hovered ? color.hovered : color.base));
}
void draw_arc(float radius, float size, float start_angle, float end_angle, color_set color, int segments, int bezier_count) {
auto track_radius = radius * this->radius;
auto track_size = size * this->radius * 0.5f + 0.0001f;
detail::draw_arc(
center,
track_radius,
start_angle,
end_angle,
track_size,
is_active ? color.active : (is_hovered ? color.hovered : color.base),
segments,
bezier_count);
}
};
template<typename DataType>
knob<DataType> knob_with_drag(const char *label, ImGuiDataType data_type, DataType *p_value, DataType v_min, DataType v_max, float _speed, const char *format, float size, ImGuiKnobFlags flags) {
auto speed = _speed == 0 ? (v_max - v_min) / 250.f : _speed;
ImGui::PushID(label);
auto width = size == 0 ? ImGui::GetTextLineHeight() * 4.0f : size * ImGui::GetIO().FontGlobalScale;
ImGui::PushItemWidth(width);
ImGui::BeginGroup();
// There's an issue with `SameLine` and Groups, see https://github.com/ocornut/imgui/issues/4190.
// This is probably not the best solution, but seems to work for now
ImGui::GetCurrentWindow()->DC.CurrLineTextBaseOffset = 0;
// Draw title
if (!(flags & ImGuiKnobFlags_NoTitle)) {
auto title_size = ImGui::CalcTextSize(label, NULL, false, width);
// Center title
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (width - title_size[0]) * 0.5f);
ImGui::Text("%s", label);
}
// Draw knob
knob<DataType> k(label, data_type, p_value, v_min, v_max, speed, width * 0.5f, format, flags);
// Draw tooltip
if (flags & ImGuiKnobFlags_ValueTooltip && (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) || ImGui::IsItemActive())) {
ImGui::BeginTooltip();
ImGui::Text(format, *p_value);
ImGui::EndTooltip();
}
// Draw input
if (!(flags & ImGuiKnobFlags_NoInput)) {
ImGuiSliderFlags drag_flags = 0;
if (!(flags & ImGuiKnobFlags_DragHorizontal)) {
drag_flags |= ImGuiSliderFlags_Vertical;
}
auto changed = ImGui::DragScalar("###knob_drag", data_type, p_value, speed, &v_min, &v_max, format, drag_flags);
if (changed) {
k.value_changed = true;
}
}
ImGui::EndGroup();
ImGui::PopItemWidth();
ImGui::PopID();
return k;
}
color_set GetPrimaryColorSet() {
auto *colors = ImGui::GetStyle().Colors;
return {colors[ImGuiCol_ButtonActive], colors[ImGuiCol_ButtonHovered], colors[ImGuiCol_ButtonHovered]};
}
color_set GetSecondaryColorSet() {
auto *colors = ImGui::GetStyle().Colors;
auto active = ImVec4(
colors[ImGuiCol_ButtonActive].x * 0.5f,
colors[ImGuiCol_ButtonActive].y * 0.5f,
colors[ImGuiCol_ButtonActive].z * 0.5f,
colors[ImGuiCol_ButtonActive].w);
auto hovered = ImVec4(
colors[ImGuiCol_ButtonHovered].x * 0.5f,
colors[ImGuiCol_ButtonHovered].y * 0.5f,
colors[ImGuiCol_ButtonHovered].z * 0.5f,
colors[ImGuiCol_ButtonHovered].w);
return {active, hovered, hovered};
}
color_set GetTrackColorSet() {
auto *colors = ImGui::GetStyle().Colors;
return {colors[ImGuiCol_FrameBg], colors[ImGuiCol_FrameBg], colors[ImGuiCol_FrameBg]};
}
}// namespace detail
template<typename DataType>
bool BaseKnob(const char *label, ImGuiDataType data_type, DataType *p_value, DataType v_min, DataType v_max, float speed, const char *format, ImGuiKnobVariant variant, float size, ImGuiKnobFlags flags, int steps = 10) {
auto knob = detail::knob_with_drag(label, data_type, p_value, v_min, v_max, speed, format, size, flags);
switch (variant) {
case ImGuiKnobVariant_Tick: {
knob.draw_circle(0.85f, detail::GetSecondaryColorSet(), true, 32);
knob.draw_tick(0.5f, 0.85f, 0.08f, knob.angle, detail::GetPrimaryColorSet());
break;
}
case ImGuiKnobVariant_Dot: {
knob.draw_circle(0.85f, detail::GetSecondaryColorSet(), true, 32);
knob.draw_dot(0.12f, 0.6f, knob.angle, detail::GetPrimaryColorSet(), true, 12);
break;
}
case ImGuiKnobVariant_Wiper: {
knob.draw_circle(0.7f, detail::GetSecondaryColorSet(), true, 32);
knob.draw_arc(0.8f, 0.41f, knob.angle_min, knob.angle_max, detail::GetTrackColorSet(), 16, 2);
if (knob.t > 0.01f) {
knob.draw_arc(0.8f, 0.43f, knob.angle_min, knob.angle, detail::GetPrimaryColorSet(), 16, 2);
}
break;
}
case ImGuiKnobVariant_WiperOnly: {
knob.draw_arc(0.8f, 0.41f, knob.angle_min, knob.angle_max, detail::GetTrackColorSet(), 32, 2);
if (knob.t > 0.01) {
knob.draw_arc(0.8f, 0.43f, knob.angle_min, knob.angle, detail::GetPrimaryColorSet(), 16, 2);
}
break;
}
case ImGuiKnobVariant_WiperDot: {
knob.draw_circle(0.6f, detail::GetSecondaryColorSet(), true, 32);
knob.draw_arc(0.85f, 0.41f, knob.angle_min, knob.angle_max, detail::GetTrackColorSet(), 16, 2);
knob.draw_dot(0.1f, 0.85f, knob.angle, detail::GetPrimaryColorSet(), true, 12);
break;
}
case ImGuiKnobVariant_Stepped: {
for (auto n = 0.f; n < steps; n++) {
auto a = n / (steps - 1);
auto angle = knob.angle_min + (knob.angle_max - knob.angle_min) * a;
knob.draw_tick(0.7f, 0.9f, 0.04f, angle, detail::GetPrimaryColorSet());
}
knob.draw_circle(0.6f, detail::GetSecondaryColorSet(), true, 32);
knob.draw_dot(0.12f, 0.4f, knob.angle, detail::GetPrimaryColorSet(), true, 12);
break;
}
case ImGuiKnobVariant_Space: {
knob.draw_circle(0.3f - knob.t * 0.1f, detail::GetSecondaryColorSet(), true, 16);
if (knob.t > 0.01f) {
knob.draw_arc(0.4f, 0.15f, knob.angle_min - 1.0f, knob.angle - 1.0f, detail::GetPrimaryColorSet(), 16, 2);
knob.draw_arc(0.6f, 0.15f, knob.angle_min + 1.0f, knob.angle + 1.0f, detail::GetPrimaryColorSet(), 16, 2);
knob.draw_arc(0.8f, 0.15f, knob.angle_min + 3.0f, knob.angle + 3.0f, detail::GetPrimaryColorSet(), 16, 2);
}
break;
}
}
return knob.value_changed;
}
bool Knob(const char *label, float *p_value, float v_min, float v_max, float speed, const char *format, ImGuiKnobVariant variant, float size, ImGuiKnobFlags flags, int steps) {
const char *_format = format == NULL ? "%.3f" : format;
return BaseKnob(label, ImGuiDataType_Float, p_value, v_min, v_max, speed, _format, variant, size, flags, steps);
}
bool KnobInt(const char *label, int *p_value, int v_min, int v_max, float speed, const char *format, ImGuiKnobVariant variant, float size, ImGuiKnobFlags flags, int steps) {
const char *_format = format == NULL ? "%i" : format;
return BaseKnob(label, ImGuiDataType_S32, p_value, v_min, v_max, speed, _format, variant, size, flags, steps);
}
}// namespace ImGuiKnobs

View File

@ -1,45 +0,0 @@
#pragma once
#include <cstdlib>
#include <imgui.h>
typedef int ImGuiKnobFlags;
enum ImGuiKnobFlags_ {
ImGuiKnobFlags_NoTitle = 1 << 0,
ImGuiKnobFlags_NoInput = 1 << 1,
ImGuiKnobFlags_ValueTooltip = 1 << 2,
ImGuiKnobFlags_DragHorizontal = 1 << 3,
};
typedef int ImGuiKnobVariant;
enum ImGuiKnobVariant_ {
ImGuiKnobVariant_Tick = 1 << 0,
ImGuiKnobVariant_Dot = 1 << 1,
ImGuiKnobVariant_Wiper = 1 << 2,
ImGuiKnobVariant_WiperOnly = 1 << 3,
ImGuiKnobVariant_WiperDot = 1 << 4,
ImGuiKnobVariant_Stepped = 1 << 5,
ImGuiKnobVariant_Space = 1 << 6,
};
namespace ImGuiKnobs {
struct color_set {
ImColor base;
ImColor hovered;
ImColor active;
color_set(ImColor base, ImColor hovered, ImColor active) : base(base), hovered(hovered), active(active) {}
color_set(ImColor color) {
base = color;
hovered = color;
active = color;
}
};
bool Knob(const char *label, float *p_value, float v_min, float v_max, float speed = 0, const char *format = NULL, ImGuiKnobVariant variant = ImGuiKnobVariant_Tick, float size = 0, ImGuiKnobFlags flags = 0, int steps = 10);
bool KnobInt(const char *label, int *p_value, int v_min, int v_max, float speed = 0, const char *format = NULL, ImGuiKnobVariant variant = ImGuiKnobVariant_Tick, float size = 0, ImGuiKnobFlags flags = 0, int steps = 10);
}// namespace ImGuiKnobs

View File