Compare commits
2 Commits
d385726ae6
...
0e76f9ccb2
Author | SHA1 | Date | |
---|---|---|---|
0e76f9ccb2 | |||
d8cd074f40 |
@ -6,6 +6,7 @@ target_link_libraries(nf7_core
|
|||||||
luajit
|
luajit
|
||||||
nf7_config
|
nf7_config
|
||||||
nf7_iface
|
nf7_iface
|
||||||
|
OpenGL
|
||||||
SDL2
|
SDL2
|
||||||
sqlite
|
sqlite
|
||||||
uvw
|
uvw
|
||||||
@ -13,6 +14,7 @@ target_link_libraries(nf7_core
|
|||||||
target_sources(nf7_core
|
target_sources(nf7_core
|
||||||
PRIVATE
|
PRIVATE
|
||||||
gl3/context.cc
|
gl3/context.cc
|
||||||
|
imgui/context.cc
|
||||||
luajit/context.cc
|
luajit/context.cc
|
||||||
luajit/lambda.cc
|
luajit/lambda.cc
|
||||||
luajit/thread.cc
|
luajit/thread.cc
|
||||||
@ -22,6 +24,8 @@ target_sources(nf7_core
|
|||||||
version.cc
|
version.cc
|
||||||
PUBLIC
|
PUBLIC
|
||||||
gl3/context.hh
|
gl3/context.hh
|
||||||
|
imgui/context.hh
|
||||||
|
imgui/driver.hh
|
||||||
luajit/context.hh
|
luajit/context.hh
|
||||||
luajit/lambda.hh
|
luajit/lambda.hh
|
||||||
luajit/thread.hh
|
luajit/thread.hh
|
||||||
@ -44,6 +48,7 @@ add_executable(nf7_core_test)
|
|||||||
target_sources(nf7_core_test
|
target_sources(nf7_core_test
|
||||||
PRIVATE
|
PRIVATE
|
||||||
gl3/context_test.cc
|
gl3/context_test.cc
|
||||||
|
imgui/context_test.cc
|
||||||
luajit/context_test.cc
|
luajit/context_test.cc
|
||||||
luajit/context_test.hh
|
luajit/context_test.hh
|
||||||
luajit/lambda_test.cc
|
luajit/lambda_test.cc
|
||||||
|
163
core/imgui/context.cc
Normal file
163
core/imgui/context.cc
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
// No copyright
|
||||||
|
#include "core/imgui/context.hh"
|
||||||
|
|
||||||
|
#include <SDL_opengl.h>
|
||||||
|
#include <imgui_impl_opengl3.h>
|
||||||
|
#include <imgui_impl_sdl2.h>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "iface/common/exception.hh"
|
||||||
|
#include "iface/common/observer.hh"
|
||||||
|
#include "iface/subsys/clock.hh"
|
||||||
|
|
||||||
|
#include "core/gl3/context.hh"
|
||||||
|
|
||||||
|
|
||||||
|
namespace nf7::core::imgui {
|
||||||
|
|
||||||
|
class Context::Impl final : public std::enable_shared_from_this<Impl> {
|
||||||
|
private:
|
||||||
|
static constexpr auto kUpdateInterval = std::chrono::milliseconds {33};
|
||||||
|
|
||||||
|
private:
|
||||||
|
class EventQueue final : public Observer<SDL_Event> {
|
||||||
|
public:
|
||||||
|
using Observer<SDL_Event>::Observer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
EventQueue(const EventQueue&) = delete;
|
||||||
|
EventQueue(EventQueue&&) = delete;
|
||||||
|
EventQueue& operator=(const EventQueue&) = delete;
|
||||||
|
EventQueue& operator=(EventQueue&&) = delete;
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::vector<SDL_Event> Take() noexcept { return std::move(items_); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Notify(const SDL_Event& e) noexcept override { items_.push_back(e); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<SDL_Event> items_;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Impl(Env& env)
|
||||||
|
: clock_(env.Get<subsys::Clock>()),
|
||||||
|
gl3_(env.Get<gl3::Context>()),
|
||||||
|
events_(std::make_unique<EventQueue>(*gl3_)),
|
||||||
|
imgui_(ImGui::CreateContext()) {
|
||||||
|
}
|
||||||
|
Impl(const Impl&) = delete;
|
||||||
|
Impl(Impl&&) = delete;
|
||||||
|
Impl& operator=(const Impl&) = delete;
|
||||||
|
Impl& operator=(Impl&&) = delete;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void ScheduleStart() noexcept {
|
||||||
|
gl3_->Exec([this, self = shared_from_this()](auto& t) { Start(t); });
|
||||||
|
}
|
||||||
|
void ScheduleTearDown() noexcept {
|
||||||
|
gl3_->Exec([this, self = shared_from_this()](auto& t) { TearDown(t); });
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::shared_ptr<Driver>& Register(const std::shared_ptr<Driver>& driver)
|
||||||
|
try {
|
||||||
|
drivers_.emplace_back(driver);
|
||||||
|
return driver;
|
||||||
|
} catch (const std::bad_alloc&) {
|
||||||
|
throw MemoryException {};
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Start(gl3::TaskContext& t) noexcept {
|
||||||
|
ImGui::SetCurrentContext(imgui_);
|
||||||
|
ImGui_ImplSDL2_InitForOpenGL(t.win(), t.gl());
|
||||||
|
ImGui_ImplOpenGL3_Init(gl3::Context::kGlslVersion);
|
||||||
|
Update(t);
|
||||||
|
}
|
||||||
|
void Update(gl3::TaskContext& t) noexcept {
|
||||||
|
ImGui::SetCurrentContext(imgui_);
|
||||||
|
|
||||||
|
// get active drivers and drop dead ones
|
||||||
|
std::vector<std::shared_ptr<Driver>> drivers;
|
||||||
|
for (auto itr = drivers_.begin(); itr != drivers_.end();) {
|
||||||
|
if (auto driver = itr->lock()) {
|
||||||
|
drivers.emplace_back(std::move(driver));
|
||||||
|
++itr;
|
||||||
|
} else {
|
||||||
|
itr = drivers_.erase(itr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// event handling
|
||||||
|
const auto events = events_->Take();
|
||||||
|
for (const auto& event : events) {
|
||||||
|
ImGui_ImplSDL2_ProcessEvent(&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
// frame reset
|
||||||
|
ImGui_ImplOpenGL3_NewFrame();
|
||||||
|
ImGui_ImplSDL2_NewFrame();
|
||||||
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
// draw something
|
||||||
|
for (const auto& driver : drivers) { driver->Update(t); }
|
||||||
|
ImGui::Render();
|
||||||
|
|
||||||
|
// render them
|
||||||
|
const auto& io = ImGui::GetIO();
|
||||||
|
glViewport(0, 0,
|
||||||
|
static_cast<int>(io.DisplaySize.x),
|
||||||
|
static_cast<int>(io.DisplaySize.y));
|
||||||
|
glClearColor(0, 0, 0, 0);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
for (const auto& driver : drivers) { driver->PreUpdate(t); }
|
||||||
|
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||||
|
for (const auto& driver : drivers) { driver->PostUpdate(t); }
|
||||||
|
SDL_GL_SwapWindow(t.win());
|
||||||
|
|
||||||
|
// schedule next frame
|
||||||
|
gl3_->Push(gl3::Task {
|
||||||
|
clock_->now() + kUpdateInterval,
|
||||||
|
[wself = weak_from_this()](auto& t) {
|
||||||
|
if (auto self = wself.lock()) { self->Update(t); }
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
void TearDown(gl3::TaskContext&) noexcept {
|
||||||
|
ImGui::SetCurrentContext(imgui_);
|
||||||
|
ImGui_ImplOpenGL3_Shutdown();
|
||||||
|
ImGui_ImplSDL2_Shutdown();
|
||||||
|
ImGui::DestroyContext(imgui_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::shared_ptr<subsys::Clock> clock_;
|
||||||
|
const std::shared_ptr<gl3::Context> gl3_;
|
||||||
|
const std::unique_ptr<EventQueue> events_;
|
||||||
|
|
||||||
|
ImGuiContext* const imgui_;
|
||||||
|
|
||||||
|
std::vector<std::weak_ptr<Driver>> drivers_;
|
||||||
|
};
|
||||||
|
|
||||||
|
Context::Context(Env& env)
|
||||||
|
try : subsys::Interface("nf7::core::imgui::Context"),
|
||||||
|
impl_(std::make_shared<Impl>(env)) {
|
||||||
|
impl_->ScheduleStart();
|
||||||
|
} catch (const std::bad_alloc&) {
|
||||||
|
throw MemoryException {};
|
||||||
|
}
|
||||||
|
Context::~Context() noexcept {
|
||||||
|
impl_->ScheduleTearDown();
|
||||||
|
}
|
||||||
|
const std::shared_ptr<Driver>& Context::Register(
|
||||||
|
const std::shared_ptr<Driver>& driver) {
|
||||||
|
return impl_->Register(driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace nf7::core::imgui
|
31
core/imgui/context.hh
Normal file
31
core/imgui/context.hh
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// No copyright
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "iface/env.hh"
|
||||||
|
|
||||||
|
#include "core/imgui/driver.hh"
|
||||||
|
|
||||||
|
|
||||||
|
namespace nf7::core::imgui {
|
||||||
|
|
||||||
|
class Context : public subsys::Interface {
|
||||||
|
private:
|
||||||
|
class Impl;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Context(Env&);
|
||||||
|
~Context() noexcept override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
const std::shared_ptr<Driver>& Register(
|
||||||
|
const std::shared_ptr<Driver>& driver);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::shared_ptr<Impl> impl_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace nf7::core::imgui
|
38
core/imgui/context_test.cc
Normal file
38
core/imgui/context_test.cc
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// No copyright
|
||||||
|
#include "core/imgui/context.hh"
|
||||||
|
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "core/gl3/context_test.hh"
|
||||||
|
#include "core/imgui/driver_test.hh"
|
||||||
|
|
||||||
|
|
||||||
|
// adds meaningless suffix to avoid a conflict with ImGuiContext
|
||||||
|
using ImGuiContext0 = nf7::core::gl3::test::ContextFixture;
|
||||||
|
|
||||||
|
TEST_F(ImGuiContext0, Init) {
|
||||||
|
const auto clock = env().Get<nf7::subsys::Clock>();
|
||||||
|
const auto concurrency = env().Get<nf7::subsys::Concurrency>();
|
||||||
|
|
||||||
|
auto ctx = std::make_shared<nf7::core::imgui::Context>(env());
|
||||||
|
concurrency->Push(nf7::SyncTask {
|
||||||
|
clock->now() + std::chrono::seconds {10},
|
||||||
|
[&](auto&) { ctx = nullptr; },
|
||||||
|
});
|
||||||
|
|
||||||
|
auto driver = std::make_shared<
|
||||||
|
::testing::NiceMock<nf7::core::imgui::test::DriverMock>>();
|
||||||
|
ctx->Register(driver);
|
||||||
|
|
||||||
|
bool shown = true;
|
||||||
|
ON_CALL(*driver, Update).WillByDefault([&](auto&) {
|
||||||
|
ImGui::ShowDemoWindow(&shown);
|
||||||
|
});
|
||||||
|
|
||||||
|
DropEnv();
|
||||||
|
ConsumeTasks();
|
||||||
|
}
|
25
core/imgui/driver.hh
Normal file
25
core/imgui/driver.hh
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// No copyright
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/gl3/context.hh"
|
||||||
|
|
||||||
|
|
||||||
|
namespace nf7::core::imgui {
|
||||||
|
|
||||||
|
class Driver {
|
||||||
|
public:
|
||||||
|
Driver() = default;
|
||||||
|
virtual ~Driver() = default;
|
||||||
|
|
||||||
|
Driver(const Driver&) = delete;
|
||||||
|
Driver(Driver&&) = delete;
|
||||||
|
Driver& operator=(const Driver&) = delete;
|
||||||
|
Driver& operator=(Driver&&) = delete;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void PreUpdate(gl3::TaskContext&) noexcept { }
|
||||||
|
virtual void Update(gl3::TaskContext&) noexcept { }
|
||||||
|
virtual void PostUpdate(gl3::TaskContext&) noexcept { }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace nf7::core::imgui
|
22
core/imgui/driver_test.hh
Normal file
22
core/imgui/driver_test.hh
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// No copyright
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/imgui/driver.hh"
|
||||||
|
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
|
#include "core/gl3/context.hh"
|
||||||
|
|
||||||
|
|
||||||
|
namespace nf7::core::imgui::test {
|
||||||
|
|
||||||
|
class DriverMock : public Driver {
|
||||||
|
public:
|
||||||
|
using Driver::Driver;
|
||||||
|
|
||||||
|
MOCK_METHOD(void, PreUpdate, (gl3::TaskContext&), (noexcept, override));
|
||||||
|
MOCK_METHOD(void, Update, (gl3::TaskContext&), (noexcept, override));
|
||||||
|
MOCK_METHOD(void, PostUpdate, (gl3::TaskContext&), (noexcept, override));
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace nf7::core::imgui::test
|
4
thirdparty/CMakeLists.txt
vendored
4
thirdparty/CMakeLists.txt
vendored
@ -29,6 +29,10 @@ FetchContent_Declare(
|
|||||||
FetchContent_Populate(luajit)
|
FetchContent_Populate(luajit)
|
||||||
include(luajit.cmake)
|
include(luajit.cmake)
|
||||||
|
|
||||||
|
# ---- OpenGL
|
||||||
|
find_package(OpenGL REQUIRED GLOBAL)
|
||||||
|
add_library(OpenGL ALIAS OpenGL::GL)
|
||||||
|
|
||||||
# ---- SDL2 (zlib)
|
# ---- SDL2 (zlib)
|
||||||
find_package(SDL2 REQUIRED GLOBAL)
|
find_package(SDL2 REQUIRED GLOBAL)
|
||||||
add_library(SDL2 ALIAS SDL2::SDL2)
|
add_library(SDL2 ALIAS SDL2::SDL2)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user