support multi-window in nf7core_sdl2
This commit is contained in:
parent
3accae56b6
commit
2e48ea3c99
@ -3,6 +3,9 @@ target_sources(nf7core_sdl2
|
||||
PRIVATE
|
||||
mod.c
|
||||
poll.h
|
||||
win.c
|
||||
PUBLIC
|
||||
win.h
|
||||
)
|
||||
target_link_libraries(nf7core_sdl2
|
||||
PRIVATE
|
||||
@ -11,3 +14,6 @@ target_link_libraries(nf7core_sdl2
|
||||
OpenGL
|
||||
SDL2
|
||||
)
|
||||
target_tests(nf7core_sdl2
|
||||
win.test.c
|
||||
)
|
||||
|
@ -18,10 +18,8 @@
|
||||
static atomic_uint_least32_t sdl_refcnt_ = 0;
|
||||
|
||||
|
||||
static bool new_setup_gl_(void);
|
||||
static bool new_init_win_(struct nf7_core_sdl2*);
|
||||
|
||||
static void del_(struct nf7_mod*);
|
||||
static void finalize_(struct nf7_core_sdl2*);
|
||||
NF7_UTIL_REFCNT_IMPL(, nf7_core_sdl2, {finalize_(this);});
|
||||
|
||||
|
||||
struct nf7_mod* nf7_core_sdl2_new(const struct nf7* nf7) {
|
||||
@ -47,89 +45,24 @@ struct nf7_mod* nf7_core_sdl2_new(const struct nf7* nf7) {
|
||||
.nf7 = nf7,
|
||||
.malloc = nf7->malloc,
|
||||
.uv = nf7->uv,
|
||||
|
||||
.poll_interval = 30,
|
||||
};
|
||||
nf7_util_signal_init(&this->update, this->malloc);
|
||||
|
||||
if (!(new_setup_gl_() && new_init_win_(this))) {
|
||||
nf7_util_log_error("failed to setup OpenGL");
|
||||
if (!poll_setup_(this)) {
|
||||
nf7_util_log_error("failed to setup polling");
|
||||
goto ABORT;
|
||||
}
|
||||
nf7_util_log_debug("OpenGL is ready");
|
||||
|
||||
if (!poll_init_(this)) {
|
||||
nf7_util_log_error("failed to setup event polling");
|
||||
goto ABORT;
|
||||
}
|
||||
nf7_util_log_debug("polling is activated");
|
||||
|
||||
nf7_core_sdl2_ref(this);
|
||||
return (struct nf7_mod*) this;
|
||||
|
||||
ABORT:
|
||||
nf7_util_log_warn("initialization is aborted");
|
||||
del_((struct nf7_mod*) this);
|
||||
finalize_(this);
|
||||
return nullptr;
|
||||
}
|
||||
static bool new_setup_gl_(void) {
|
||||
# if defined(__APPLE__)
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); // Always required on Mac
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||
# else
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||
# endif
|
||||
return true;
|
||||
}
|
||||
static bool new_init_win_(struct nf7_core_sdl2* this) {
|
||||
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
||||
|
||||
this->win = SDL_CreateWindow(
|
||||
"helloworld",
|
||||
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||
1280, 720,
|
||||
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
|
||||
if (nullptr == this->win) {
|
||||
nf7_util_log_error("failed to create SDL window: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
nf7_util_log_debug("GUI window is created");
|
||||
|
||||
this->gl = SDL_GL_CreateContext(this->win);
|
||||
if (nullptr == this->gl) {
|
||||
nf7_util_log_error("failed to create GL context: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
nf7_util_log_debug("OpenGL context is created");
|
||||
|
||||
if (0 != SDL_GL_SetSwapInterval(0)) {
|
||||
nf7_util_log_warn(
|
||||
"failed to set swap interval, this will cause a performance issue: %s",
|
||||
SDL_GetError());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void del_(struct nf7_mod* this_) {
|
||||
struct nf7_core_sdl2* this = (struct nf7_core_sdl2*) this_;
|
||||
static void finalize_(struct nf7_core_sdl2* this) {
|
||||
if (nullptr != this) {
|
||||
if (nullptr != this->gl) {
|
||||
SDL_GL_DeleteContext(this->gl);
|
||||
nf7_util_log_debug("OpenGL context is deleted");
|
||||
}
|
||||
if (nullptr != this->win) {
|
||||
SDL_DestroyWindow(this->win);
|
||||
nf7_util_log_debug("GUI window is destroyed");
|
||||
}
|
||||
nf7_util_signal_deinit(&this->update);
|
||||
nf7_util_malloc_del(this->malloc, this);
|
||||
}
|
||||
if (1 == atomic_fetch_sub(&sdl_refcnt_, 1)) {
|
||||
@ -139,11 +72,15 @@ static void del_(struct nf7_mod* this_) {
|
||||
}
|
||||
}
|
||||
|
||||
static void unref_(struct nf7_mod* this_) {
|
||||
struct nf7_core_sdl2* this = (struct nf7_core_sdl2*) this_;
|
||||
nf7_core_sdl2_unref(this);
|
||||
}
|
||||
|
||||
const struct nf7_mod_meta nf7_core_sdl2 = {
|
||||
.name = (const uint8_t*) "nf7core_sdl2",
|
||||
.desc = (const uint8_t*) "provides SDL2 features",
|
||||
.ver = 0,
|
||||
|
||||
.delete = del_,
|
||||
.delete = unref_,
|
||||
};
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "nf7.h"
|
||||
|
||||
#include "util/malloc.h"
|
||||
#include "util/refcnt.h"
|
||||
#include "util/signal.h"
|
||||
|
||||
|
||||
@ -24,12 +25,6 @@ struct nf7_core_sdl2 {
|
||||
SDL_Window* win;
|
||||
void* gl;
|
||||
|
||||
// uv handles (immutable)
|
||||
uv_timer_t poll_timer;
|
||||
|
||||
// signals
|
||||
struct nf7_util_signal update;
|
||||
|
||||
// mutable parameters
|
||||
uint64_t poll_interval;
|
||||
uint32_t refcnt;
|
||||
};
|
||||
NF7_UTIL_REFCNT_DECL(, nf7_core_sdl2);
|
||||
|
@ -7,49 +7,88 @@
|
||||
|
||||
#include "core/sdl2/mod.h"
|
||||
|
||||
static bool poll_init_(struct nf7_core_sdl2*);
|
||||
static void poll_deinit_(struct nf7_core_sdl2*);
|
||||
|
||||
struct nf7_core_sdl2_poll {
|
||||
struct nf7_core_sdl2* mod;
|
||||
|
||||
const struct nf7* nf7;
|
||||
struct nf7_util_malloc* malloc;
|
||||
uv_loop_t* uv;
|
||||
|
||||
uv_timer_t timer;
|
||||
|
||||
uint64_t interval;
|
||||
};
|
||||
|
||||
|
||||
static bool poll_setup_(struct nf7_core_sdl2*);
|
||||
static void poll_cancel_(struct nf7_core_sdl2_poll*);
|
||||
|
||||
static void poll_proc_(uv_timer_t*);
|
||||
static void poll_finalize_(uv_handle_t*);
|
||||
|
||||
|
||||
static bool poll_init_(struct nf7_core_sdl2* this) {
|
||||
assert(nullptr != this);
|
||||
static bool poll_setup_(struct nf7_core_sdl2* mod) {
|
||||
assert(nullptr != mod);
|
||||
|
||||
if (0 != uv_timer_init(this->uv, &this->poll_timer)) {
|
||||
struct nf7_core_sdl2_poll* this =
|
||||
nf7_util_malloc_new(mod->malloc, sizeof(*this));
|
||||
if (nullptr == this) {
|
||||
nf7_util_log_error("failed to allocate poll context");
|
||||
return false;
|
||||
}
|
||||
*this = (struct nf7_core_sdl2_poll) {
|
||||
.mod = mod,
|
||||
.nf7 = mod->nf7,
|
||||
.malloc = mod->malloc,
|
||||
.uv = mod->uv,
|
||||
|
||||
.interval = 30,
|
||||
};
|
||||
|
||||
if (0 != uv_timer_init(this->uv, &this->timer)) {
|
||||
nf7_util_log_error("failed to init poll timer");
|
||||
return false;
|
||||
}
|
||||
this->poll_timer.data = this;
|
||||
this->timer.data = this;
|
||||
|
||||
if (0 != uv_timer_start(&this->poll_timer, poll_proc_, 0, 0)) {
|
||||
if (0 != uv_timer_start(&this->timer, poll_proc_, 0, 0)) {
|
||||
nf7_util_log_error("failed to start poll timer");
|
||||
poll_deinit_(this);
|
||||
poll_cancel_(this);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static void poll_deinit_(struct nf7_core_sdl2* this) {
|
||||
static void poll_cancel_(struct nf7_core_sdl2_poll* this) {
|
||||
assert(nullptr != this);
|
||||
uv_close((uv_handle_t*) &this->poll_timer, nullptr);
|
||||
if (this == this->timer.data) {
|
||||
uv_close((uv_handle_t*) &this->timer, poll_finalize_);
|
||||
}
|
||||
}
|
||||
|
||||
static void poll_proc_(uv_timer_t* timer) {
|
||||
assert(nullptr != timer);
|
||||
|
||||
struct nf7_core_sdl2* this = timer->data;
|
||||
struct nf7_core_sdl2_poll* this = timer->data;
|
||||
|
||||
SDL_Event e;
|
||||
while (0 != SDL_PollEvent(&e)) {
|
||||
if (SDL_QUIT == e.type) {
|
||||
nf7_util_log_info("SDL2 event poller is uninstalled");
|
||||
poll_deinit_(this);
|
||||
poll_cancel_(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != uv_timer_start(&this->poll_timer, poll_proc_, this->poll_interval, 0)) {
|
||||
if (0 != uv_timer_start(&this->timer, poll_proc_, this->interval, 0)) {
|
||||
nf7_util_log_error("failed to restart poll timer");
|
||||
poll_deinit_(this);
|
||||
poll_cancel_(this);
|
||||
}
|
||||
}
|
||||
|
||||
static void poll_finalize_(uv_handle_t* handle) {
|
||||
struct nf7_core_sdl2_poll* this = handle->data;
|
||||
assert(nullptr != this);
|
||||
|
||||
nf7_util_malloc_del(this->malloc, this);
|
||||
}
|
||||
|
79
core/sdl2/win.c
Normal file
79
core/sdl2/win.c
Normal file
@ -0,0 +1,79 @@
|
||||
// No copyright
|
||||
#include "core/sdl2/win.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
|
||||
static void setup_gl_(void);
|
||||
|
||||
|
||||
bool nf7_core_sdl2_win_init(struct nf7_core_sdl2_win* this) {
|
||||
assert(nullptr != this);
|
||||
assert(nullptr != this->mod);
|
||||
assert(nullptr != this->malloc);
|
||||
|
||||
setup_gl_();
|
||||
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
||||
|
||||
this->win = SDL_CreateWindow(
|
||||
"Nf7",
|
||||
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||
1280, 720,
|
||||
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
|
||||
if (nullptr == this->win) {
|
||||
nf7_util_log_error("failed to create SDL window: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
nf7_util_log_debug("GUI window is created");
|
||||
|
||||
this->gl = SDL_GL_CreateContext(this->win);
|
||||
if (nullptr == this->gl) {
|
||||
nf7_util_log_error("failed to create GL context: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
nf7_util_log_debug("OpenGL context is created");
|
||||
|
||||
if (0 != SDL_GL_SetSwapInterval(0)) {
|
||||
nf7_util_log_warn(
|
||||
"failed to set swap interval, this will cause a performance issue: %s",
|
||||
SDL_GetError());
|
||||
}
|
||||
|
||||
nf7_core_sdl2_ref(this->mod);
|
||||
return true;
|
||||
}
|
||||
|
||||
void nf7_core_sdl2_win_deinit(struct nf7_core_sdl2_win* this) {
|
||||
if (nullptr != this) {
|
||||
if (nullptr != this->gl) {
|
||||
SDL_GL_DeleteContext(this->gl);
|
||||
nf7_util_log_debug("OpenGL context is deleted");
|
||||
}
|
||||
if (nullptr != this->win) {
|
||||
SDL_DestroyWindow(this->win);
|
||||
nf7_util_log_debug("GUI window is destroyed");
|
||||
}
|
||||
nf7_core_sdl2_unref(this->mod);
|
||||
}
|
||||
}
|
||||
|
||||
static void setup_gl_(void) {
|
||||
# if defined(__APPLE__)
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); // Always required on Mac
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||
# else
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||
# endif
|
||||
}
|
22
core/sdl2/win.h
Normal file
22
core/sdl2/win.h
Normal file
@ -0,0 +1,22 @@
|
||||
// No copyright
|
||||
#pragma once
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "nf7.h"
|
||||
|
||||
#include "util/malloc.h"
|
||||
|
||||
#include "core/sdl2/mod.h"
|
||||
|
||||
|
||||
struct nf7_core_sdl2_win {
|
||||
struct nf7_core_sdl2* mod;
|
||||
struct nf7_util_malloc* malloc;
|
||||
|
||||
SDL_Window* win;
|
||||
void* gl;
|
||||
};
|
||||
|
||||
bool nf7_core_sdl2_win_init(struct nf7_core_sdl2_win*);
|
||||
void nf7_core_sdl2_win_deinit(struct nf7_core_sdl2_win*);
|
84
core/sdl2/win.test.c
Normal file
84
core/sdl2/win.test.c
Normal file
@ -0,0 +1,84 @@
|
||||
// No copyright
|
||||
#include "core/sdl2/win.h"
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include "test/common.h"
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
#include "core/sdl2/mod.h"
|
||||
|
||||
|
||||
struct nf7_core_sdl2_win_test {
|
||||
struct nf7_test* test;
|
||||
struct nf7_util_malloc* malloc;
|
||||
uv_loop_t* uv;
|
||||
|
||||
struct nf7_core_sdl2_win win;
|
||||
uv_timer_t timer;
|
||||
};
|
||||
|
||||
static void finalize_(struct nf7_core_sdl2_win_test*);
|
||||
static void on_time_(uv_timer_t*);
|
||||
static void on_close_(uv_handle_t*);
|
||||
|
||||
NF7_TEST(nf7_core_sdl2_win_test) {
|
||||
struct nf7_core_sdl2* mod = (void*) nf7_get_mod_by_meta(
|
||||
test_->nf7, (struct nf7_mod_meta*) &nf7_core_sdl2);
|
||||
|
||||
struct nf7_core_sdl2_win_test* this =
|
||||
nf7_util_malloc_new(test_->malloc, sizeof(*this));
|
||||
if (!nf7_test_expect(nullptr != this)) {
|
||||
goto ABORT;
|
||||
}
|
||||
*this = (struct nf7_core_sdl2_win_test) {
|
||||
.test = test_,
|
||||
.malloc = test_->malloc,
|
||||
.uv = test_->nf7->uv,
|
||||
.win = {
|
||||
.mod = mod,
|
||||
.malloc = test_->malloc,
|
||||
},
|
||||
};
|
||||
nf7_test_ref(this->test);
|
||||
|
||||
if (!nf7_test_expect(nf7_core_sdl2_win_init(&this->win))) {
|
||||
goto ABORT;
|
||||
}
|
||||
|
||||
if (0 != nf7_util_log_uv(uv_timer_init(this->uv, &this->timer))) {
|
||||
goto ABORT;
|
||||
}
|
||||
this->timer.data = this;
|
||||
|
||||
if (0 != nf7_util_log_uv(uv_timer_start(&this->timer, on_time_, 3000, 0))) {
|
||||
goto ABORT;
|
||||
}
|
||||
return true;
|
||||
|
||||
ABORT:
|
||||
finalize_(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void finalize_(struct nf7_core_sdl2_win_test* this) {
|
||||
if (nullptr != this->timer.data) {
|
||||
uv_close((uv_handle_t*) &this->timer, on_close_);
|
||||
return;
|
||||
}
|
||||
nf7_core_sdl2_win_deinit(&this->win);
|
||||
nf7_test_unref(this->test);
|
||||
nf7_util_malloc_del(this->malloc, this);
|
||||
}
|
||||
|
||||
static void on_time_(uv_timer_t* timer) {
|
||||
struct nf7_core_sdl2_win_test* this = timer->data;
|
||||
finalize_(this);
|
||||
}
|
||||
|
||||
static void on_close_(uv_handle_t* handle) {
|
||||
struct nf7_core_sdl2_win_test* this = handle->data;
|
||||
handle->data = nullptr;
|
||||
finalize_(this);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user