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") {
|
||||
sources = [
|
||||
"RobotoMono-Regular.ttf",
|
||||
"imgui.glsl_fragment",
|
||||
"imgui.glsl_vertex",
|
||||
"pass_through.glsl_fragment",
|
||||
"pass_through.glsl_vertex",
|
||||
"RobotoMono-Regular.ttf",
|
||||
"solid.glsl_fragment",
|
||||
"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",
|
||||
"image_quad.cc",
|
||||
"image_quad.h",
|
||||
"imgui_backend.cc",
|
||||
"imgui_backend.h",
|
||||
"input_event.h",
|
||||
"persistent_data.cc",
|
||||
"persistent_data.h",
|
||||
|
|
|
@ -53,6 +53,7 @@ Engine::~Engine() {
|
|||
thread_pool_.CancelTasks();
|
||||
thread_pool_.Shutdown();
|
||||
|
||||
imgui_backend_.Shutdown();
|
||||
game_.reset();
|
||||
stats_.reset();
|
||||
textures_.clear();
|
||||
|
@ -125,6 +126,9 @@ void Engine::Initialize() {
|
|||
// Create resources and let the game finalize initialization.
|
||||
CreateRenderResources();
|
||||
WaitForAsyncWork();
|
||||
|
||||
imgui_backend_.Initialize();
|
||||
|
||||
CHECK(game_->Initialize()) << "Failed to initialize the game.";
|
||||
}
|
||||
|
||||
|
@ -161,7 +165,10 @@ void Engine::Draw(float frame_frac) {
|
|||
d->Draw(frame_frac);
|
||||
}
|
||||
|
||||
imgui_backend_.Render();
|
||||
|
||||
renderer_->Present();
|
||||
imgui_backend_.NewFrame();
|
||||
}
|
||||
|
||||
void Engine::AddDrawable(Drawable* drawable) {
|
||||
|
@ -516,6 +523,10 @@ void Engine::GainedFocus(bool from_interstitial_ad) {
|
|||
}
|
||||
|
||||
void Engine::AddInputEvent(std::unique_ptr<InputEvent> event) {
|
||||
event = imgui_backend_.OnInputEvent(std::move(event));
|
||||
if (!event)
|
||||
return;
|
||||
|
||||
if (replaying_)
|
||||
return;
|
||||
|
||||
|
@ -644,6 +655,8 @@ void Engine::CreateRenderResources() {
|
|||
LOG(0) << "Could not create solid shader.";
|
||||
}
|
||||
|
||||
imgui_backend_.CreateRenderResources(renderer_.get());
|
||||
|
||||
for (auto& t : textures_) {
|
||||
t.second.texture->SetRenderer(renderer_.get());
|
||||
if (t.second.persistent || t.second.use_count > 0) {
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "base/random.h"
|
||||
#include "base/thread_pool.h"
|
||||
#include "base/vecmath.h"
|
||||
#include "engine/imgui_backend.h"
|
||||
#include "engine/persistent_data.h"
|
||||
#include "engine/platform/platform_observer.h"
|
||||
|
||||
|
@ -196,6 +197,8 @@ class Engine : public PlatformObserver {
|
|||
|
||||
std::unique_ptr<ImageQuad> stats_;
|
||||
|
||||
ImguiBackend imgui_backend_;
|
||||
|
||||
float fps_seconds_ = 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