mirror of https://github.com/auygun/kaliber.git
Implement ImguiBackend
This commit is contained in:
parent
eed6d4751c
commit
7b8d2db565
|
@ -1,11 +1,13 @@
|
||||||
copy("engine") {
|
copy("engine") {
|
||||||
sources = [
|
sources = [
|
||||||
|
"RobotoMono-Regular.ttf",
|
||||||
|
"imgui.glsl_fragment",
|
||||||
|
"imgui.glsl_vertex",
|
||||||
"pass_through.glsl_fragment",
|
"pass_through.glsl_fragment",
|
||||||
"pass_through.glsl_vertex",
|
"pass_through.glsl_vertex",
|
||||||
"RobotoMono-Regular.ttf",
|
|
||||||
"solid.glsl_fragment",
|
"solid.glsl_fragment",
|
||||||
"solid.glsl_vertex",
|
"solid.glsl_vertex",
|
||||||
]
|
]
|
||||||
|
|
||||||
outputs = ["$root_out_dir/assets/engine/{{source_file_part}}"]
|
outputs = [ "$root_out_dir/assets/engine/{{source_file_part}}" ]
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision mediump float;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
IN(0) vec2 tex_coord_0;
|
||||||
|
IN(1) vec4 color;
|
||||||
|
|
||||||
|
UNIFORM_BEGIN
|
||||||
|
UNIFORM_V(mat4 projection)
|
||||||
|
UNIFORM_END
|
||||||
|
|
||||||
|
SAMPLER(0, sampler2D texture_0)
|
||||||
|
|
||||||
|
FRAG_COLOR_OUT(frag_color)
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
FRAG_COLOR(frag_color) = TEXTURE(texture_0, tex_coord_0) * color;
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
IN(0) vec2 in_position;
|
||||||
|
IN(1) vec2 in_tex_coord_0;
|
||||||
|
IN(2) vec4 in_color;
|
||||||
|
|
||||||
|
UNIFORM_BEGIN
|
||||||
|
UNIFORM_V(mat4 projection)
|
||||||
|
UNIFORM_END
|
||||||
|
|
||||||
|
OUT(0) vec2 tex_coord_0;
|
||||||
|
OUT(1) vec4 color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
tex_coord_0 = in_tex_coord_0;
|
||||||
|
color = in_color;
|
||||||
|
|
||||||
|
gl_Position = PARAM(projection) * vec4(in_position, 0.0, 1.0);
|
||||||
|
}
|
|
@ -22,6 +22,8 @@ source_set("engine") {
|
||||||
"game_factory.h",
|
"game_factory.h",
|
||||||
"image_quad.cc",
|
"image_quad.cc",
|
||||||
"image_quad.h",
|
"image_quad.h",
|
||||||
|
"imgui_backend.cc",
|
||||||
|
"imgui_backend.h",
|
||||||
"input_event.h",
|
"input_event.h",
|
||||||
"persistent_data.cc",
|
"persistent_data.cc",
|
||||||
"persistent_data.h",
|
"persistent_data.h",
|
||||||
|
|
|
@ -53,6 +53,7 @@ Engine::~Engine() {
|
||||||
thread_pool_.CancelTasks();
|
thread_pool_.CancelTasks();
|
||||||
thread_pool_.Shutdown();
|
thread_pool_.Shutdown();
|
||||||
|
|
||||||
|
imgui_backend_.Shutdown();
|
||||||
game_.reset();
|
game_.reset();
|
||||||
stats_.reset();
|
stats_.reset();
|
||||||
textures_.clear();
|
textures_.clear();
|
||||||
|
@ -125,6 +126,9 @@ void Engine::Initialize() {
|
||||||
// Create resources and let the game finalize initialization.
|
// Create resources and let the game finalize initialization.
|
||||||
CreateRenderResources();
|
CreateRenderResources();
|
||||||
WaitForAsyncWork();
|
WaitForAsyncWork();
|
||||||
|
|
||||||
|
imgui_backend_.Initialize();
|
||||||
|
|
||||||
CHECK(game_->Initialize()) << "Failed to initialize the game.";
|
CHECK(game_->Initialize()) << "Failed to initialize the game.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +165,10 @@ void Engine::Draw(float frame_frac) {
|
||||||
d->Draw(frame_frac);
|
d->Draw(frame_frac);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
imgui_backend_.Render();
|
||||||
|
|
||||||
renderer_->Present();
|
renderer_->Present();
|
||||||
|
imgui_backend_.NewFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::AddDrawable(Drawable* drawable) {
|
void Engine::AddDrawable(Drawable* drawable) {
|
||||||
|
@ -516,6 +523,10 @@ void Engine::GainedFocus(bool from_interstitial_ad) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::AddInputEvent(std::unique_ptr<InputEvent> event) {
|
void Engine::AddInputEvent(std::unique_ptr<InputEvent> event) {
|
||||||
|
event = imgui_backend_.OnInputEvent(std::move(event));
|
||||||
|
if (!event)
|
||||||
|
return;
|
||||||
|
|
||||||
if (replaying_)
|
if (replaying_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -644,6 +655,8 @@ void Engine::CreateRenderResources() {
|
||||||
LOG(0) << "Could not create solid shader.";
|
LOG(0) << "Could not create solid shader.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
imgui_backend_.CreateRenderResources(renderer_.get());
|
||||||
|
|
||||||
for (auto& t : textures_) {
|
for (auto& t : textures_) {
|
||||||
t.second.texture->SetRenderer(renderer_.get());
|
t.second.texture->SetRenderer(renderer_.get());
|
||||||
if (t.second.persistent || t.second.use_count > 0) {
|
if (t.second.persistent || t.second.use_count > 0) {
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "base/random.h"
|
#include "base/random.h"
|
||||||
#include "base/thread_pool.h"
|
#include "base/thread_pool.h"
|
||||||
#include "base/vecmath.h"
|
#include "base/vecmath.h"
|
||||||
|
#include "engine/imgui_backend.h"
|
||||||
#include "engine/persistent_data.h"
|
#include "engine/persistent_data.h"
|
||||||
#include "engine/platform/platform_observer.h"
|
#include "engine/platform/platform_observer.h"
|
||||||
|
|
||||||
|
@ -196,6 +197,8 @@ class Engine : public PlatformObserver {
|
||||||
|
|
||||||
std::unique_ptr<ImageQuad> stats_;
|
std::unique_ptr<ImageQuad> stats_;
|
||||||
|
|
||||||
|
ImguiBackend imgui_backend_;
|
||||||
|
|
||||||
float fps_seconds_ = 0;
|
float fps_seconds_ = 0;
|
||||||
int fps_ = 0;
|
int fps_ = 0;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,149 @@
|
||||||
|
#include "engine/imgui_backend.h"
|
||||||
|
|
||||||
|
#include "base/log.h"
|
||||||
|
#include "engine/asset/image.h"
|
||||||
|
#include "engine/asset/mesh.h"
|
||||||
|
#include "engine/asset/shader_source.h"
|
||||||
|
#include "engine/engine.h"
|
||||||
|
#include "engine/input_event.h"
|
||||||
|
#include "engine/renderer/renderer.h"
|
||||||
|
#include "engine/renderer/shader.h"
|
||||||
|
#include "engine/renderer/texture.h"
|
||||||
|
#include "third_party/imgui/imgui.h"
|
||||||
|
|
||||||
|
using namespace base;
|
||||||
|
|
||||||
|
namespace eng {
|
||||||
|
|
||||||
|
ImguiBackend::ImguiBackend() : shader_{std::make_unique<Shader>(nullptr)} {}
|
||||||
|
|
||||||
|
ImguiBackend::~ImguiBackend() = default;
|
||||||
|
|
||||||
|
void ImguiBackend::Initialize() {
|
||||||
|
IMGUI_CHECKVERSION();
|
||||||
|
ImGui::CreateContext();
|
||||||
|
Engine::Get().SetImageSource(
|
||||||
|
"imgui_atlas",
|
||||||
|
[]() -> std::unique_ptr<Image> {
|
||||||
|
// Build texture atlas
|
||||||
|
unsigned char* pixels;
|
||||||
|
int width, height;
|
||||||
|
ImGui::GetIO().Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||||
|
LOG(0) << "imgui font width: " << width << " height: " << height;
|
||||||
|
auto image = std::make_unique<Image>();
|
||||||
|
image->Create(width, height);
|
||||||
|
memcpy(image->GetBuffer(), pixels, width * height * 4);
|
||||||
|
return image;
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
Engine::Get().RefreshImage("imgui_atlas");
|
||||||
|
ImGui::GetIO().Fonts->SetTexID(
|
||||||
|
(ImTextureID)(intptr_t)Engine::Get().AcquireTexture("imgui_atlas"));
|
||||||
|
|
||||||
|
NewFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImguiBackend::Shutdown() {
|
||||||
|
ImGui::DestroyContext();
|
||||||
|
shader_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImguiBackend::CreateRenderResources(Renderer* renderer) {
|
||||||
|
renderer_ = renderer;
|
||||||
|
shader_->SetRenderer(renderer);
|
||||||
|
|
||||||
|
auto source = std::make_unique<ShaderSource>();
|
||||||
|
if (source->Load("engine/imgui.glsl")) {
|
||||||
|
static const char vertex_description[] = "p2f;t2f;c4b";
|
||||||
|
VertexDescription vd;
|
||||||
|
if (!ParseVertexDescription(vertex_description, vd)) {
|
||||||
|
DLOG(0) << "Failed to parse vertex description.";
|
||||||
|
} else {
|
||||||
|
shader_->Create(std::move(source), vd, kPrimitive_Triangles, false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG(0) << "Could not create imgui shader.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<InputEvent> ImguiBackend::OnInputEvent(
|
||||||
|
std::unique_ptr<InputEvent> event) {
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
switch (event->GetType()) {
|
||||||
|
case InputEvent::kDragStart:
|
||||||
|
io.AddMousePosEvent(event->GetVector().x, event->GetVector().y);
|
||||||
|
io.AddMouseButtonEvent(0, true);
|
||||||
|
break;
|
||||||
|
case InputEvent::kDragEnd:
|
||||||
|
io.AddMousePosEvent(event->GetVector().x, event->GetVector().y);
|
||||||
|
io.AddMouseButtonEvent(0, false);
|
||||||
|
break;
|
||||||
|
case InputEvent::kDrag:
|
||||||
|
io.AddMousePosEvent(event->GetVector().x, event->GetVector().y);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// TODO: Keyboard input
|
||||||
|
|
||||||
|
if (io.WantCaptureMouse)
|
||||||
|
event.reset();
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImguiBackend::NewFrame() {
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.DisplaySize = ImVec2((float)renderer_->GetScreenWidth(),
|
||||||
|
(float)renderer_->GetScreenHeight());
|
||||||
|
io.DeltaTime = timer_.Elapsed();
|
||||||
|
ImGui::NewFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImguiBackend::Render() {
|
||||||
|
ImGui::Render();
|
||||||
|
|
||||||
|
ImDrawData* draw_data = ImGui::GetDrawData();
|
||||||
|
if (draw_data->CmdListsCount < -0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float L = draw_data->DisplayPos.x;
|
||||||
|
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||||
|
float T = draw_data->DisplayPos.y;
|
||||||
|
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
||||||
|
base::Matrix4f ortho_projection;
|
||||||
|
ortho_projection.CreateOrthoProjection(L, R, B, T);
|
||||||
|
|
||||||
|
for (int n = 0; n < draw_data->CmdListsCount; n++) {
|
||||||
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
static const char vertex_description[] = "p2f;t2f;c4b";
|
||||||
|
auto mesh = std::make_unique<Mesh>();
|
||||||
|
mesh->Create(kPrimitive_Triangles, vertex_description,
|
||||||
|
cmd_list->VtxBuffer.Size, cmd_list->VtxBuffer.Data,
|
||||||
|
kDataType_UShort, cmd_list->IdxBuffer.Size,
|
||||||
|
cmd_list->IdxBuffer.Data);
|
||||||
|
auto geometry_id = renderer_->CreateGeometry(std::move(mesh));
|
||||||
|
|
||||||
|
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) {
|
||||||
|
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||||
|
reinterpret_cast<Texture*>(pcmd->GetTexID())->Activate();
|
||||||
|
|
||||||
|
// Vulkan renderer needs activating the shader again after a texture.
|
||||||
|
// TODO: Fix it in vulkan renderer and active the shader only once.
|
||||||
|
shader_->Activate();
|
||||||
|
shader_->SetUniform("projection", ortho_projection);
|
||||||
|
shader_->UploadUniforms();
|
||||||
|
|
||||||
|
if (pcmd->ClipRect.z > pcmd->ClipRect.x &&
|
||||||
|
pcmd->ClipRect.w > pcmd->ClipRect.y) {
|
||||||
|
renderer_->SetScissor(int(pcmd->ClipRect.x), int(pcmd->ClipRect.y),
|
||||||
|
int(pcmd->ClipRect.z - pcmd->ClipRect.x),
|
||||||
|
int(pcmd->ClipRect.w - pcmd->ClipRect.y));
|
||||||
|
}
|
||||||
|
renderer_->Draw(geometry_id, pcmd->ElemCount, pcmd->IdxOffset);
|
||||||
|
}
|
||||||
|
renderer_->DestroyGeometry(geometry_id);
|
||||||
|
}
|
||||||
|
renderer_->ResetScissor();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace eng
|
|
@ -0,0 +1,37 @@
|
||||||
|
#ifndef ENGINE_IMGUI_BACKEND_H
|
||||||
|
#define ENGINE_IMGUI_BACKEND_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "base/timer.h"
|
||||||
|
|
||||||
|
namespace eng {
|
||||||
|
|
||||||
|
class InputEvent;
|
||||||
|
class Shader;
|
||||||
|
class Renderer;
|
||||||
|
|
||||||
|
class ImguiBackend {
|
||||||
|
public:
|
||||||
|
ImguiBackend();
|
||||||
|
~ImguiBackend();
|
||||||
|
|
||||||
|
void Initialize();
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
void CreateRenderResources(Renderer* renderer);
|
||||||
|
|
||||||
|
std::unique_ptr<InputEvent> OnInputEvent(std::unique_ptr<InputEvent> event);
|
||||||
|
|
||||||
|
void NewFrame();
|
||||||
|
void Render();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<Shader> shader_;
|
||||||
|
Renderer* renderer_ = nullptr;
|
||||||
|
base::ElapsedTimer timer_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace eng
|
||||||
|
|
||||||
|
#endif // ENGINE_IMGUI_BACKEND_H
|
Loading…
Reference in New Issue