Moved window event handling out of gfx thread so resizing doesn't freeze gameplay, added full document hot reloading for UI
This commit is contained in:
parent
458ccd81fc
commit
346e298eb1
|
@ -64,7 +64,7 @@ typedef struct {
|
||||||
//DLLEXPORT void (CALL *PumpEvents)(void) = nullptr;
|
//DLLEXPORT void (CALL *PumpEvents)(void) = nullptr;
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
extern "C" int InitiateGFXWindows(GFX_INFO Gfx_Info, HWND hwnd);
|
extern "C" int InitiateGFXWindows(GFX_INFO Gfx_Info, HWND hwnd, DWORD threadId);
|
||||||
#elif defined(__ANDROID__)
|
#elif defined(__ANDROID__)
|
||||||
static_assert(false && "Unimplemented");
|
static_assert(false && "Unimplemented");
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
|
|
|
@ -6,10 +6,8 @@ static uint32_t sample_rate = 48000;
|
||||||
|
|
||||||
static Multilibultra::audio_callbacks_t audio_callbacks;
|
static Multilibultra::audio_callbacks_t audio_callbacks;
|
||||||
|
|
||||||
void Multilibultra::set_audio_callbacks(const audio_callbacks_t* callbacks) {
|
void set_audio_callbacks(const Multilibultra::audio_callbacks_t& callbacks) {
|
||||||
if (callbacks != nullptr) {
|
audio_callbacks = callbacks;
|
||||||
audio_callbacks = *callbacks;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Multilibultra::init_audio() {
|
void Multilibultra::init_audio() {
|
||||||
|
|
|
@ -236,14 +236,6 @@ void task_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* thread_rea
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Multilibultra::gfx_callbacks_t gfx_callbacks;
|
|
||||||
|
|
||||||
void Multilibultra::set_gfx_callbacks(const gfx_callbacks_t* callbacks) {
|
|
||||||
if (callbacks != nullptr) {
|
|
||||||
gfx_callbacks = *callbacks;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void gfx_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* thread_ready, Multilibultra::WindowHandle window_handle) {
|
void gfx_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* thread_ready, Multilibultra::WindowHandle window_handle) {
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
Multilibultra::gfx_callbacks_t::gfx_data_t gfx_data{};
|
Multilibultra::gfx_callbacks_t::gfx_data_t gfx_data{};
|
||||||
|
@ -251,14 +243,6 @@ void gfx_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* thread_read
|
||||||
Multilibultra::set_native_thread_name("Gfx Thread");
|
Multilibultra::set_native_thread_name("Gfx Thread");
|
||||||
Multilibultra::set_native_thread_priority(Multilibultra::ThreadPriority::Normal);
|
Multilibultra::set_native_thread_priority(Multilibultra::ThreadPriority::Normal);
|
||||||
|
|
||||||
if (gfx_callbacks.create_gfx != nullptr) {
|
|
||||||
gfx_data = gfx_callbacks.create_gfx();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gfx_callbacks.create_window != nullptr) {
|
|
||||||
window_handle = gfx_callbacks.create_window(gfx_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
RT64Init(rom, rdram, window_handle);
|
RT64Init(rom, rdram, window_handle);
|
||||||
|
|
||||||
rsp_constants_init();
|
rsp_constants_init();
|
||||||
|
@ -285,9 +269,6 @@ void gfx_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* thread_read
|
||||||
RT64UpdateScreen(swap_action->origin);
|
RT64UpdateScreen(swap_action->origin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (gfx_callbacks.update_gfx != nullptr) {
|
|
||||||
gfx_callbacks.update_gfx(nullptr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,13 +30,18 @@ namespace Multilibultra {
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
// Native HWND handle to the target window.
|
// Native HWND handle to the target window.
|
||||||
using WindowHandle = HWND;
|
struct WindowHandle {
|
||||||
|
HWND window;
|
||||||
|
DWORD thread_id = (DWORD)-1;
|
||||||
|
auto operator<=>(const WindowHandle&) const = default;
|
||||||
|
};
|
||||||
#elif defined(__ANDROID__)
|
#elif defined(__ANDROID__)
|
||||||
using WindowHandle = ANativeWindow*;
|
using WindowHandle = ANativeWindow*;
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
struct WindowHandle {
|
struct WindowHandle {
|
||||||
Display* display;
|
Display* display;
|
||||||
Window window;
|
Window window;
|
||||||
|
auto operator<=>(const WindowHandle&) const = default;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -101,14 +106,12 @@ struct audio_callbacks_t {
|
||||||
get_samples_remaining_t* get_frames_remaining;
|
get_samples_remaining_t* get_frames_remaining;
|
||||||
set_frequency_t* set_frequency;
|
set_frequency_t* set_frequency;
|
||||||
};
|
};
|
||||||
void set_audio_callbacks(const audio_callbacks_t* callbacks);
|
|
||||||
|
|
||||||
// Input
|
// Input
|
||||||
struct input_callbacks_t {
|
struct input_callbacks_t {
|
||||||
using get_input_t = void(uint16_t*, float*, float*);
|
using get_input_t = void(uint16_t*, float*, float*);
|
||||||
get_input_t* get_input;
|
get_input_t* get_input;
|
||||||
};
|
};
|
||||||
void set_input_callbacks(const input_callbacks_t* callback);
|
|
||||||
|
|
||||||
struct gfx_callbacks_t {
|
struct gfx_callbacks_t {
|
||||||
using gfx_data_t = void*;
|
using gfx_data_t = void*;
|
||||||
|
@ -119,7 +122,7 @@ struct gfx_callbacks_t {
|
||||||
create_window_t* create_window;
|
create_window_t* create_window;
|
||||||
update_gfx_t* update_gfx;
|
update_gfx_t* update_gfx;
|
||||||
};
|
};
|
||||||
void set_gfx_callbacks(const gfx_callbacks_t* callbacks);
|
void start(WindowHandle window_handle, const audio_callbacks_t& audio_callbacks, const input_callbacks_t& input_callbacks, const gfx_callbacks_t& gfx_callbacks);
|
||||||
|
|
||||||
class preemption_guard {
|
class preemption_guard {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include "multilibultra.hpp"
|
#include "multilibultra.hpp"
|
||||||
|
|
||||||
// Start time for the program
|
// Start time for the program
|
||||||
static std::chrono::system_clock::time_point start = std::chrono::system_clock::now();
|
static std::chrono::system_clock::time_point start_time = std::chrono::system_clock::now();
|
||||||
// Game speed multiplier (1 means no speedup)
|
// Game speed multiplier (1 means no speedup)
|
||||||
constexpr uint32_t speed_multiplier = 1;
|
constexpr uint32_t speed_multiplier = 1;
|
||||||
// N64 CPU counter ticks per millisecond
|
// N64 CPU counter ticks per millisecond
|
||||||
|
@ -52,11 +52,11 @@ std::chrono::microseconds ticks_to_duration(uint64_t ticks) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::chrono::system_clock::time_point ticks_to_timepoint(uint64_t ticks) {
|
std::chrono::system_clock::time_point ticks_to_timepoint(uint64_t ticks) {
|
||||||
return start + ticks_to_duration(ticks);
|
return start_time + ticks_to_duration(ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t time_now() {
|
uint64_t time_now() {
|
||||||
return duration_to_ticks(std::chrono::system_clock::now() - start);
|
return duration_to_ticks(std::chrono::system_clock::now() - start_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
void timer_thread(RDRAM_ARG1) {
|
void timer_thread(RDRAM_ARG1) {
|
||||||
|
@ -142,11 +142,11 @@ uint32_t Multilibultra::get_speed_multiplier() {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::chrono::system_clock::time_point Multilibultra::get_start() {
|
std::chrono::system_clock::time_point Multilibultra::get_start() {
|
||||||
return start;
|
return start_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::chrono::system_clock::duration Multilibultra::time_since_start() {
|
std::chrono::system_clock::duration Multilibultra::time_since_start() {
|
||||||
return std::chrono::system_clock::now() - start;
|
return std::chrono::system_clock::now() - start_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" u32 osGetCount() {
|
extern "C" u32 osGetCount() {
|
||||||
|
|
|
@ -3,10 +3,8 @@
|
||||||
|
|
||||||
static Multilibultra::input_callbacks_t input_callbacks;
|
static Multilibultra::input_callbacks_t input_callbacks;
|
||||||
|
|
||||||
void Multilibultra::set_input_callbacks(const input_callbacks_t* callbacks) {
|
void set_input_callbacks(const Multilibultra::input_callbacks_t& callbacks) {
|
||||||
if (callbacks != nullptr) {
|
input_callbacks = callbacks;
|
||||||
input_callbacks = *callbacks;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int max_controllers = 0;
|
static int max_controllers = 0;
|
||||||
|
|
|
@ -164,7 +164,7 @@ Multilibultra::WindowHandle create_window(Multilibultra::gfx_callbacks_t::gfx_da
|
||||||
SDL_GetWindowWMInfo(window, &wmInfo);
|
SDL_GetWindowWMInfo(window, &wmInfo);
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
return wmInfo.info.win.window;
|
return Multilibultra::WindowHandle{ wmInfo.info.win.window, GetCurrentThreadId() };
|
||||||
#elif defined(__ANDROID__)
|
#elif defined(__ANDROID__)
|
||||||
static_assert(false && "Unimplemented");
|
static_assert(false && "Unimplemented");
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
|
@ -353,19 +353,7 @@ int main(int argc, char** argv) {
|
||||||
.get_input = get_input,
|
.get_input = get_input,
|
||||||
};
|
};
|
||||||
|
|
||||||
//create_gfx();
|
Multilibultra::start({}, audio_callbacks, input_callbacks, gfx_callbacks);
|
||||||
//void* window_handle = create_window(nullptr);
|
|
||||||
|
|
||||||
Multilibultra::set_gfx_callbacks(&gfx_callbacks);
|
|
||||||
start(Multilibultra::WindowHandle{}, &audio_callbacks, &input_callbacks);
|
|
||||||
|
|
||||||
// Do nothing forever
|
|
||||||
while (1) {
|
|
||||||
using namespace std::chrono_literals;
|
|
||||||
std::this_thread::sleep_for(10ms);
|
|
||||||
//update_gfx(nullptr);
|
|
||||||
//std::this_thread::sleep_for(1ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,31 +187,31 @@ EXPORT extern "C" void init() {
|
||||||
// return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
// return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
/*EXPORT extern "C"*/ void start(Multilibultra::WindowHandle window_handle, const Multilibultra::audio_callbacks_t* audio_callbacks, const Multilibultra::input_callbacks_t* input_callbacks) {
|
static Multilibultra::gfx_callbacks_t gfx_callbacks;
|
||||||
Multilibultra::set_audio_callbacks(audio_callbacks);
|
|
||||||
Multilibultra::set_input_callbacks(input_callbacks);
|
|
||||||
|
|
||||||
//// Register window class.
|
void set_audio_callbacks(const Multilibultra::audio_callbacks_t& callbacks);
|
||||||
//WNDCLASS wc;
|
void set_input_callbacks(const Multilibultra::input_callbacks_t& callback);
|
||||||
//memset(&wc, 0, sizeof(WNDCLASS));
|
|
||||||
//wc.lpfnWndProc = WindowProc;
|
|
||||||
//wc.hInstance = GetModuleHandle(0);
|
|
||||||
//wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
|
|
||||||
//wc.lpszClassName = "RT64Sample";
|
|
||||||
//RegisterClass(&wc);
|
|
||||||
|
|
||||||
//// Create window.
|
void Multilibultra::start(WindowHandle window_handle, const audio_callbacks_t& audio_callbacks, const input_callbacks_t& input_callbacks, const gfx_callbacks_t& gfx_callbacks_) {
|
||||||
//const int Width = 1280;
|
set_audio_callbacks(audio_callbacks);
|
||||||
//const int Height = 720;
|
set_input_callbacks(input_callbacks);
|
||||||
//RECT rect;
|
|
||||||
//UINT dwStyle = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
|
|
||||||
//rect.left = (GetSystemMetrics(SM_CXSCREEN) - Width) / 2;
|
|
||||||
//rect.top = (GetSystemMetrics(SM_CYSCREEN) - Height) / 2;
|
|
||||||
//rect.right = rect.left + Width;
|
|
||||||
//rect.bottom = rect.top + Height;
|
|
||||||
//AdjustWindowRectEx(&rect, dwStyle, 0, 0);
|
|
||||||
|
|
||||||
//HWND hwnd = CreateWindow(wc.lpszClassName, "Recomp", dwStyle, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0, 0, wc.hInstance, NULL);
|
gfx_callbacks_t gfx_callbacks = gfx_callbacks_;
|
||||||
|
|
||||||
|
gfx_callbacks_t::gfx_data_t gfx_data{};
|
||||||
|
|
||||||
|
if (gfx_callbacks.create_gfx) {
|
||||||
|
gfx_data = gfx_callbacks.create_gfx();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window_handle == WindowHandle{}) {
|
||||||
|
if (gfx_callbacks.create_window) {
|
||||||
|
window_handle = gfx_callbacks.create_window(gfx_data);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert(false && "No create_window callback provided");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::thread game_thread{[](Multilibultra::WindowHandle window_handle) {
|
std::thread game_thread{[](Multilibultra::WindowHandle window_handle) {
|
||||||
debug_printf("[Recomp] Starting\n");
|
debug_printf("[Recomp] Starting\n");
|
||||||
|
@ -225,5 +225,11 @@ EXPORT extern "C" void init() {
|
||||||
debug_printf("[Recomp] Quitting\n");
|
debug_printf("[Recomp] Quitting\n");
|
||||||
}, window_handle};
|
}, window_handle};
|
||||||
|
|
||||||
game_thread.detach();
|
while (true) {
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
std::this_thread::sleep_for(1ms);
|
||||||
|
if (gfx_callbacks.update_gfx != nullptr) {
|
||||||
|
gfx_callbacks.update_gfx(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,7 @@ void RT64Init(uint8_t* rom, uint8_t* rdram, Multilibultra::WindowHandle window_h
|
||||||
gfx_info.RDRAM_SIZE = &RDRAM_SIZE;
|
gfx_info.RDRAM_SIZE = &RDRAM_SIZE;
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
InitiateGFXWindows(gfx_info, window_handle);
|
InitiateGFXWindows(gfx_info, window_handle.window, window_handle.thread_id);
|
||||||
#elif defined(__ANDROID__)
|
#elif defined(__ANDROID__)
|
||||||
static_assert(false && "Unimplemented");
|
static_assert(false && "Unimplemented");
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
|
|
56
src/ui.cpp
56
src/ui.cpp
|
@ -38,6 +38,7 @@
|
||||||
struct UIRenderContext {
|
struct UIRenderContext {
|
||||||
RT64::RenderInterface* interface;
|
RT64::RenderInterface* interface;
|
||||||
RT64::RenderDevice* device;
|
RT64::RenderDevice* device;
|
||||||
|
Rml::ElementDocument* document;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO deduplicate from rt64_common.h
|
// TODO deduplicate from rt64_common.h
|
||||||
|
@ -99,6 +100,8 @@ T from_bytes_le(const char* input) {
|
||||||
return *reinterpret_cast<const T*>(input);
|
return *reinterpret_cast<const T*>(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void load_document();
|
||||||
|
|
||||||
class RmlRenderInterface_RT64 : public Rml::RenderInterface {
|
class RmlRenderInterface_RT64 : public Rml::RenderInterface {
|
||||||
static constexpr uint32_t per_frame_descriptor_set = 0;
|
static constexpr uint32_t per_frame_descriptor_set = 0;
|
||||||
static constexpr uint32_t per_draw_descriptor_set = 1;
|
static constexpr uint32_t per_draw_descriptor_set = 1;
|
||||||
|
@ -516,7 +519,7 @@ public:
|
||||||
mvp_ = projection_mtx_ * transform_;
|
mvp_ = projection_mtx_ * transform_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void start(RT64::RenderCommandList* list, uint32_t image_width, uint32_t image_height) {
|
void start(RT64::RenderCommandList* list, uint32_t image_width, uint32_t image_height, bool reload_style) {
|
||||||
list_ = list;
|
list_ = list;
|
||||||
list_->setPipeline(pipeline_.get());
|
list_->setPipeline(pipeline_.get());
|
||||||
list_->setGraphicsPipelineLayout(layout_.get());
|
list_->setGraphicsPipelineLayout(layout_.get());
|
||||||
|
@ -528,6 +531,10 @@ public:
|
||||||
// Clear out any stale buffers from the last command list.
|
// Clear out any stale buffers from the last command list.
|
||||||
stale_buffers_.clear();
|
stale_buffers_.clear();
|
||||||
|
|
||||||
|
if (reload_style) {
|
||||||
|
load_document();
|
||||||
|
}
|
||||||
|
|
||||||
// Reset and map the upload buffer.
|
// Reset and map the upload buffer.
|
||||||
upload_buffer_bytes_used_ = 0;
|
upload_buffer_bytes_used_ = 0;
|
||||||
upload_buffer_mapped_data_ = reinterpret_cast<uint8_t*>(upload_buffer_->map());
|
upload_buffer_mapped_data_ = reinterpret_cast<uint8_t*>(upload_buffer_->map());
|
||||||
|
@ -556,6 +563,18 @@ struct {
|
||||||
// TODO make this not be global
|
// TODO make this not be global
|
||||||
extern SDL_Window* window;
|
extern SDL_Window* window;
|
||||||
|
|
||||||
|
void load_document() {
|
||||||
|
if (UIContext.render.document) {
|
||||||
|
UIContext.render.document->Close();
|
||||||
|
// Documents are owned by RmlUi, so we don't have anything to free here.
|
||||||
|
UIContext.render.document = nullptr;
|
||||||
|
}
|
||||||
|
UIContext.render.document = UIContext.rml.context->LoadDocument("assets/demo.rml");
|
||||||
|
if (UIContext.render.document) {
|
||||||
|
UIContext.render.document->Show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void init_hook(RT64::RenderInterface* interface, RT64::RenderDevice* device) {
|
void init_hook(RT64::RenderInterface* interface, RT64::RenderDevice* device) {
|
||||||
printf("RT64 hook init\n");
|
printf("RT64 hook init\n");
|
||||||
|
|
||||||
|
@ -598,10 +617,7 @@ void init_hook(RT64::RenderInterface* interface, RT64::RenderDevice* device) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Rml::ElementDocument* document = UIContext.rml.context->LoadDocument("assets/demo.rml")) {
|
load_document();
|
||||||
document->Show();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderTexture* swap_chain_texture) {
|
void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderTexture* swap_chain_texture) {
|
||||||
|
@ -613,14 +629,42 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderTexture* swap_
|
||||||
|
|
||||||
// TODO process SDL events
|
// TODO process SDL events
|
||||||
|
|
||||||
|
int num_keys;
|
||||||
|
const Uint8* key_state = SDL_GetKeyboardState(&num_keys);
|
||||||
|
|
||||||
|
static bool was_reload_held = false;
|
||||||
|
bool is_reload_held = key_state[SDL_SCANCODE_F11] != 0;
|
||||||
|
bool reload_sheets = is_reload_held && !was_reload_held;
|
||||||
|
was_reload_held = is_reload_held;
|
||||||
|
|
||||||
|
static bool menu_open = false;
|
||||||
|
static bool was_toggle_menu_held = false;
|
||||||
|
bool is_toggle_menu_held = key_state[SDL_SCANCODE_M] != 0;
|
||||||
|
if (is_toggle_menu_held && !was_toggle_menu_held) {
|
||||||
|
menu_open = !menu_open;
|
||||||
|
}
|
||||||
|
was_toggle_menu_held = is_toggle_menu_held;
|
||||||
|
|
||||||
|
if (menu_open) {
|
||||||
int width, height;
|
int width, height;
|
||||||
SDL_GetWindowSizeInPixels(window, &width, &height);
|
SDL_GetWindowSizeInPixels(window, &width, &height);
|
||||||
|
|
||||||
UIContext.rml.render_interface->start(command_list, width, height);
|
UIContext.rml.render_interface->start(command_list, width, height, reload_sheets);
|
||||||
|
|
||||||
|
static int prev_width = 0;
|
||||||
|
static int prev_height = 0;
|
||||||
|
|
||||||
|
if (prev_width != width || prev_height != height) {
|
||||||
|
UIContext.rml.context->SetDimensions({ width, height });
|
||||||
|
}
|
||||||
|
prev_width = width;
|
||||||
|
prev_height = height;
|
||||||
|
|
||||||
UIContext.rml.context->Update();
|
UIContext.rml.context->Update();
|
||||||
UIContext.rml.context->Render();
|
UIContext.rml.context->Render();
|
||||||
UIContext.rml.render_interface->end(command_list);
|
UIContext.rml.render_interface->end(command_list);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void deinit_hook() {
|
void deinit_hook() {
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue