From fa71b56cb0caafbfe5260c9f60910f0319897157 Mon Sep 17 00:00:00 2001 From: KiritoDv Date: Mon, 5 Jul 2021 01:31:11 -0500 Subject: [PATCH] Added hooks to interact with the rendering api [OpenGL / DirectX] --- src/moon/mod-engine/hooks/hook.h | 13 ++ src/pc/gfx/gfx_direct3d11.cpp | 23 +++ src/pc/gfx/gfx_direct3d12.cpp | 24 +++ src/pc/gfx/gfx_opengl.c | 29 +++ src/pc/gfx/gfx_opengl.unused | 344 ------------------------------- src/pc/gfx/gfx_opengl_legacy.c | 30 ++- 6 files changed, 118 insertions(+), 345 deletions(-) delete mode 100644 src/pc/gfx/gfx_opengl.unused diff --git a/src/moon/mod-engine/hooks/hook.h b/src/moon/mod-engine/hooks/hook.h index 6e754fea..d5ca42c4 100644 --- a/src/moon/mod-engine/hooks/hook.h +++ b/src/moon/mod-engine/hooks/hook.h @@ -14,6 +14,19 @@ struct HookParameter { #define SAVE_GRAPH_NODE "SaveGraphNode" #define LOAD_GRAPH_NODE "LoadGraphNode" +// Graphics API Hooks +#define GFX_PRE_START_FRAME "GFXApiPreStartFrame" +#define GFX_POST_START_FRAME "GFXApiPostStartFrame" + +#define GFX_PRE_END_FRAME "GFXApiPreEndFrame" +#define GFX_POST_END_FRAME "GFXApiPostEndFrame" + +#define GFX_ON_REZISE "GFXApiOnResize" +#define GFX_INIT "GFXApiInit" +#define GFX_SHUTDOWN "GFXApiShutdown" + +// End + #ifdef __cplusplus #include diff --git a/src/pc/gfx/gfx_direct3d11.cpp b/src/pc/gfx/gfx_direct3d11.cpp index d27524b7..73acb605 100644 --- a/src/pc/gfx/gfx_direct3d11.cpp +++ b/src/pc/gfx/gfx_direct3d11.cpp @@ -26,6 +26,7 @@ #include "gfx_dxgi.h" #include "gfx_screen_config.h" +#include "moon/mod-engine/hooks/hook.h" #define THREE_POINT_FILTERING 0 #define DEBUG_D3D 0 @@ -303,6 +304,10 @@ static void gfx_d3d11_init(void) { gfx_dxgi_get_h_wnd(), "Failed to create per-draw constant buffer."); d3d.context->PSSetConstantBuffers(1, 1, d3d.per_draw_cb.GetAddressOf()); + + MoonInternal::bindHook(GFX_INIT); + MoonInternal::initBindHook(0); + MoonInternal::callBindHook(1, (struct HookParameter){.name = "d3d", .parameter = (void*) &d3d}); } @@ -664,9 +669,16 @@ static void gfx_d3d11_draw_triangles(float buf_vbo[], size_t buf_vbo_len, size_t static void gfx_d3d11_on_resize(void) { create_render_target_views(true); + MoonInternal::bindHook(GFX_ON_REZISE); + MoonInternal::initBindHook(0); + MoonInternal::callBindHook(1, (struct HookParameter){.name = "d3d", .parameter = (void*) &d3d}); } static void gfx_d3d11_start_frame(void) { + MoonInternal::bindHook(GFX_PRE_START_FRAME); + MoonInternal::initBindHook(0); + if(MoonInternal::callBindHook(1, (struct HookParameter){.name = "d3d", .parameter = (void*) &d3d})) return; + // Set render targets d3d.context->OMSetRenderTargets(1, d3d.backbuffer_view.GetAddressOf(), d3d.depth_stencil_view.Get()); @@ -693,9 +705,20 @@ static void gfx_d3d11_start_frame(void) { d3d.context->Map(d3d.per_frame_cb.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &ms); memcpy(ms.pData, &d3d.per_frame_cb_data, sizeof(PerFrameCB)); d3d.context->Unmap(d3d.per_frame_cb.Get(), 0); + + MoonInternal::bindHook(GFX_POST_START_FRAME); + MoonInternal::initBindHook(0); + MoonInternal::callBindHook(1, (struct HookParameter){.name = "d3d", .parameter = (void*) &d3d}); } static void gfx_d3d11_end_frame(void) { + MoonInternal::bindHook(GFX_PRE_END_FRAME); + MoonInternal::initBindHook(0); + MoonInternal::callBindHook(1, (struct HookParameter){.name = "d3d", .parameter = (void*) &d3d}); + + MoonInternal::bindHook(GFX_POST_END_FRAME); + MoonInternal::initBindHook(0); + MoonInternal::callBindHook(1, (struct HookParameter){.name = "d3d", .parameter = (void*) &d3d}); } static void gfx_d3d11_finish_render(void) { diff --git a/src/pc/gfx/gfx_direct3d12.cpp b/src/pc/gfx/gfx_direct3d12.cpp index 2a31043b..c8913a93 100644 --- a/src/pc/gfx/gfx_direct3d12.cpp +++ b/src/pc/gfx/gfx_direct3d12.cpp @@ -38,6 +38,7 @@ #include "gfx_direct3d_common.h" #include "gfx_screen_config.h" +#include "moon/mod-engine/hooks/hook.h" #define DEBUG_D3D 0 @@ -582,6 +583,11 @@ static void gfx_direct3d12_draw_triangles(float buf_vbo[], size_t buf_vbo_len, s } static void gfx_direct3d12_start_frame(void) { + + MoonInternal::bindHook(GFX_PRE_START_FRAME); + MoonInternal::initBindHook(0); + if(MoonInternal::callBindHook(1, (struct HookParameter){.name = "d3d", .parameter = (void*) &d3d})) return; + ++d3d.frame_counter; d3d.srv_pos = 0; texture_uploads = 0; @@ -614,6 +620,10 @@ static void gfx_direct3d12_start_frame(void) { memcpy(d3d.mapped_noise_cb_address, &d3d.noise_cb_data, sizeof(struct NoiseCB)); d3d.vbuf_pos = 0; + + MoonInternal::bindHook(GFX_POST_START_FRAME); + MoonInternal::initBindHook(0); + MoonInternal::callBindHook(1, (struct HookParameter){.name = "d3d", .parameter = (void*) &d3d}); } static void create_render_target_views(void) { @@ -675,6 +685,9 @@ static void gfx_direct3d12_on_resize(void) { d3d.frame_index = d3d.swap_chain->GetCurrentBackBufferIndex(); create_render_target_views(); create_depth_buffer(); + MoonInternal::bindHook(GFX_ON_REZISE); + MoonInternal::initBindHook(0); + MoonInternal::callBindHook(1, (struct HookParameter){.name = "d3d", .parameter = (void*) &d3d}); } } @@ -866,9 +879,17 @@ static void gfx_direct3d12_init(void ) { CD3DX12_RANGE read_range(0, 0); // Read not possible from CPU ThrowIfFailed(d3d.vertex_buffer->Map(0, &read_range, &d3d.mapped_vbuf_address)); } + + MoonInternal::bindHook(GFX_INIT); + MoonInternal::initBindHook(0); + MoonInternal::callBindHook(1, (struct HookParameter){.name = "d3d", .parameter = (void*) &d3d}); } static void gfx_direct3d12_end_frame(void) { + MoonInternal::bindHook(GFX_PRE_END_FRAME); + MoonInternal::initBindHook(0); + if(MoonInternal::callBindHook(1, (struct HookParameter){.name = "d3d", .parameter = (void*) &d3d})) return; + if (max_texture_uploads < texture_uploads && texture_uploads != 38 && texture_uploads != 34 && texture_uploads != 29) { max_texture_uploads = texture_uploads; } @@ -902,6 +923,9 @@ static void gfx_direct3d12_end_frame(void) { QueryPerformanceCounter(&t0); //printf("Present: %llu %u\n", (unsigned long long)(t0.QuadPart - d3d.qpc_init), d3d.length_in_vsync_frames); } + MoonInternal::bindHook(GFX_POST_END_FRAME); + MoonInternal::initBindHook(0); + MoonInternal::callBindHook(1, (struct HookParameter){.name = "d3d", .parameter = (void*) &d3d}); } static void gfx_direct3d12_finish_render(void) { diff --git a/src/pc/gfx/gfx_opengl.c b/src/pc/gfx/gfx_opengl.c index b3d090b0..8aeabb2b 100644 --- a/src/pc/gfx/gfx_opengl.c +++ b/src/pc/gfx/gfx_opengl.c @@ -32,6 +32,7 @@ #include "../configfile.h" #include "gfx_cc.h" #include "gfx_rendering_api.h" +#include "moon/mod-engine/hooks/hook.h" #define TEX_CACHE_STEP 512 @@ -632,12 +633,26 @@ static void gfx_opengl_init(void) { glDepthFunc(GL_LEQUAL); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + moon_bind_hook(GFX_INIT); + moon_init_hook(0); + moon_call_hook(0); } static void gfx_opengl_on_resize(void) { + moon_bind_hook(GFX_ON_REZISE); + moon_init_hook(0); + moon_call_hook(0); } static void gfx_opengl_start_frame(void) { + + moon_bind_hook(GFX_PRE_START_FRAME); + moon_init_hook(0); + if(moon_call_hook(0)){ + return; + } + frame_count++; glDisable(GL_SCISSOR_TEST); @@ -645,15 +660,29 @@ static void gfx_opengl_start_frame(void) { glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_SCISSOR_TEST); + moon_bind_hook(GFX_POST_START_FRAME); + moon_init_hook(0); + moon_call_hook(0); + } static void gfx_opengl_end_frame(void) { + moon_bind_hook(GFX_PRE_END_FRAME); + moon_init_hook(0); + moon_call_hook(0); + + moon_bind_hook(GFX_POST_END_FRAME); + moon_init_hook(0); + moon_call_hook(0); } static void gfx_opengl_finish_render(void) { } static void gfx_opengl_shutdown(void) { + moon_bind_hook(GFX_SHUTDOWN); + moon_init_hook(0); + moon_call_hook(0); } struct GfxRenderingAPI gfx_opengl_api = { diff --git a/src/pc/gfx/gfx_opengl.unused b/src/pc/gfx/gfx_opengl.unused deleted file mode 100644 index cb186e3a..00000000 --- a/src/pc/gfx/gfx_opengl.unused +++ /dev/null @@ -1,344 +0,0 @@ -#ifndef RAPI_GL - -#include -#include - -#ifndef _LANGUAGE_C -# define _LANGUAGE_C -#endif -#include - -#ifdef __MINGW32__ -# define FOR_WINDOWS 1 -#else -# define FOR_WINDOWS 0 -#endif - -#if FOR_WINDOWS || defined(OSX_BUILD) -# define GLEW_STATIC -# include -#endif - -#include - -#define GL_GLEXT_PROTOTYPES 1 -#ifdef USE_GLES -# include -#else -# include -#endif - -extern "C" { -#include "../configfile.h" -#include "../../game/area.h" -#include "../../game/level_update.h" -#include "../fs/fs.h" -#include "../pc_main.h" -#include "../../goddard/gd_math.h" -#include "gfx_cc.h" -} - -#include -#include -#include -#include -#include -#include - -#define TEX_CACHE_STEP 512 - -struct ShaderProgram { - uint32_t shader_id; - GLuint opengl_program_id; - uint8_t num_inputs; - bool used_textures[2]; - uint8_t num_floats; - GLint attrib_locations[7]; - GLint uniform_locations[5]; - uint8_t attrib_sizes[7]; - uint8_t num_attribs; - bool used_noise; -}; - -struct GLTexture { - GLuint gltex; - GLfloat size[2]; - bool filter; -}; - -static struct ShaderProgram shader_program_pool[64]; -static uint8_t shader_program_pool_size; -static GLuint opengl_vbo; - -static int tex_cache_size = 0; -static int num_textures = 0; -static struct GLTexture *tex_cache = NULL; - -static struct ShaderProgram *opengl_prg = NULL; -static struct GLTexture *opengl_tex[2]; -static int opengl_curtex = 0; - -static uint32_t frame_count; - -static bool gfx_opengl_z_is_from_0_to_1(void) { - return false; -} - -static void gfx_opengl_vertex_array_set_attribs(struct ShaderProgram *prg) { - size_t num_floats = prg->num_floats; - size_t pos = 0; - - for (int i = 0; i < prg->num_attribs; i++) { - glEnableVertexAttribArray(prg->attrib_locations[i]); - glVertexAttribPointer(prg->attrib_locations[i], prg->attrib_sizes[i], GL_FLOAT, GL_FALSE, num_floats * sizeof(float), (void *) (pos * sizeof(float))); - pos += prg->attrib_sizes[i]; - } -} - -static inline void gfx_opengl_set_shader_uniforms(struct ShaderProgram *prg) { - if (prg->used_noise) - glUniform1f(prg->uniform_locations[4], (float)frame_count); -} - -static inline void gfx_opengl_set_texture_uniforms(struct ShaderProgram *prg, const int tile) { - if (prg->used_textures[tile] && opengl_tex[tile]) { - glUniform2f(prg->uniform_locations[tile*2 + 0], opengl_tex[tile]->size[0], opengl_tex[tile]->size[1]); - glUniform1i(prg->uniform_locations[tile*2 + 1], opengl_tex[tile]->filter); - } -} - -static void gfx_opengl_unload_shader(struct ShaderProgram *old_prg) { - -} - -static void gfx_opengl_load_shader(struct ShaderProgram *new_prg) { - -} - -static struct ShaderProgram *gfx_opengl_create_and_load_new_shader(uint32_t shader_id) { - ShaderProgram *shaderProgram = new ShaderProgram(); - int c[2][4]; - for (int i = 0; i < 4; i++) { - c[0][i] = (shader_id >> (i * 3)) & 7; - c[1][i] = (shader_id >> (12 + i * 3)) & 7; - } - shaderProgram->shader_id = shader_id; - shaderProgram->used_textures[0] = false; - shaderProgram->used_textures[1] = false; - shaderProgram->num_inputs = 0; - for (int i = 0; i < 2; i++) { - for (int j = 0; j < 4; j++) { - if (c[i][j] >= SHADER_INPUT_1 && c[i][j] <= SHADER_INPUT_4) { - if (c[i][j] > shaderProgram->num_inputs) { - shaderProgram->num_inputs = c[i][j]; - } - } - if (c[i][j] == SHADER_TEXEL0 || c[i][j] == SHADER_TEXEL0A) { - shaderProgram->used_textures[0] = true; - } - if (c[i][j] == SHADER_TEXEL1) { - shaderProgram->used_textures[1] = true; - } - } - } - - return shaderProgram; -} - -static struct ShaderProgram *gfx_opengl_lookup_shader(uint32_t shader_id) { - for (size_t i = 0; i < shader_program_pool_size; i++) { - if (shader_program_pool[i].shader_id == shader_id) { - return &shader_program_pool[i]; - } - } - return NULL; -} - -static void gfx_opengl_shader_get_info(struct ShaderProgram *prg, uint8_t *num_inputs, bool used_textures[2]) { - *num_inputs = prg->num_inputs; - used_textures[0] = prg->used_textures[0]; - used_textures[1] = prg->used_textures[1]; -} - -static GLuint gfx_opengl_new_texture(void) { - if (num_textures >= tex_cache_size) { - tex_cache_size += TEX_CACHE_STEP; - tex_cache = realloc(tex_cache, sizeof(struct GLTexture) * tex_cache_size); - if (!tex_cache) sys_fatal("out of memory allocating texture cache"); - // invalidate these because they might be pointing to garbage now - opengl_tex[0] = NULL; - opengl_tex[1] = NULL; - } - glGenTextures(1, &tex_cache[num_textures].gltex); - return num_textures++; -} - -static void gfx_opengl_select_texture(int tile, GLuint texture_id) { - opengl_tex[tile] = tex_cache + texture_id; - opengl_curtex = tile; - glActiveTexture(GL_TEXTURE0 + tile); - glBindTexture(GL_TEXTURE_2D, opengl_tex[tile]->gltex); - gfx_opengl_set_texture_uniforms(opengl_prg, tile); -} - -static void gfx_opengl_upload_texture(uint8_t *rgba32_buf, int width, int height) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba32_buf); - opengl_tex[opengl_curtex]->size[0] = width; - opengl_tex[opengl_curtex]->size[1] = height; -} - -static uint32_t gfx_cm_to_opengl(uint32_t val) { - if (val & G_TX_CLAMP) { - return GL_CLAMP_TO_EDGE; - } - return (val & G_TX_MIRROR) ? GL_MIRRORED_REPEAT : GL_REPEAT; -} - -static void gfx_opengl_set_sampler_parameters(int tile, bool linear_filter, uint32_t cms, uint32_t cmt) { - const GLenum filter = linear_filter ? GL_LINEAR : GL_NEAREST; - glActiveTexture(GL_TEXTURE0 + tile); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gfx_cm_to_opengl(cms)); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gfx_cm_to_opengl(cmt)); - opengl_curtex = tile; - if (opengl_tex[tile]) { - opengl_tex[tile]->filter = linear_filter; - gfx_opengl_set_texture_uniforms(opengl_prg, tile); - } -} - -static void gfx_opengl_set_depth_test(bool depth_test) { - if (depth_test) { - glEnable(GL_DEPTH_TEST); - } else { - glDisable(GL_DEPTH_TEST); - } -} - -static void gfx_opengl_set_depth_mask(bool z_upd) { - glDepthMask(z_upd ? GL_TRUE : GL_FALSE); -} - -static void gfx_opengl_set_zmode_decal(bool zmode_decal) { - if (zmode_decal) { - glPolygonOffset(-2, -2); - glEnable(GL_POLYGON_OFFSET_FILL); - } else { - glPolygonOffset(0, 0); - glDisable(GL_POLYGON_OFFSET_FILL); - } -} - -static void gfx_opengl_set_viewport(int x, int y, int width, int height) { - glViewport(x, y, width, height); -} - -static void gfx_opengl_set_scissor(int x, int y, int width, int height) { - glScissor(x, y, width, height); -} - -static void gfx_opengl_set_use_alpha(bool use_alpha) { - if (use_alpha) { - glEnable(GL_BLEND); - } else { - glDisable(GL_BLEND); - } -} - -static void gfx_opengl_draw_triangles(float buf_vbo[], size_t buf_vbo_len, size_t buf_vbo_num_tris) { - //printf("flushing %d tris\n", buf_vbo_num_tris); - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * buf_vbo_len, buf_vbo, GL_STREAM_DRAW); - glDrawArrays(GL_TRIANGLES, 0, 3 * buf_vbo_num_tris); -} - -static inline bool gl_get_version(int *major, int *minor, bool *is_es) { - const char *vstr = (const char *)glGetString(GL_VERSION); - if (!vstr || !vstr[0]) return false; - - if (!strncmp(vstr, "OpenGL ES ", 10)) { - vstr += 10; - *is_es = true; - } else if (!strncmp(vstr, "OpenGL ES-CM ", 13)) { - vstr += 13; - *is_es = true; - } - - return (sscanf(vstr, "%d.%d", major, minor) == 2); -} - -static void gfx_opengl_init(void) { -#if FOR_WINDOWS || defined(OSX_BUILD) - GLenum err; - if ((err = glewInit()) != GLEW_OK) - sys_fatal("could not init GLEW:\n%s", glewGetErrorString(err)); -#endif - - tex_cache_size = TEX_CACHE_STEP; - tex_cache = calloc(tex_cache_size, sizeof(struct GLTexture)); - if (!tex_cache) sys_fatal("out of memory allocating texture cache"); - - // check GL version - int vmajor, vminor; - bool is_es = false; - gl_get_version(&vmajor, &vminor, &is_es); - if (vmajor < 2 && vminor < 1 && !is_es) - sys_fatal("OpenGL 2.1+ is required.\nReported version: %s%d.%d", is_es ? "ES" : "", vmajor, vminor); - - glGenBuffers(1, &opengl_vbo); - - glBindBuffer(GL_ARRAY_BUFFER, opengl_vbo); - - glDepthFunc(GL_LEQUAL); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -} - -static void gfx_opengl_on_resize(void) { -} - -static void gfx_opengl_start_frame(void) { - frame_count++; - - glDisable(GL_SCISSOR_TEST); - glDepthMask(GL_TRUE); // Must be set to clear Z-buffer - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glEnable(GL_SCISSOR_TEST); -} - -static void gfx_opengl_end_frame(void) { -} - -static void gfx_opengl_finish_render(void) { -} - -static void gfx_opengl_shutdown(void) { -} - -struct GfxRenderingAPI gfx_opengl_api = { - gfx_opengl_z_is_from_0_to_1, - gfx_opengl_unload_shader, - gfx_opengl_load_shader, - gfx_opengl_create_and_load_new_shader, - gfx_opengl_lookup_shader, - gfx_opengl_shader_get_info, - gfx_opengl_new_texture, - gfx_opengl_select_texture, - gfx_opengl_upload_texture, - gfx_opengl_set_sampler_parameters, - gfx_opengl_set_depth_test, - gfx_opengl_set_depth_mask, - gfx_opengl_set_zmode_decal, - gfx_opengl_set_viewport, - gfx_opengl_set_scissor, - gfx_opengl_set_use_alpha, - gfx_opengl_draw_triangles, - gfx_opengl_init, - gfx_opengl_on_resize, - gfx_opengl_start_frame, - gfx_opengl_end_frame, - gfx_opengl_finish_render, - gfx_opengl_shutdown -}; - -#endif // RAPI_GL diff --git a/src/pc/gfx/gfx_opengl_legacy.c b/src/pc/gfx/gfx_opengl_legacy.c index 5f7c7daa..49cc849c 100644 --- a/src/pc/gfx/gfx_opengl_legacy.c +++ b/src/pc/gfx/gfx_opengl_legacy.c @@ -42,8 +42,9 @@ static PFNMGLFOGCOORDPOINTERPROC mglFogCoordPointer = NULL; #include "../platform.h" #include "gfx_cc.h" -#include "gfx_rendering_api.h" #include "macros.h" +#include "gfx_rendering_api.h" +#include "moon/mod-engine/hooks/hook.h" enum MixFlags { SH_MF_OVERRIDE_ALPHA = 1, @@ -567,26 +568,53 @@ static void gfx_opengl_init(void) { glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, c_white); TEXENV_COMBINE_OP(0, GL_SRC_COLOR, GL_SRC_ALPHA); TEXENV_COMBINE_OP(1, GL_SRC_COLOR, GL_SRC_ALPHA); + moon_bind_hook(GFX_INIT); + moon_init_hook(0); + moon_call_hook(0); } static void gfx_opengl_on_resize(void) { + moon_bind_hook(GFX_ON_REZISE); + moon_init_hook(0); + moon_call_hook(0); } static void gfx_opengl_start_frame(void) { + + moon_bind_hook(GFX_PRE_START_FRAME); + moon_init_hook(0); + if(moon_call_hook(0)){ + return; + } + glDisable(GL_SCISSOR_TEST); glDepthMask(GL_TRUE); // Must be set to clear Z-buffer glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_SCISSOR_TEST); + moon_bind_hook(GFX_POST_START_FRAME); + moon_init_hook(0); + moon_call_hook(0); + } static void gfx_opengl_end_frame(void) { + moon_bind_hook(GFX_PRE_END_FRAME); + moon_init_hook(0); + moon_call_hook(0); + + moon_bind_hook(GFX_POST_END_FRAME); + moon_init_hook(0); + moon_call_hook(0); } static void gfx_opengl_finish_render(void) { } static void gfx_opengl_shutdown(void) { + moon_bind_hook(GFX_SHUTDOWN); + moon_init_hook(0); + moon_call_hook(0); } struct GfxRenderingAPI gfx_opengl_api = {