Skip to content

Commit

Permalink
�[WIP] Work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
IAmNotHanni committed Aug 1, 2024
1 parent 5933fb9 commit 315473b
Show file tree
Hide file tree
Showing 83 changed files with 619 additions and 1,835 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ if(INEXOR_BUILD_DOC)
endif()

if(INEXOR_BUILD_EXAMPLE)
add_subdirectory(example)
add_subdirectory(example-app/src)
endif()

if(INEXOR_BUILD_TESTS)
Expand Down
Empty file.
47 changes: 47 additions & 0 deletions example-app/include/example_app.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#pragma once

#include "../include/example_app_base.hpp"

#include "inexor/vulkan-renderer/rendering/imgui/imgui.hpp"
#include "inexor/vulkan-renderer/rendering/octree/octree_renderer.hpp"

#include <spdlog/spdlog.h>

namespace inexor::example_app {

/// An example application using Inexor vulkan-renderer
class ExampleApp : public ExampleAppBase {
private:
std::unique_ptr<ImGuiRenderer> m_imgui_renderer;
std::unique_ptr<OctreeRenderer> m_octree_renderer;

public:
ExampleApp(int argc, char **argv);
~ExampleApp();

ExampleApp(const ExampleApp &) = delete;
// TODO: Implement me!
ExampleApp(ExampleApp &&) noexcept;

ExampleApp &operator=(const ExampleApp &) = delete;
// TODO: Implement me!
ExampleApp &operator=(ExampleApp &&) noexcept;

void initialize() override;

void load_toml_configuration_file(const std::string &file_name);

void setup_render_graph() override;

void cursor_position_callback(GLFWwindow *window, double x_pos, double y_pos) override;

void keyboard_button_callback(GLFWwindow *window, int key, int scancode, int action, int mods) override;

void mouse_button_callback(GLFWwindow *window, int button, int action, int mods) override;

void mouse_scroll_callback(GLFWwindow *window, double x_offset, double y_offset) override;

void update_imgui() override;
};

} // namespace inexor::example_app
102 changes: 102 additions & 0 deletions example-app/include/example_app_base.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#pragma once

#include "inexor/vulkan-renderer/input/keyboard_mouse_data.hpp"
#include "inexor/vulkan-renderer/rendering/render-graph/render_graph.hpp"
#include "inexor/vulkan-renderer/tools/cla_parser.hpp"
#include "inexor/vulkan-renderer/wrapper/device.hpp"
#include "inexor/vulkan-renderer/wrapper/instance.hpp"
#include "inexor/vulkan-renderer/wrapper/surface.hpp"
#include "inexor/vulkan-renderer/wrapper/swapchain.hpp"
#include "inexor/vulkan-renderer/wrapper/window.hpp"

#include <memory>
#include <string>

namespace inexor::example_app {

// Using declarations
using inexor::vulkan_renderer::input::KeyboardMouseInputData;
using inexor::vulkan_renderer::render_graph::RenderGraph;
using inexor::vulkan_renderer::tools::CommandLineArgumentParser;
using inexor::vulkan_renderer::wrapper::Device;
using inexor::vulkan_renderer::wrapper::Instance;
using inexor::vulkan_renderer::wrapper::Surface;
using inexor::vulkan_renderer::wrapper::Swapchain;
using inexor::vulkan_renderer::wrapper::Window;

/// The command line arguments will be parsed into these options
struct CommandLineOptions {
bool stop_on_validation_error{false};
bool vsync_enabled{false};
};

/// A base class for example apps which use Inexor vulkan-renderer
class ExampleAppBase {
private:
const std::string m_wnd_title = "inexor-vulkan-renderer-example";
std::uint32_t m_wnd_width{1280};
std::uint32_t m_wnd_height{720};
Window::Mode m_wnd_mode{Window::Mode::WINDOWED};
bool m_wnd_resized{false};

std::unique_ptr<Window> m_window;
std::unique_ptr<Instance> m_instance;
std::unique_ptr<Surface> m_surface;
std::unique_ptr<Device> m_device;
std::shared_ptr<Swapchain> m_swapchain;
std::unique_ptr<KeyboardMouseInputData> m_input_data;

void initialize_spdlog();

void recreate_swapchain();

/// Because GLFW is a C-style API, we can't use a pointer to non-static class methods as window or input callback.
/// A good explanation can be found on Stack Overflow:
/// https://stackoverflow.com/questions/7676971/pointing-to-a-function-that-is-a-class-member-glfw-setkeycallback
/// In order to fix this, we can pass a lambda to glfwSetKeyCallback, which calls our callbacks internally. There is
/// another problem: Inside of the lambda, we need to call the member function. In order to do so, we need to have
/// access to the this-pointer. Unfortunately, the this-pointer can't be captured in the lambda capture like
/// [this](){}, because the glfw would not accept the lambda then. To fix this problem, we store the this pointer
/// using glfwSetWindowUserPointer. Inside of these lambdas, we then cast the pointer to Application* again,
/// allowing us to finally use the callbacks.
void setup_window_and_input_callbacks();

protected:
CommandLineOptions m_options;

VKAPI_ATTR VkBool32 VKAPI_CALL
validation_layer_debug_messenger_callback(VkDebugUtilsMessageSeverityFlagBitsEXT,
VkDebugUtilsMessageTypeFlagsEXT,
const VkDebugUtilsMessengerCallbackDataEXT *,
void *);

std::shared_ptr<RenderGraph> m_rendergraph;

public:
ExampleAppBase(int argc, char **argv);
virtual ~ExampleAppBase();

ExampleAppBase(const ExampleAppBase &) = delete;
// TODO: Implement me!
ExampleAppBase(ExampleAppBase &&) noexcept;

ExampleAppBase &operator=(const ExampleAppBase &) = delete;
// TODO: Implement me!
ExampleAppBase &operator=(ExampleAppBase &&) noexcept;

virtual void evaluate_command_line_arguments(const CommandLineArgumentParser &parser) = 0;
virtual void cursor_position_callback(GLFWwindow *, double, double) = 0;
virtual void keyboard_button_callback(GLFWwindow *, int, int, int, int) = 0;
virtual void mouse_button_callback(GLFWwindow *, int, int, int) = 0;
virtual void mouse_scroll_callback(GLFWwindow *, double, double) = 0;
virtual void initialize() = 0;
virtual void process_mouse_input() = 0;
virtual void process_keyboard_input() = 0;
virtual void render_frame() = 0;
virtual void setup_device() = 0;
virtual void setup_render_graph() = 0;
virtual void shutdown() = 0;
virtual void update_imgui() = 0;
};

} // namespace inexor::example_app
20 changes: 19 additions & 1 deletion example/CMakeLists.txt → example-app/src/CMakeLists.txt
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,4 +1,22 @@
add_executable(inexor-vulkan-renderer-example main.cpp)
set(INEXOR_EXAMPLE_APP_SOURCE_FILES
example_app_base.cpp
example_app.cpp)

foreach(FILE ${INEXOR_EXAMPLE_APP_SOURCE_FILES})
get_filename_component(PARENT_DIR "${FILE}" PATH)

string(REPLACE "/" "\\" GROUP "${PARENT_DIR}")

if("${FILE}" MATCHES ".*\\.cpp")
set(GROUP "Source Files\\${GROUP}")
elseif("${FILE}" MATCHES ".*\\.hpp")
set(GROUP "Header Files\\${GROUP}")
endif()

source_group("${GROUP}" FILES "${FILE}")
endforeach()

add_executable(inexor-vulkan-renderer-example ${INEXOR_EXAMPLE_APP_SOURCE_FILES})

target_compile_features(inexor-vulkan-renderer-example PRIVATE cxx_std_20)
target_link_libraries(inexor-vulkan-renderer-example PRIVATE inexor-vulkan-renderer)
Expand Down
Empty file.
66 changes: 66 additions & 0 deletions example-app/src/example_app.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include "../include/example_app.hpp"

#include <toml.hpp>

#include <memory>

namespace inexor::example_app {

ExampleApp::ExampleApp(int argc, char **argv) : ExampleAppBase(argc, argv) {}

ExampleApp::~ExampleApp() {}

void ExampleApp::initialize() {
//
}

void ExampleApp::setup_render_graph() {
spdlog::trace("Setting up rendergraph");
m_octree_renderer = std::make_unique<OctreeRenderer>(m_rendergraph);
m_imgui_renderer = std::make_unique<ImGuiRenderer>(m_rendergraph);
}

void ExampleApp::update_imgui() {
ImGuiIO &io = ImGui::GetIO();
io.DeltaTime = m_time_passed + 0.00001f;
auto cursor_pos = m_input_data->get_cursor_pos();
io.MousePos = ImVec2(static_cast<float>(cursor_pos[0]), static_cast<float>(cursor_pos[1]));
io.MouseDown[0] = m_input_data->is_mouse_button_pressed(GLFW_MOUSE_BUTTON_LEFT);
io.MouseDown[1] = m_input_data->is_mouse_button_pressed(GLFW_MOUSE_BUTTON_RIGHT);
io.DisplaySize =
ImVec2(static_cast<float>(m_swapchain->extent().width), static_cast<float>(m_swapchain->extent().height));

ImGui::NewFrame();
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0);
ImGui::SetNextWindowPos(ImVec2(10, 10));
ImGui::SetNextWindowSize(ImVec2(330, 0));
ImGui::Begin("Inexor Vulkan-renderer", nullptr,
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove);
ImGui::Text("%s", m_device->gpu_name().c_str());
ImGui::Text("Engine version %d.%d.%d (Git sha %s)", ENGINE_VERSION[0], ENGINE_VERSION[1], ENGINE_VERSION[2],
BUILD_GIT);
ImGui::Text("Vulkan API %d.%d.%d", VK_API_VERSION_MAJOR(wrapper::Instance::REQUIRED_VK_API_VERSION),
VK_API_VERSION_MINOR(wrapper::Instance::REQUIRED_VK_API_VERSION),
VK_API_VERSION_PATCH(wrapper::Instance::REQUIRED_VK_API_VERSION));
const auto &cam_pos = m_camera->position();
ImGui::Text("Camera position (%.2f, %.2f, %.2f)", cam_pos.x, cam_pos.y, cam_pos.z);
const auto &cam_rot = m_camera->rotation();
ImGui::Text("Camera rotation: (%.2f, %.2f, %.2f)", cam_rot.x, cam_rot.y, cam_rot.z);
const auto &cam_front = m_camera->front();
ImGui::Text("Camera vector front: (%.2f, %.2f, %.2f)", cam_front.x, cam_front.y, cam_front.z);
const auto &cam_right = m_camera->right();
ImGui::Text("Camera vector right: (%.2f, %.2f, %.2f)", cam_right.x, cam_right.y, cam_right.z);
const auto &cam_up = m_camera->up();
ImGui::Text("Camera vector up (%.2f, %.2f, %.2f)", cam_up.x, cam_up.y, cam_up.z);
ImGui::Text("Yaw: %.2f pitch: %.2f roll: %.2f", m_camera->yaw(), m_camera->pitch(), m_camera->roll());
const auto cam_fov = m_camera->fov();
ImGui::Text("Field of view: %d", static_cast<std::uint32_t>(cam_fov));
ImGui::PushItemWidth(150.0f);
ImGui::PopItemWidth();
ImGui::PopStyleVar();
ImGui::End();
ImGui::EndFrame();
ImGui::Render();
}

} // namespace inexor::example_app
112 changes: 112 additions & 0 deletions example-app/src/example_app_base.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#include "../include/example_app_base.hpp"

#include <spdlog/async.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/spdlog.h>

namespace inexor::example_app {

ExampleAppBase::ExampleAppBase(int argc, char **argv) {
// Setup spdlog logging library
initialize_spdlog();

// Parse and evaluate command line arguments
CommandLineArgumentParser cla_parser;
cla_parser.parse_args(argc, argv);
evaluate_command_line_arguments(cla_parser);

spdlog::trace("Application version: {}.{}.{}", APP_VERSION[0], APP_VERSION[1], APP_VERSION[2]);
spdlog::trace("Engine version: {}.{}.{}", ENGINE_VERSION[0], ENGINE_VERSION[1], ENGINE_VERSION[2]);

// NOTE: We must create the window before the VkInstance, otherwise glfwGetRequiredInstanceExtensions fails!
m_window = std::make_unique<Window>(m_wnd_title, m_wnd_width, m_wnd_height, true, true, m_wnd_mode);
setup_window_and_input_callbacks();

m_instance = std::make_unique<Instance>(
APP_NAME, ENGINE_NAME, VK_MAKE_API_VERSION(0, APP_VERSION[0], APP_VERSION[1], APP_VERSION[2]),
VK_MAKE_API_VERSION(0, ENGINE_VERSION[0], ENGINE_VERSION[1], ENGINE_VERSION[2]),
validation_layer_debug_messenger_callback);

m_surface = std::make_unique<Surface>(m_instance->instance(), m_window->window());
m_input_data = std::make_unique<KeyboardMouseInputData>();

m_device = std::make_unique<Device>(*m_instance, m_surface->surface(), physical_device, required_extensions,
required_features, optional_extensions, optional_features);

m_swapchain = std::make_shared<Swapchain>(*m_device, "Default Swapchain", m_surface->surface(), *m_window,
m_options.vsync_enabled);
}

ExampleAppBase::~ExampleAppBase() {
spdlog::trace("Shutting down vulkan-renderer-example");
}

void ExampleAppBase::initialize_spdlog() {
spdlog::init_thread_pool(8192, 2);
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("vulkan-renderer-example.log", true);
auto logger = std::make_shared<spdlog::async_logger>("vulkan-renderer-example",
spdlog::sinks_init_list{console_sink, file_sink},
spdlog::thread_pool(), spdlog::async_overflow_policy::block);
logger->set_level(spdlog::level::trace);
logger->set_pattern("%Y-%m-%d %T.%f %^%l%$ %5t [%-10n] %v");
logger->flush_on(spdlog::level::trace);
spdlog::set_default_logger(logger);
spdlog::trace("Inexor vulkan-renderer-example, BUILD " + std::string(__DATE__) + ", " + __TIME__);
}

void ExampleAppBase::setup_window_and_input_callbacks() {
m_window->set_user_ptr(this);

m_window->set_resize_callback([](GLFWwindow *window, int width, int height) {
auto *app = static_cast<ExampleAppBase *>(glfwGetWindowUserPointer(window));
app->m_wnd_resized = true;
});

m_window->set_keyboard_button_callback([](GLFWwindow *window, int key, int scancode, int action, int mods) {
auto *app = static_cast<ExampleAppBase *>(glfwGetWindowUserPointer(window));
app->keyboard_button_callback(window, key, scancode, action, mods);
});

m_window->set_cursor_position_callback([](GLFWwindow *window, double xpos, double ypos) {
auto *app = static_cast<ExampleAppBase *>(glfwGetWindowUserPointer(window));
app->cursor_position_callback(window, xpos, ypos);
});

m_window->set_mouse_button_callback([](GLFWwindow *window, int button, int action, int mods) {
auto *app = static_cast<ExampleAppBase *>(glfwGetWindowUserPointer(window));
app->mouse_button_callback(window, button, action, mods);
});

m_window->set_mouse_scroll_callback([](GLFWwindow *window, double xoffset, double yoffset) {
auto *app = static_cast<ExampleAppBase *>(glfwGetWindowUserPointer(window));
app->mouse_scroll_callback(window, xoffset, yoffset);
});
}

void ExampleAppBase::recreate_swapchain() {
// TODO: Implement!
}

VkBool32 VKAPI_CALL
ExampleAppBase::validation_layer_debug_messenger_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
VkDebugUtilsMessageTypeFlagsEXT type,
const VkDebugUtilsMessengerCallbackDataEXT *data,
void *user_data) {
if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) {
spdlog::trace("{}", data->pMessage);
} else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) {
spdlog::info("{}", data->pMessage);
} else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
spdlog::warn("{}", data->pMessage);
} else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
spdlog::critical("{}", data->pMessage);
}
if (m_options.stop_on_validation_error) {
throw std::runtime_error("[ExampleApp::validation_layer_debug_messenger_callback] Validation error, stopped.");
}
return false;
}

} // namespace inexor::example_app
18 changes: 0 additions & 18 deletions example/main.cpp

This file was deleted.

Loading

0 comments on commit 315473b

Please sign in to comment.