Compare commits
2 Commits
1229f5c017
...
a6b98e0613
| Author | SHA1 | Date | |
|---|---|---|---|
| a6b98e0613 | |||
| b16507c61d |
@@ -18,12 +18,14 @@ class DebugUI {
|
|||||||
|
|
||||||
void showPanelRegistry(bool show = true);
|
void showPanelRegistry(bool show = true);
|
||||||
void showFrameStats(bool show = true);
|
void showFrameStats(bool show = true);
|
||||||
|
void showConsole(bool show = true);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PanelRegistry& registry;
|
PanelRegistry& registry;
|
||||||
|
|
||||||
PanelHandle panelRegistryHandle;
|
PanelHandle panelRegistryHandle;
|
||||||
PanelHandle frameStatsHandle;
|
PanelHandle frameStatsHandle;
|
||||||
|
PanelHandle consoleHandle;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sophia
|
} // namespace sophia
|
||||||
|
|||||||
+19
-89
@@ -10,10 +10,13 @@
|
|||||||
|
|
||||||
#define GLM_FORCE_RADIANS
|
#define GLM_FORCE_RADIANS
|
||||||
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
#include "buffer.hpp"
|
#include "buffer.hpp"
|
||||||
#include "device.hpp"
|
#include "device.hpp"
|
||||||
|
#include "imgui_renderer.hpp"
|
||||||
#include "mesh.hpp"
|
#include "mesh.hpp"
|
||||||
#include "pipelines/graphics_pipeline.hpp"
|
#include "pipelines/graphics_pipeline.hpp"
|
||||||
#include "render_context.hpp"
|
#include "render_context.hpp"
|
||||||
@@ -49,72 +52,10 @@ class Application::Impl {
|
|||||||
device{&window},
|
device{&window},
|
||||||
renderContext{window, device} {}
|
renderContext{window, device} {}
|
||||||
|
|
||||||
/*void run(const std::string& vertShaderPath,
|
|
||||||
const std::string& fragShaderPath) {
|
|
||||||
log::info("Running Render Triangle Test...");
|
|
||||||
|
|
||||||
RenderContext renderContext{window, device};
|
|
||||||
|
|
||||||
auto vertexShader = Shader::Builder()
|
|
||||||
.fromGLSL(vertShaderPath)
|
|
||||||
.setStage(ShaderStage::VERTEX)
|
|
||||||
.build();
|
|
||||||
auto fragmentShader = Shader::Builder()
|
|
||||||
.fromGLSL(fragShaderPath)
|
|
||||||
.setStage(ShaderStage::FRAGMENT)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
vk::PushConstantRange pushConstantRange{};
|
|
||||||
pushConstantRange.stageFlags =
|
|
||||||
vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment;
|
|
||||||
pushConstantRange.offset = 0;
|
|
||||||
pushConstantRange.size = sizeof(PushConstants);
|
|
||||||
|
|
||||||
vk::PipelineLayoutCreateInfo pipelineLayoutInfo{};
|
|
||||||
pipelineLayoutInfo.pushConstantRangeCount = 1;
|
|
||||||
pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange;
|
|
||||||
|
|
||||||
vk::UniquePipelineLayout pipelineLayout =
|
|
||||||
device.get()->createPipelineLayoutUnique(pipelineLayoutInfo);
|
|
||||||
|
|
||||||
std::vector<vk::VertexInputBindingDescription> bindingDescriptions{
|
|
||||||
{0, sizeof(Vertex), vk::VertexInputRate::eVertex}};
|
|
||||||
std::vector<vk::VertexInputAttributeDescription> attributeDescriptions{
|
|
||||||
{0, 0, vk::Format::eR32G32Sfloat, offsetof(Vertex, position)},
|
|
||||||
{1, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, color)}};
|
|
||||||
|
|
||||||
std::unique_ptr<sophia::GraphicsPipeline> graphicsPipeline =
|
|
||||||
GraphicsPipeline::Builder(device)
|
|
||||||
.setVertexShader(*vertexShader)
|
|
||||||
.setFragmentShader(*fragmentShader)
|
|
||||||
.setPipelineLayout(pipelineLayout.get())
|
|
||||||
.setColorAttachmentFormats({renderContext.getImageFormat()})
|
|
||||||
.setVertexInput(bindingDescriptions, attributeDescriptions)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// Oversized triangle covering the full screen so the fragment shader runs
|
|
||||||
// for every pixel.
|
|
||||||
std::vector<Vertex> vertices{
|
|
||||||
{{-1.0f, -1.0f}, {1.0f, 0.0f, 0.0f}},
|
|
||||||
{{3.0f, -1.0f}, {0.0f, 1.0f, 0.0f}},
|
|
||||||
{{-1.0f, 3.0f}, {0.0f, 0.0f, 1.0f}},
|
|
||||||
};
|
|
||||||
|
|
||||||
Buffer vertexBuffer{device, sizeof(Vertex),
|
|
||||||
static_cast<u32>(vertices.size()),
|
|
||||||
vk::BufferUsageFlagBits::eVertexBuffer,
|
|
||||||
vk::MemoryPropertyFlagBits::eHostVisible |
|
|
||||||
vk::MemoryPropertyFlagBits::eHostCoherent};
|
|
||||||
vertexBuffer.map();
|
|
||||||
vertexBuffer.writeToBuffer(vertices.data(),
|
|
||||||
sizeof(Vertex) * vertices.size());
|
|
||||||
vertexBuffer.unmap();
|
|
||||||
|
|
||||||
|
|
||||||
}*/
|
|
||||||
|
|
||||||
void run() {
|
void run() {
|
||||||
ModelRenderSystem modelRenderSystem{device, renderContext};
|
ModelRenderSystem modelRenderSystem{device, renderContext};
|
||||||
|
ImGuiRenderer imguiRenderer{window, device, renderContext.getImageFormat(),
|
||||||
|
renderContext.getImageCount()};
|
||||||
|
|
||||||
this->application.onCreate();
|
this->application.onCreate();
|
||||||
|
|
||||||
@@ -139,7 +80,6 @@ class Application::Impl {
|
|||||||
static_cast<float>(extent.height)),
|
static_cast<float>(extent.height)),
|
||||||
this->application.camera};
|
this->application.camera};
|
||||||
this->application.onUpdate(frameInfo);
|
this->application.onUpdate(frameInfo);
|
||||||
this->application.onRender();
|
|
||||||
this->application.camera.setProjection(
|
this->application.camera.setProjection(
|
||||||
-frameInfo.currentFramebufferExtent.x / 2.f,
|
-frameInfo.currentFramebufferExtent.x / 2.f,
|
||||||
frameInfo.currentFramebufferExtent.x / 2.f,
|
frameInfo.currentFramebufferExtent.x / 2.f,
|
||||||
@@ -151,6 +91,11 @@ class Application::Impl {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
imguiRenderer.beginFrame();
|
||||||
|
|
||||||
|
this->application.panelRegistry.update(frameInfo);
|
||||||
|
this->application.onRender();
|
||||||
|
|
||||||
renderContext.transitionCurrentImage(
|
renderContext.transitionCurrentImage(
|
||||||
commandBuffer, vk::ImageLayout::eColorAttachmentOptimal);
|
commandBuffer, vk::ImageLayout::eColorAttachmentOptimal);
|
||||||
|
|
||||||
@@ -194,6 +139,8 @@ class Application::Impl {
|
|||||||
modelRenderSystem.render(commandBuffer, instances, frameInfo);
|
modelRenderSystem.render(commandBuffer, instances, frameInfo);
|
||||||
this->drawCalls.clear();
|
this->drawCalls.clear();
|
||||||
|
|
||||||
|
imguiRenderer.endFrame(commandBuffer);
|
||||||
|
|
||||||
commandBuffer.endRendering();
|
commandBuffer.endRendering();
|
||||||
|
|
||||||
renderContext.transitionCurrentImage(commandBuffer,
|
renderContext.transitionCurrentImage(commandBuffer,
|
||||||
@@ -233,24 +180,11 @@ class Application::Impl {
|
|||||||
this->meshes.clear();
|
this->meshes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshHandle createMesh(std::vector<CanvasVertex> vertices,
|
void drawMesh(const Mesh& mesh, const glm::mat4& transform) {
|
||||||
std::vector<u32> indices) {
|
this->drawCalls.push_back({&mesh, transform});
|
||||||
Mesh::Builder builder{};
|
|
||||||
builder.vertices.reserve(vertices.size());
|
|
||||||
for (const CanvasVertex& vertex : vertices) {
|
|
||||||
builder.vertices.push_back({vertex.position, vertex.color});
|
|
||||||
}
|
|
||||||
builder.indices = std::move(indices);
|
|
||||||
|
|
||||||
this->persistentMeshes.push_back(
|
|
||||||
std::make_unique<Mesh>(this->device, builder));
|
|
||||||
return static_cast<MeshHandle>(this->persistentMeshes.size() - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawMesh(MeshHandle handle, const glm::mat4& transform) {
|
Device& getDevice() { return device; }
|
||||||
this->drawCalls.push_back(
|
|
||||||
{this->persistentMeshes[handle].get(), transform});
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Application& application;
|
Application& application;
|
||||||
@@ -260,7 +194,6 @@ class Application::Impl {
|
|||||||
RenderContext renderContext;
|
RenderContext renderContext;
|
||||||
|
|
||||||
std::vector<std::unique_ptr<Mesh>> meshes;
|
std::vector<std::unique_ptr<Mesh>> meshes;
|
||||||
std::vector<std::unique_ptr<Mesh>> persistentMeshes;
|
|
||||||
std::vector<ModelRenderSystem::MeshInstance> drawCalls;
|
std::vector<ModelRenderSystem::MeshInstance> drawCalls;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -271,7 +204,9 @@ void Application::setCommandLineArgs(int argc, const char* const* argv) {
|
|||||||
Application::Application(const Config& config)
|
Application::Application(const Config& config)
|
||||||
: impl{std::make_unique<Impl>(*this, config)},
|
: impl{std::make_unique<Impl>(*this, config)},
|
||||||
canvas{this},
|
canvas{this},
|
||||||
args{std::move(commandLineArgs)} {}
|
args{std::move(commandLineArgs)},
|
||||||
|
assetRegistry{impl->getDevice()},
|
||||||
|
_debugUI{this->panelRegistry} {}
|
||||||
|
|
||||||
Application::~Application() = default;
|
Application::~Application() = default;
|
||||||
|
|
||||||
@@ -284,13 +219,8 @@ void Application::pushMesh(std::vector<CanvasVertex> vertices,
|
|||||||
|
|
||||||
void Application::clearMeshes() { impl->clearMeshes(); }
|
void Application::clearMeshes() { impl->clearMeshes(); }
|
||||||
|
|
||||||
MeshHandle Application::createMesh(std::vector<CanvasVertex> vertices,
|
|
||||||
std::vector<u32> indices) {
|
|
||||||
return impl->createMesh(std::move(vertices), std::move(indices));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::drawMesh(MeshHandle handle, const glm::mat4& transform) {
|
void Application::drawMesh(MeshHandle handle, const glm::mat4& transform) {
|
||||||
impl->drawMesh(handle, transform);
|
impl->drawMesh(assetRegistry.get<Mesh>(handle), transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace sophia
|
} // namespace sophia
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include <sophia/ui/debug_ui.hpp>
|
#include <sophia/ui/debug_ui.hpp>
|
||||||
|
|
||||||
|
#include "panels/console_panel.hpp"
|
||||||
#include "panels/frame_stats_panel.hpp"
|
#include "panels/frame_stats_panel.hpp"
|
||||||
#include "panels/panel_registry_panel.hpp"
|
#include "panels/panel_registry_panel.hpp"
|
||||||
|
|
||||||
@@ -9,17 +10,20 @@ DebugUI::DebugUI(PanelRegistry& registry) : registry{registry} {
|
|||||||
// #ifndef NDEBUG
|
// #ifndef NDEBUG
|
||||||
this->panelRegistryHandle = registry.emplace<PanelRegistryPanel>(registry);
|
this->panelRegistryHandle = registry.emplace<PanelRegistryPanel>(registry);
|
||||||
this->frameStatsHandle = registry.emplace<FrameStatsPanel>();
|
this->frameStatsHandle = registry.emplace<FrameStatsPanel>();
|
||||||
|
this->consoleHandle = registry.emplace<ConsolePanel>();
|
||||||
// #endif // !NDEBUG
|
// #endif // !NDEBUG
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugUI::show() {
|
void DebugUI::show() {
|
||||||
showPanelRegistry(true);
|
showPanelRegistry(true);
|
||||||
showFrameStats(true);
|
showFrameStats(true);
|
||||||
|
showConsole(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugUI::hide() {
|
void DebugUI::hide() {
|
||||||
showPanelRegistry(false);
|
showPanelRegistry(false);
|
||||||
showFrameStats(false);
|
showFrameStats(false);
|
||||||
|
showConsole(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugUI::showPanelRegistry(bool show) {
|
void DebugUI::showPanelRegistry(bool show) {
|
||||||
@@ -34,4 +38,10 @@ void DebugUI::showFrameStats(bool show) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DebugUI::showConsole(bool show) {
|
||||||
|
if (registry.isValid(consoleHandle)) {
|
||||||
|
registry.get(consoleHandle).setVisible(show);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace sophia
|
} // namespace sophia
|
||||||
|
|||||||
@@ -0,0 +1,136 @@
|
|||||||
|
#include "console_panel.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace sophia {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr ImVec4 COLOR_DEFAULT = ImVec4(0.85f, 0.85f, 0.85f, 1.0f);
|
||||||
|
constexpr ImVec4 COLOR_COMMAND = ImVec4(1.0f, 0.78f, 0.37f, 1.0f);
|
||||||
|
constexpr ImVec4 COLOR_ERROR = ImVec4(1.0f, 0.4f, 0.4f, 1.0f);
|
||||||
|
constexpr ImVec4 COLOR_INFO = ImVec4(0.4f, 0.7f, 1.0f, 1.0f);
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void ConsolePanel::registerDefaultCommands() {
|
||||||
|
log("Console ready. Type 'help' for a list of commands.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsolePanel::log(const std::string& message) {
|
||||||
|
entries.push_back(Entry{message, COLOR_DEFAULT});
|
||||||
|
scrollToBottom = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsolePanel::clear() { entries.clear(); }
|
||||||
|
|
||||||
|
void ConsolePanel::execute(const std::string& command) {
|
||||||
|
entries.push_back(Entry{"> " + command, COLOR_COMMAND});
|
||||||
|
scrollToBottom = true;
|
||||||
|
|
||||||
|
historyPos = -1;
|
||||||
|
history.erase(std::remove(history.begin(), history.end(), command),
|
||||||
|
history.end());
|
||||||
|
history.push_back(command);
|
||||||
|
|
||||||
|
if (command == "help") {
|
||||||
|
entries.push_back(
|
||||||
|
Entry{"Available commands: help, clear, history", COLOR_INFO});
|
||||||
|
} else if (command == "clear") {
|
||||||
|
clear();
|
||||||
|
} else if (command == "history") {
|
||||||
|
for (const std::string& past : history) {
|
||||||
|
entries.push_back(Entry{past, COLOR_DEFAULT});
|
||||||
|
}
|
||||||
|
} else if (commandCallback) {
|
||||||
|
commandCallback(*this, command);
|
||||||
|
} else {
|
||||||
|
entries.push_back(Entry{"Unknown command: '" + command + "'", COLOR_ERROR});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConsolePanel::textEditCallback(ImGuiInputTextCallbackData* data) {
|
||||||
|
if (data->EventFlag != ImGuiInputTextFlags_CallbackHistory) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int previousPos = historyPos;
|
||||||
|
if (data->EventKey == ImGuiKey_UpArrow) {
|
||||||
|
if (historyPos == -1) {
|
||||||
|
historyPos = static_cast<int>(history.size()) - 1;
|
||||||
|
} else if (historyPos > 0) {
|
||||||
|
historyPos--;
|
||||||
|
}
|
||||||
|
} else if (data->EventKey == ImGuiKey_DownArrow) {
|
||||||
|
if (historyPos != -1 && ++historyPos >= static_cast<int>(history.size())) {
|
||||||
|
historyPos = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previousPos != historyPos) {
|
||||||
|
const std::string& historyStr =
|
||||||
|
historyPos >= 0 ? history[static_cast<size_t>(historyPos)] : "";
|
||||||
|
data->DeleteChars(0, data->BufTextLen);
|
||||||
|
data->InsertChars(0, historyStr.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsolePanel::onUpdate(const FrameInfo&) {
|
||||||
|
ImGui::Begin("Console");
|
||||||
|
|
||||||
|
if (ImGui::SmallButton("Clear")) {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Checkbox("Auto-scroll", &autoScroll);
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
const float footerHeight =
|
||||||
|
ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
|
||||||
|
ImGui::BeginChild("ScrollRegion", ImVec2(0, -footerHeight), false,
|
||||||
|
ImGuiWindowFlags_HorizontalScrollbar);
|
||||||
|
|
||||||
|
for (const Entry& entry : entries) {
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, entry.color);
|
||||||
|
ImGui::TextUnformatted(entry.text.c_str());
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scrollToBottom ||
|
||||||
|
(autoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())) {
|
||||||
|
ImGui::SetScrollHereY(1.0f);
|
||||||
|
}
|
||||||
|
scrollToBottom = false;
|
||||||
|
|
||||||
|
ImGui::EndChild();
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
ImGuiInputTextFlags inputFlags = ImGuiInputTextFlags_EnterReturnsTrue |
|
||||||
|
ImGuiInputTextFlags_CallbackHistory;
|
||||||
|
|
||||||
|
bool reclaimFocus = false;
|
||||||
|
if (ImGui::InputText(
|
||||||
|
"Input", inputBuffer, sizeof(inputBuffer), inputFlags,
|
||||||
|
[](ImGuiInputTextCallbackData* data) -> int {
|
||||||
|
auto* console = static_cast<ConsolePanel*>(data->UserData);
|
||||||
|
return console->textEditCallback(data);
|
||||||
|
},
|
||||||
|
this)) {
|
||||||
|
std::string command{inputBuffer};
|
||||||
|
if (!command.empty()) {
|
||||||
|
execute(command);
|
||||||
|
}
|
||||||
|
inputBuffer[0] = '\0';
|
||||||
|
reclaimFocus = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SetItemDefaultFocus();
|
||||||
|
if (reclaimFocus) {
|
||||||
|
ImGui::SetKeyboardFocusHere(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sophia
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <sophia/frame_info.hpp>
|
||||||
|
#include <sophia/ui/panel.hpp>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace sophia {
|
||||||
|
|
||||||
|
class ConsolePanel : public Panel {
|
||||||
|
public:
|
||||||
|
using CommandCallback =
|
||||||
|
std::function<void(ConsolePanel&, const std::string&)>;
|
||||||
|
|
||||||
|
ConsolePanel() : Panel{"Console"} { registerDefaultCommands(); }
|
||||||
|
|
||||||
|
void onUpdate(const FrameInfo& frameInfo) override;
|
||||||
|
|
||||||
|
void log(const std::string& message);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
void setCommandCallback(CommandCallback callback) {
|
||||||
|
this->commandCallback = std::move(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Entry {
|
||||||
|
std::string text;
|
||||||
|
ImVec4 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
void registerDefaultCommands();
|
||||||
|
void execute(const std::string& command);
|
||||||
|
int textEditCallback(struct ImGuiInputTextCallbackData* data);
|
||||||
|
|
||||||
|
std::vector<Entry> entries;
|
||||||
|
std::vector<std::string> history;
|
||||||
|
int historyPos = -1;
|
||||||
|
|
||||||
|
char inputBuffer[256] = {};
|
||||||
|
bool autoScroll = true;
|
||||||
|
bool scrollToBottom = false;
|
||||||
|
|
||||||
|
CommandCallback commandCallback;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sophia
|
||||||
Reference in New Issue
Block a user