新增窗口管理

This commit is contained in:
Nanako 2024-02-28 11:08:29 +08:00
parent 2f1fc152ff
commit 63436a413f
12 changed files with 188 additions and 36 deletions

View File

@ -5,6 +5,7 @@
#include "command_line.h"
#include "imgui_impl_sdl3.h"
#include "imgui_internal.h"
#include "window_manager.h"
#include "filesystem/stb_image.h"
#include "rhi/texture.h"
#include "rhi/renderer.h"
@ -35,27 +36,26 @@ void application::init(const window_params& in_window_params, int argc, char** a
renderer_->pre_init();
const auto window = g_window_manager.create_main_window(in_window_params.title.c_str(), in_window_params.width, in_window_params.height);
// new glfw window
window_ = glfwCreateWindow(in_window_params.width, in_window_params.height, in_window_params.title.c_str(), nullptr,
nullptr);
if (!window_) {
if (!window) {
spdlog::error("Failed to create glfw window");
return;
}
renderer_->init(window_);
renderer_->init(window);
g_is_running = true;
}
int application::run() {
const ImGuiIO& io = ImGui::GetIO();
while (!g_exit_requested) {
glfwPollEvents();
g_exit_requested = g_exit_requested || glfwWindowShouldClose(window_);
g_window_manager.tick();
g_exit_requested = g_exit_requested || g_window_manager.should_close();
tick(io.DeltaTime);
renderer_->new_frame(window_);
renderer_->new_frame(g_window_manager.get_main_window());
draw_gui();
renderer_->end_frame(window_);
renderer_->end_frame(g_window_manager.get_main_window());
}
shutdown();
@ -74,6 +74,11 @@ void application::shutdown() {
g_is_running = false;
}
void application::request_exit() {
g_window_manager.request_exit();
g_exit_requested = true;
}
std::shared_ptr<texture> application::load_texture(const std::string& path, vk::Format format) {
int width = 0;
int height = 0;
@ -116,8 +121,6 @@ void application::init_imgui() {
}
void application::destroy_glfw() {
glfwDestroyWindow(window_);
window_ = nullptr;
glfwTerminate();
}

View File

@ -48,10 +48,7 @@ public:
virtual void shutdown();
void request_exit() {
glfwSetWindowShouldClose(window_, GLFW_TRUE);
g_exit_requested = true;
}
void request_exit();
virtual void draw_gui() = 0;
virtual void tick(float delta_time) {}
@ -68,11 +65,8 @@ public:
[[nodiscard]] virtual const char* get_draw_ps_vertex_shader_entry() const = 0; // Vertex Shader used for drawing ps
[[nodiscard]] renderer* get_renderer() const { return renderer_; }
[[nodiscard]] GLFWwindow* get_window() const { return window_; }
protected:
renderer* renderer_ = nullptr;
GLFWwindow* window_ = nullptr;
std::shared_ptr<spdlog::logger> async_spdlog_;
private:

View File

@ -0,0 +1,90 @@
#include "window_manager.h"
#include <ranges>
#include "audio/plugin_host/plugin_host.h"
window_manager::window_manager() {
main_window_ = nullptr;
}
void window_manager::init(singleton_initliazer& initliazer) {
singleton_t<window_manager>::init(initliazer);
start_idle_thread();
}
void window_manager::release() {
singleton_t<window_manager>::release();
if (main_window_)
glfwDestroyWindow(main_window_);
stop_idle_thread();
}
void window_manager::tick() {
glfwPollEvents();
if (should_close()) {
destroy_all_plugin_host_window();
}
}
void window_manager::destroy_all_plugin_host_window() {
for (const auto& window: host_window_map_ | std::views::values) {
glfwDestroyWindow(window);
}
host_window_map_.clear();
}
GLFWwindow* window_manager::create_main_window(const char* title, int width, int height) {
if (!main_window_)
main_window_ = glfwCreateWindow(width, height, title, nullptr, nullptr);
return main_window_;
}
GLFWwindow* window_manager::create_plugin_host_window(plugin_host* host) {
if (!host->has_editor())
return nullptr;
if (host_window_map_.contains(host))
return host_window_map_[host];
auto editor_size = host->get_editor_size();
auto new_window = glfwCreateWindow(editor_size.x, editor_size.y, host->name.c_str(), nullptr, nullptr);
host_window_map_[host] = new_window;
return new_window;
}
void window_manager::destroy_plugin_host_window(plugin_host* host) {
if (!host_window_map_.contains(host))
return;
glfwDestroyWindow(host_window_map_[host]);
host_window_map_.erase(host);
}
void window_manager::resize_plugin_host_window(plugin_host* host, int width, int height) {
if (!host_window_map_.contains(host))
return;
glfwSetWindowSize(host_window_map_[host], width, height);
}
void window_manager::idle_plugin_host_window() const {
for (const auto& window_map: host_window_map_) {
window_map.first->idle_editor();
}
}
void window_manager::start_idle_thread() {
idle_thread_ = std::thread(&window_manager::idle_thread_func, this);
idle_thread_.detach();
}
void window_manager::stop_idle_thread() {
idle_thread_running_ = false;
if (idle_thread_.joinable())
idle_thread_.join();
}
void window_manager::idle_thread_func() {
idle_thread_running_ = true;
while (idle_thread_running_) {
idle_plugin_host_window();
std::this_thread::yield();
}
}

View File

@ -0,0 +1,41 @@
#pragma once
#include "GLFW/glfw3.h"
#include "misc/singleton/singleton.h"
#include <map>
class plugin_host;
class window_manager : public singleton_t<window_manager> {
public:
window_manager();
void init(singleton_initliazer& initliazer) override;
void release() override;
void tick();
bool should_close() const { return glfwWindowShouldClose(main_window_); }
void destroy_all_plugin_host_window();
GLFWwindow* create_main_window(const char* title, int width, int height);
void request_exit() const { glfwSetWindowShouldClose(main_window_, GLFW_TRUE); }
GLFWwindow* get_main_window() const { return main_window_; }
GLFWwindow* create_plugin_host_window(plugin_host* host);
void destroy_plugin_host_window(plugin_host* host);
void resize_plugin_host_window(plugin_host* host, int width, int height);
void idle_plugin_host_window() const;
const char* get_name() override { return "window_manager"; }
private:
#pragma region idle_thread
void start_idle_thread();
void stop_idle_thread();
void idle_thread_func();
std::thread idle_thread_;
std::atomic_bool idle_thread_running_;
#pragma endregion
GLFWwindow* main_window_;
std::map<plugin_host*, GLFWwindow*> host_window_map_;
};
DEFINE_SINGLETON_INSTANCE(window_manager)

View File

@ -20,6 +20,10 @@ void audio_device_manager::release() {
delete main_audio_device_;
}
void audio_device_manager::start() {
main_audio_device_->start();
}
double audio_device_manager::get_sample_rate() const {
return main_audio_device_->sample_rate();
}

View File

@ -9,6 +9,8 @@ public:
void init(singleton_initliazer& initliazer) override;
void release() override;
void start();
[[nodiscard]] const char* get_name() override { return "audio_device_manager"; }
[[nodiscard]] double get_sample_rate() const;

View File

@ -18,12 +18,6 @@ port_audio_device::~port_audio_device() {
bool port_audio_device::init() {
Pa_Initialize();
try {
open_stream(-1, Pa_GetDefaultOutputDevice(), sample_rate(), buffer_size());
} catch (const std::exception& e) {
spdlog::error("Init failed: {}", e.what());
return false;
}
return true;
}
@ -36,11 +30,18 @@ void port_audio_device::stop() {
Pa_StopStream(stream_);
Pa_CloseStream(stream_);
stream_ = nullptr;
while (!render_thread_running_)
std::this_thread::sleep_for(std::chrono::milliseconds(1));
stop_render_thread();
spdlog::info("port_audio stopped");
}
void port_audio_device::start() {
try {
open_stream(-1, Pa_GetDefaultOutputDevice(), sample_rate(), buffer_size());
} catch (const std::exception& e) {
spdlog::error("Init failed: {}", e.what());
}
}
void port_audio_device::open_stream(PaDeviceIndex input_device, PaDeviceIndex output_device, double in_sample_rate, uint32_t in_buffer_size) {
const PaStreamParameters* input_params = nullptr;
if (input_device >= 0) {
@ -65,8 +66,7 @@ void port_audio_device::open_stream(PaDeviceIndex input_device, PaDeviceIndex ou
if (err != paNoError) {
throw std::runtime_error(Pa_GetErrorText(err));
}
render_thread_ = std::thread(&port_audio_device::render_thread, this);
render_thread_.detach();
start_render_thread();
}
int port_audio_device::stream_callback(float** input, float** output, unsigned long frame_count,
@ -102,9 +102,18 @@ bool port_audio_device::on_set_sample_rate(double in_sample_rate) {
return true;
}
void port_audio_device::start_render_thread() {
render_thread_ = std::thread(&port_audio_device::render_thread, this);
render_thread_.detach();
}
void port_audio_device::stop_render_thread() {
if (render_thread_.joinable())
render_thread_.join();
}
void port_audio_device::render_thread() {
dummy_track* master = g_mixer.get_master();
render_thread_running_ = true;
spdlog::info("port_audio render thread started");
while (stream_) {
const uint32_t frames = buffer_size();
@ -128,5 +137,4 @@ void port_audio_device::render_thread() {
}
}
spdlog::info("port_audio render thread stopped");
render_thread_running_ = false;
}

View File

@ -12,6 +12,7 @@ public:
void stop();
void start();
void open_stream(PaDeviceIndex input_device, PaDeviceIndex output_device, double in_sample_rate, uint32_t in_buffer_size);
int stream_callback(float** input, float** output, unsigned long frame_count, const PaStreamCallbackTimeInfo* time_info, PaStreamCallbackFlags status_flags);
@ -21,6 +22,8 @@ protected:
private:
#pragma region render_thread
void start_render_thread();
void stop_render_thread();
void render_thread();
std::thread render_thread_;
circular_audio_buffer<float> render_buffer_;

View File

@ -62,7 +62,7 @@ void build_instrument_process_node(const plugin_host* host, std::map<mixer_track
void mixer::init(singleton_initliazer& initliazer) {
singleton_t<mixer>::init(initliazer);
initliazer.require<audio_device_manager>();
auto device_manager = initliazer.require<audio_device_manager>();
zero_track = new dummy_track();
zero_track->rename("zero");
zero_track->init();
@ -71,6 +71,8 @@ void mixer::init(singleton_initliazer& initliazer) {
master->rename("master");
master->init();
tracks_.push_back(master);
device_manager->start();
}
void mixer::release() {

View File

@ -1,5 +1,6 @@
#include "plugin_host.h"
#include "application/window_manager.h"
#include "audio/mixer/channel_interface.h"
plugin_host::~plugin_host() {
@ -7,8 +8,7 @@ plugin_host::~plugin_host() {
}
void plugin_host::try_open_editor() {
auto editor_size = get_editor_size();
editor_window = glfwCreateWindow(editor_size.x, editor_size.y, name.c_str(), nullptr, nullptr);
editor_window = g_window_manager.create_plugin_host_window(this);
open_editor(editor_window);
}

View File

@ -16,7 +16,13 @@ void plugin_host_manager::init(singleton_initliazer& initliazer) {
plugin_host* plugin_host_manager::load_plugin(const char* path) {
auto host = new vst2_plugin_host();
host->load_plugin(path);
try {
host->load_plugin(path);
} catch (std::exception& e) {
spdlog::error("Failed to load plugin: {}", e.what());
delete host;
return nullptr;
}
host->init_channel_interface();
plugin_hosts_.push_back(host);
host->try_open_editor();

View File

@ -1,5 +1,6 @@
#include "vst2_plugin_host.h"
#include "application/window_manager.h"
#include "audio/device/audio_device_manager.h"
#include "audio/mixer/channel_interface.h"
#include "misc/glfw_misc.h"
@ -64,9 +65,7 @@ VstIntPtr vst_master_callback(AEffect* effect, VstInt32 opcode, VstInt32 index,
case audioMasterSizeWindow:
{
// 设置插件窗口大小
// FVST2PluginHost* Host = static_cast<FVST2PluginHost*>(Effect->user);
// if (const TSharedPtr<SWindow> Window = FWindowManager::Get().FindPluginEditor(Host))
// Window->Resize(FVector2D(Index, Value));
g_window_manager.resize_plugin_host_window((plugin_host*)effect->user, index, value);
return 1;
}
case audioMasterGetTime: