diff --git a/CHANGELOG.md b/CHANGELOG.md index 39f328ec7..0dc4fedd6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ ## [Unreleased](https://github.com/rr-/Tomb1Main/compare/stable...develop) - ××××-××-×× +- added a new rendering mode called "framebuffer" that lets the game to run at lower resolutions (#114) - added the current music track and timestamp to the savegame so they now persist on load (#419) - added the triggered music tracks to the savegame so one shot tracks don't replay on load (#371) - added forward/backward input detection in line with TR2+ for jump-twists (#931) diff --git a/bin/cfg/Tomb1Main_gameflow.json5 b/bin/cfg/Tomb1Main_gameflow.json5 index bec84d42b..694322d8d 100644 --- a/bin/cfg/Tomb1Main_gameflow.json5 +++ b/bin/cfg/Tomb1Main_gameflow.json5 @@ -637,7 +637,11 @@ "DETAIL_BRIGHTNESS": "Brightness", "DETAIL_UI_TEXT_SCALE": "UI text scale", "DETAIL_UI_BAR_SCALE": "UI bar scale", + "DETAIL_RENDER_MODE": "Render mode", + "DETAIL_RENDER_MODE_LEGACY": "Window size", + "DETAIL_RENDER_MODE_FBO": "Framebuffer", "DETAIL_RESOLUTION": "Resolution", + "DETAIL_STRING_FMT": "%s", "DETAIL_FLOAT_FMT": "%.1f", "DETAIL_RESOLUTION_FMT": "%dx%d", "SOUND_SET_VOLUMES": "Set Volumes", diff --git a/bin/cfg/Tomb1Main_gameflow_ub.json5 b/bin/cfg/Tomb1Main_gameflow_ub.json5 index d3c38e3f1..2ace4b571 100644 --- a/bin/cfg/Tomb1Main_gameflow_ub.json5 +++ b/bin/cfg/Tomb1Main_gameflow_ub.json5 @@ -175,7 +175,11 @@ "DETAIL_BRIGHTNESS": "Brightness", "DETAIL_UI_TEXT_SCALE": "UI text scale", "DETAIL_UI_BAR_SCALE": "UI bar scale", + "DETAIL_RENDER_MODE": "Render mode", + "DETAIL_RENDER_MODE_LEGACY": "Window size", + "DETAIL_RENDER_MODE_FBO": "Framebuffer", "DETAIL_RESOLUTION": "Resolution", + "DETAIL_STRING_FMT": "%s", "DETAIL_FLOAT_FMT": "%.1f", "DETAIL_RESOLUTION_FMT": "%dx%d", "SOUND_SET_VOLUMES": "Set Volumes", diff --git a/bin/shaders/fbo.fsh b/bin/shaders/fbo.fsh new file mode 100644 index 000000000..6f81b3159 --- /dev/null +++ b/bin/shaders/fbo.fsh @@ -0,0 +1,9 @@ +#version 120 + +varying vec2 vertTexCoords; + +uniform sampler2D tex0; + +void main(void) { + gl_FragColor = texture2D(tex0, vertTexCoords); +} diff --git a/bin/shaders/fbo.vsh b/bin/shaders/fbo.vsh new file mode 100644 index 000000000..bd5393d2a --- /dev/null +++ b/bin/shaders/fbo.vsh @@ -0,0 +1,11 @@ +#version 120 +#extension GL_ARB_explicit_attrib_location: enable + +layout(location = 0) in vec2 inPosition; + +varying vec2 vertTexCoords; + +void main(void) { + vertTexCoords = inPosition; + gl_Position = vec4(vertTexCoords * vec2(2.0, 2.0) + vec2(-1.0, -1.0), 0.0, 1.0); +} diff --git a/meson.build b/meson.build index 9ba736528..099f2aa33 100644 --- a/meson.build +++ b/meson.build @@ -223,6 +223,7 @@ sources = [ 'src/game/stats.c', 'src/game/text.c', 'src/game/viewport.c', + 'src/gfx/fbo/fbo_renderer.c', 'src/gfx/2d/2d_renderer.c', 'src/gfx/2d/2d_surface.c', 'src/gfx/3d/3d_renderer.c', diff --git a/src/config.c b/src/config.c index db4633643..095ea407e 100644 --- a/src/config.c +++ b/src/config.c @@ -4,7 +4,6 @@ #include "game/input.h" #include "game/music.h" #include "game/sound.h" -#include "gfx/context.h" #include "global/const.h" #include "global/types.h" #include "json/json_base.h" @@ -243,6 +242,7 @@ bool Config_ReadFromJSON(const char *cfg_data) CLAMP(g_Config.camera_speed, 1, 10); // User settings + READ_INTEGER(rendering.render_mode, GFX_RM_LEGACY); READ_BOOL(rendering.enable_bilinear_filter, true); READ_BOOL(rendering.enable_perspective_filter, true); READ_BOOL(rendering.enable_vsync, true); @@ -431,6 +431,7 @@ bool Config_Write(void) WRITE_BOOL(enable_save_crystals); // User settings + WRITE_INTEGER(rendering.render_mode); WRITE_BOOL(rendering.enable_bilinear_filter); WRITE_BOOL(rendering.enable_perspective_filter); WRITE_BOOL(rendering.enable_vsync); diff --git a/src/config.h b/src/config.h index e8259b0a8..0bd1f08e4 100644 --- a/src/config.h +++ b/src/config.h @@ -1,5 +1,7 @@ #pragma once +#include "gfx/context.h" + #include #include @@ -124,6 +126,7 @@ typedef struct { } input; struct { + GFX_RENDER_MODE render_mode; bool enable_perspective_filter; bool enable_bilinear_filter; bool enable_vsync; diff --git a/src/game/gameflow.c b/src/game/gameflow.c index dcf6a71b4..b77d1d85d 100644 --- a/src/game/gameflow.c +++ b/src/game/gameflow.c @@ -78,7 +78,11 @@ static GAME_STRING_ID GameFlow_StringToGameStringID(const char *str) { "DETAIL_BRIGHTNESS", GS_DETAIL_BRIGHTNESS }, { "DETAIL_UI_TEXT_SCALE", GS_DETAIL_UI_TEXT_SCALE }, { "DETAIL_UI_BAR_SCALE", GS_DETAIL_UI_BAR_SCALE }, + { "DETAIL_RENDER_MODE", GS_DETAIL_RENDER_MODE }, + { "DETAIL_RENDER_MODE_LEGACY", GS_DETAIL_RENDER_MODE_LEGACY }, + { "DETAIL_RENDER_MODE_FBO", GS_DETAIL_RENDER_MODE_FBO }, { "DETAIL_RESOLUTION", GS_DETAIL_RESOLUTION }, + { "DETAIL_STRING_FMT", GS_DETAIL_STRING_FMT }, { "DETAIL_FLOAT_FMT", GS_DETAIL_FLOAT_FMT }, { "DETAIL_RESOLUTION_FMT", GS_DETAIL_RESOLUTION_FMT }, { "SOUND_SET_VOLUMES", GS_SOUND_SET_VOLUMES }, diff --git a/src/game/level.c b/src/game/level.c index e4003760c..36ce85859 100644 --- a/src/game/level.c +++ b/src/game/level.c @@ -783,7 +783,7 @@ bool Level_Initialise(int32_t level_num) level_num == g_GameFlow.title_level_num ? g_GameFlow.main_menu_background_path : NULL); - Output_ApplyResolution(); + Output_ApplyRenderSettings(); if (!Level_Load(g_CurrentLevel)) { return false; diff --git a/src/game/option/option_graphics.c b/src/game/option/option_graphics.c index 7dd290eae..5efa022a2 100644 --- a/src/game/option/option_graphics.c +++ b/src/game/option/option_graphics.c @@ -3,6 +3,7 @@ #include "config.h" #include "game/gameflow.h" #include "game/input.h" +#include "game/output.h" #include "game/screen.h" #include "game/text.h" #include "gfx/context.h" @@ -23,26 +24,28 @@ #define RIGHT_ARROW_OFFSET 35 typedef enum GRAPHICS_TEXT { - TEXT_PERSPECTIVE = 0, - TEXT_BILINEAR = 1, - TEXT_VSYNC = 2, - TEXT_BRIGHTNESS = 3, - TEXT_UI_TEXT_SCALE = 4, - TEXT_UI_BAR_SCALE = 5, - TEXT_RESOLUTION = 6, - TEXT_TITLE = 7, - TEXT_TITLE_BORDER = 8, - TEXT_PERSPECTIVE_TOGGLE = 9, - TEXT_BILINEAR_TOGGLE = 10, - TEXT_VSYNC_TOGGLE = 11, - TEXT_BRIGHTNESS_TOGGLE = 12, - TEXT_UI_TEXT_SCALE_TOGGLE = 13, - TEXT_UI_BAR_SCALE_TOGGLE = 14, - TEXT_RESOLUTION_TOGGLE = 15, - TEXT_LEFT_ARROW = 16, - TEXT_RIGHT_ARROW = 17, - TEXT_ROW_SELECT = 18, - TEXT_NUMBER_OF = 19, + TEXT_PERSPECTIVE, + TEXT_BILINEAR, + TEXT_VSYNC, + TEXT_BRIGHTNESS, + TEXT_UI_TEXT_SCALE, + TEXT_UI_BAR_SCALE, + TEXT_RENDER_MODE, + TEXT_RESOLUTION, + TEXT_TITLE, + TEXT_TITLE_BORDER, + TEXT_PERSPECTIVE_TOGGLE, + TEXT_BILINEAR_TOGGLE, + TEXT_VSYNC_TOGGLE, + TEXT_BRIGHTNESS_TOGGLE, + TEXT_UI_TEXT_SCALE_TOGGLE, + TEXT_UI_BAR_SCALE_TOGGLE, + TEXT_RENDER_MODE_VALUE, + TEXT_RESOLUTION_TOGGLE, + TEXT_LEFT_ARROW, + TEXT_RIGHT_ARROW, + TEXT_ROW_SELECT, + TEXT_NUMBER_OF, TEXT_EMPTY_ENTRY = -1, TEXT_OPTION_MIN = TEXT_PERSPECTIVE, TEXT_OPTION_MAX = TEXT_RESOLUTION, @@ -62,6 +65,7 @@ static const TEXT_COLUMN_PLACEMENT m_GfxTextPlacement[] = { { TEXT_BRIGHTNESS, 0, GS_DETAIL_BRIGHTNESS }, { TEXT_UI_TEXT_SCALE, 0, GS_DETAIL_UI_TEXT_SCALE }, { TEXT_UI_BAR_SCALE, 0, GS_DETAIL_UI_BAR_SCALE }, + { TEXT_RENDER_MODE, 0, GS_DETAIL_RENDER_MODE }, { TEXT_RESOLUTION, 0, GS_DETAIL_RESOLUTION }, // right column { TEXT_PERSPECTIVE_TOGGLE, 1, GS_MISC_ON }, @@ -70,6 +74,7 @@ static const TEXT_COLUMN_PLACEMENT m_GfxTextPlacement[] = { { TEXT_BRIGHTNESS_TOGGLE, 1, GS_DETAIL_FLOAT_FMT }, { TEXT_UI_TEXT_SCALE_TOGGLE, 1, GS_DETAIL_FLOAT_FMT }, { TEXT_UI_BAR_SCALE_TOGGLE, 1, GS_DETAIL_FLOAT_FMT }, + { TEXT_RENDER_MODE_VALUE, 1, GS_DETAIL_STRING_FMT }, { TEXT_RESOLUTION_TOGGLE, 1, GS_DETAIL_RESOLUTION_FMT }, // end { TEXT_EMPTY_ENTRY, -1, -1 }, @@ -144,6 +149,7 @@ static void Option_GraphicsInitText(void) Option_GraphicsChangeTextOption(TEXT_BRIGHTNESS); Option_GraphicsChangeTextOption(TEXT_UI_TEXT_SCALE); Option_GraphicsChangeTextOption(TEXT_UI_BAR_SCALE); + Option_GraphicsChangeTextOption(TEXT_RENDER_MODE); Option_GraphicsChangeTextOption(TEXT_RESOLUTION); } @@ -157,7 +163,7 @@ static void Option_GraphicsShutdownText(void) static void Option_GraphicsUpdateArrows(void) { - int16_t resolution_offset = 0; + int16_t local_right_arrow_offset = 0; switch (g_OptionSelected) { case TEXT_PERSPECTIVE: @@ -184,8 +190,13 @@ static void Option_GraphicsUpdateArrows(void) m_HideArrowLeft = g_Config.ui.bar_scale <= MIN_BAR_SCALE; m_HideArrowRight = g_Config.ui.bar_scale >= MAX_BAR_SCALE; break; + case TEXT_RENDER_MODE: + local_right_arrow_offset = 95; + m_HideArrowLeft = false; + m_HideArrowRight = false; + break; case TEXT_RESOLUTION: - resolution_offset = 70; + local_right_arrow_offset = 95; m_HideArrowLeft = !Screen_CanSetPrevRes(); m_HideArrowRight = !Screen_CanSetNextRes(); break; @@ -199,7 +210,7 @@ static void Option_GraphicsUpdateArrows(void) Text_SetPos( m_Text[TEXT_RIGHT_ARROW], m_Text[g_OptionSelected + TEXT_PERSPECTIVE_TOGGLE]->pos.x - + RIGHT_ARROW_OFFSET + resolution_offset, + + RIGHT_ARROW_OFFSET + local_right_arrow_offset, m_Text[g_OptionSelected + TEXT_PERSPECTIVE_TOGGLE]->pos.y); Text_Hide(m_Text[TEXT_LEFT_ARROW], m_HideArrowLeft); @@ -211,7 +222,7 @@ static int16_t Option_GraphicsPlaceColumns(bool create) const int16_t centre = Screen_GetResWidthDownscaled(RSR_TEXT) / 2; int16_t max_y = 0; - int16_t xs[2] = { centre - 142, centre + 30 }; + int16_t xs[2] = { centre - 142, centre }; int16_t ys[2] = { TOP_Y + ROW_HEIGHT + BORDER * 2, TOP_Y + ROW_HEIGHT + BORDER * 2 }; @@ -289,6 +300,15 @@ static void Option_GraphicsChangeTextOption(int32_t option_num) Text_ChangeText(m_Text[TEXT_UI_BAR_SCALE_TOGGLE], buf); break; + case TEXT_RENDER_MODE: + sprintf( + buf, g_GameFlow.strings[GS_DETAIL_STRING_FMT], + (g_Config.rendering.render_mode == GFX_RM_FRAMEBUFFER + ? g_GameFlow.strings[GS_DETAIL_RENDER_MODE_FBO] + : g_GameFlow.strings[GS_DETAIL_RENDER_MODE_LEGACY])); + Text_ChangeText(m_Text[TEXT_RENDER_MODE_VALUE], buf); + break; + case TEXT_RESOLUTION: sprintf( buf, g_GameFlow.strings[GS_DETAIL_RESOLUTION_FMT], @@ -362,6 +382,16 @@ void Option_Graphics(INVENTORY_ITEM *inv_item) reset = TEXT_UI_BAR_SCALE; break; + case TEXT_RENDER_MODE: + if (g_Config.rendering.render_mode == GFX_RM_LEGACY) { + g_Config.rendering.render_mode = GFX_RM_FRAMEBUFFER; + } else { + g_Config.rendering.render_mode = GFX_RM_LEGACY; + } + Output_ApplyRenderSettings(); + reset = TEXT_RENDER_MODE; + break; + case TEXT_RESOLUTION: if (Screen_SetNextRes()) { reset = TEXT_NUMBER_OF; @@ -414,6 +444,16 @@ void Option_Graphics(INVENTORY_ITEM *inv_item) reset = TEXT_UI_BAR_SCALE; break; + case TEXT_RENDER_MODE: + if (g_Config.rendering.render_mode == GFX_RM_LEGACY) { + g_Config.rendering.render_mode = GFX_RM_FRAMEBUFFER; + } else { + g_Config.rendering.render_mode = GFX_RM_LEGACY; + } + Output_ApplyRenderSettings(); + reset = TEXT_RENDER_MODE; + break; + case TEXT_RESOLUTION: if (Screen_SetPrevRes()) { reset = TEXT_NUMBER_OF; diff --git a/src/game/output.c b/src/game/output.c index eeed95f57..781a44911 100644 --- a/src/game/output.c +++ b/src/game/output.c @@ -384,9 +384,9 @@ void Output_Shutdown(void) Memory_FreePointer(&m_BackdropImagePath); } -void Output_SetViewport(int width, int height) +void Output_SetWindowSize(int width, int height) { - S_Output_SetViewport(width, height); + S_Output_SetWindowSize(width, height); } void Output_SetFullscreen(bool fullscreen) @@ -394,9 +394,9 @@ void Output_SetFullscreen(bool fullscreen) S_Output_SetFullscreen(fullscreen); } -void Output_ApplyResolution(void) +void Output_ApplyRenderSettings(void) { - S_Output_ApplyResolution(); + S_Output_ApplyRenderSettings(); if (m_BackdropImagePath) { Output_LoadBackdropImage(m_BackdropImagePath); } @@ -600,9 +600,9 @@ void Output_DrawShadow(int16_t size, int16_t *bptr, ITEM_INFO *item) PHD_VBUF *vn2 = &m_VBuf[g_Config.enable_round_shadow ? 4 : 1]; PHD_VBUF *vn3 = &m_VBuf[g_Config.enable_round_shadow ? 8 : 2]; - bool visible = - ((int32_t)(((vn3->xs - vn2->xs) * (vn1->ys - vn2->ys)) - ((vn1->xs - vn2->xs) * (vn3->ys - vn2->ys))) - >= 0); + int32_t c1 = (vn3->xs - vn2->xs) * (vn1->ys - vn2->ys); + int32_t c2 = (vn1->xs - vn2->xs) * (vn3->ys - vn2->ys); + bool visible = (int32_t)(c1 - c2) >= 0; if (!clip_and && clip_positive && visible) { S_Output_DrawShadow( diff --git a/src/game/output.h b/src/game/output.h index 91e08c783..77257d7a3 100644 --- a/src/game/output.h +++ b/src/game/output.h @@ -8,9 +8,9 @@ bool Output_Init(void); void Output_Shutdown(void); -void Output_SetViewport(int width, int height); +void Output_SetWindowSize(int width, int height); void Output_SetFullscreen(bool fullscreen); -void Output_ApplyResolution(void); +void Output_ApplyRenderSettings(void); void Output_DownloadTextures(int page_count); RGBA8888 Output_RGB2RGBA(const RGB888 color); diff --git a/src/game/screen.c b/src/game/screen.c index b25b88b00..222725ca2 100644 --- a/src/game/screen.c +++ b/src/game/screen.c @@ -39,7 +39,7 @@ static void Screen_ApplyResolution(void) int32_t height = Screen_GetResHeight(); Viewport_Init(width, height); - Output_ApplyResolution(); + Output_ApplyRenderSettings(); Matrix_ResetStack(); Viewport_AlterFOV(g_Config.fov_value * PHD_DEGREE); diff --git a/src/game/sound.c b/src/game/sound.c index 3d7221f41..bc899099d 100644 --- a/src/game/sound.c +++ b/src/game/sound.c @@ -4,15 +4,14 @@ #include "game/random.h" #include "game/room.h" #include "game/shell.h" +#include "global/const.h" #include "global/vars.h" -#include "log.h" #include "math/math.h" #include "specific/s_audio.h" #include "util.h" #include #include -#include #define MAX_PLAYING_FX AUDIO_MAX_ACTIVE_SAMPLES #define MAX_AMBIENT_FX 8 diff --git a/src/gfx/2d/2d_renderer.c b/src/gfx/2d/2d_renderer.c index 6359a10db..b0ec9d5c1 100644 --- a/src/gfx/2d/2d_renderer.c +++ b/src/gfx/2d/2d_renderer.c @@ -2,9 +2,15 @@ #include "gfx/gl/gl_core_3_3.h" #include "gfx/gl/utils.h" +#include "log.h" + +#include void GFX_2D_Renderer_Init(GFX_2D_Renderer *renderer) { + LOG_INFO(""); + assert(renderer); + GFX_GL_Buffer_Init(&renderer->surface_buffer, GL_ARRAY_BUFFER); GFX_GL_Buffer_Bind(&renderer->surface_buffer); GLfloat verts[] = { 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, @@ -43,6 +49,9 @@ void GFX_2D_Renderer_Init(GFX_2D_Renderer *renderer) void GFX_2D_Renderer_Close(GFX_2D_Renderer *renderer) { + LOG_INFO(""); + assert(renderer); + GFX_GL_VertexArray_Close(&renderer->surface_format); GFX_GL_Buffer_Close(&renderer->surface_buffer); GFX_GL_Texture_Close(&renderer->surface_texture); @@ -69,10 +78,12 @@ void GFX_2D_Renderer_Upload( glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, renderer->width, renderer->height, 0, tex_format, tex_type, data); + GFX_GL_CheckError(); } else { glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, renderer->width, renderer->height, tex_format, tex_type, data); + GFX_GL_CheckError(); } } @@ -95,6 +106,7 @@ void GFX_2D_Renderer_Render(GFX_2D_Renderer *renderer) } glDrawArrays(GL_TRIANGLES, 0, 6); + GFX_GL_CheckError(); if (blend) { glEnable(GL_BLEND); @@ -103,6 +115,4 @@ void GFX_2D_Renderer_Render(GFX_2D_Renderer *renderer) if (depth_test) { glEnable(GL_DEPTH_TEST); } - - GFX_GL_CheckError(); } diff --git a/src/gfx/2d/2d_surface.c b/src/gfx/2d/2d_surface.c index 565267e5f..e094dfd58 100644 --- a/src/gfx/2d/2d_surface.c +++ b/src/gfx/2d/2d_surface.c @@ -163,9 +163,6 @@ bool GFX_2D_Surface_Flip(GFX_2D_Surface *surface) GFX_Context_SwapBuffers(); } - // update viewport in case the window size has changed - GFX_Context_SetupViewport(); - // render surface GFX_2D_Renderer_Render(surface->renderer); diff --git a/src/gfx/3d/3d_renderer.c b/src/gfx/3d/3d_renderer.c index c8957c09a..6a7494ead 100644 --- a/src/gfx/3d/3d_renderer.c +++ b/src/gfx/3d/3d_renderer.c @@ -29,7 +29,9 @@ static void GFX_3D_Renderer_SelectTextureImpl( void GFX_3D_Renderer_Init(GFX_3D_Renderer *renderer) { + LOG_INFO(""); assert(renderer); + // TODO: make me configurable renderer->wireframe = false; renderer->selected_texture_num = GFX_NO_TEXTURE; @@ -82,7 +84,9 @@ void GFX_3D_Renderer_Init(GFX_3D_Renderer *renderer) void GFX_3D_Renderer_Close(GFX_3D_Renderer *renderer) { + LOG_INFO(""); assert(renderer); + GFX_3D_VertexStream_Close(&renderer->vertex_stream); GFX_GL_Program_Close(&renderer->program); GFX_GL_Sampler_Close(&renderer->sampler); @@ -96,6 +100,7 @@ void GFX_3D_Renderer_RenderBegin(GFX_3D_Renderer *renderer) if (renderer->wireframe) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); } + GFX_GL_CheckError(); GFX_GL_Program_Bind(&renderer->program); GFX_3D_VertexStream_Bind(&renderer->vertex_stream); @@ -124,7 +129,6 @@ void GFX_3D_Renderer_RenderBegin(GFX_3D_Renderer *renderer) glDepthFunc(GL_LEQUAL); glDepthMask(GL_TRUE); glEnable(GL_DEPTH_TEST); - GFX_GL_CheckError(); } @@ -143,6 +147,7 @@ void GFX_3D_Renderer_RenderEnd(GFX_3D_Renderer *renderer) void GFX_3D_Renderer_ClearDepth(GFX_3D_Renderer *renderer) { glClear(GL_DEPTH_BUFFER_BIT); + GFX_GL_CheckError(); } int GFX_3D_Renderer_TextureReg( @@ -151,8 +156,7 @@ int GFX_3D_Renderer_TextureReg( assert(renderer); assert(data); GFX_GL_Texture *texture = GFX_GL_Texture_Create(GL_TEXTURE_2D); - GFX_GL_Texture_Bind(texture); - GFX_GL_Texture_Load(texture, data, width, height); + GFX_GL_Texture_Load(texture, data, width, height, GL_RGBA, GL_BGRA); int texture_num = GFX_NO_TEXTURE; for (int i = 0; i < GFX_MAX_TEXTURES; i++) { diff --git a/src/gfx/3d/vertex_stream.c b/src/gfx/3d/vertex_stream.c index 4e1473c03..d844bf1ae 100644 --- a/src/gfx/3d/vertex_stream.c +++ b/src/gfx/3d/vertex_stream.c @@ -154,7 +154,6 @@ void GFX_3D_VertexStream_RenderPending(GFX_3D_VertexStream *vertex_stream) glDrawArrays( GL_PRIM_MODES[vertex_stream->prim_type], 0, vertex_stream->pending_vertices.count); - GFX_GL_CheckError(); vertex_stream->pending_vertices.count = 0; diff --git a/src/gfx/context.c b/src/gfx/context.c index 7d6f0f68e..785cb4bed 100644 --- a/src/gfx/context.c +++ b/src/gfx/context.c @@ -1,6 +1,5 @@ #include "gfx/context.h" -#include "config.h" #include "game/shell.h" #include "gfx/gl/gl_core_3_3.h" #include "gfx/gl/utils.h" @@ -8,39 +7,46 @@ #include "log.h" #include "memory.h" -#include +#include #include -typedef struct GFX_Context { +typedef struct GFX_CONTEXT { SDL_GLContext context; SDL_Window *window_handle; - bool is_fullscreen; // fullscreen flag - bool is_rendered; // rendering flag + GFX_RENDER_MODE render_mode; int32_t display_width; int32_t display_height; - int32_t screen_width; - int32_t screen_height; int32_t window_width; int32_t window_height; + + bool is_fullscreen; // fullscreen flag + bool is_rendered; // rendering flag char *scheduled_screenshot_path; + GFX_FBO_Renderer renderer_fbo; GFX_2D_Renderer renderer_2d; GFX_3D_Renderer renderer_3d; -} GFX_Context; +} GFX_CONTEXT; -static GFX_Context m_Context = { 0 }; +static GFX_CONTEXT m_Context = { 0 }; static bool GFX_Context_IsExtensionSupported(const char *name); static void GFX_Context_CheckExtensionSupport(const char *name); +static void GFX_Context_SwitchToWindowViewport(void); +static void GFX_Context_SwitchToWindowViewportAR(void); +static void GFX_Context_SwitchToDisplayViewport(void); static bool GFX_Context_IsExtensionSupported(const char *name) { int number_of_extensions; glGetIntegerv(GL_NUM_EXTENSIONS, &number_of_extensions); + GFX_GL_CheckError(); for (int i = 0; i < number_of_extensions; i++) { const char *gl_ext = (const char *)glGetStringi(GL_EXTENSIONS, i); + GFX_GL_CheckError(); + if (gl_ext && !strcmp(gl_ext, name)) { return true; } @@ -55,6 +61,47 @@ static void GFX_Context_CheckExtensionSupport(const char *name) GFX_Context_IsExtensionSupported(name) ? "yes" : "no"); } +static void GFX_Context_SwitchToWindowViewport(void) +{ + glViewport(0, 0, m_Context.window_width, m_Context.window_height); + GFX_GL_CheckError(); +} + +static void GFX_Context_SwitchToWindowViewportAR(void) +{ + // switch to window viewport at the aspect ratio of the display viewport + int vp_width = m_Context.window_width; + int vp_height = m_Context.window_height; + + // default to bottom left corner of the window + int vp_x = 0; + int vp_y = 0; + + int hw = m_Context.display_height * vp_width; + int wh = m_Context.display_width * vp_height; + + // create viewport offset if the window has a different + // aspect ratio than the current display mode + if (hw > wh) { + int max_w = wh / m_Context.display_height; + vp_x = (vp_width - max_w) / 2; + vp_width = max_w; + } else if (hw < wh) { + int max_h = hw / m_Context.display_width; + vp_y = (vp_height - max_h) / 2; + vp_height = max_h; + } + + glViewport(vp_x, vp_y, vp_width, vp_height); + GFX_GL_CheckError(); +} + +static void GFX_Context_SwitchToDisplayViewport(void) +{ + glViewport(0, 0, m_Context.display_width, m_Context.display_height); + GFX_GL_CheckError(); +} + void GFX_Context_Attach(void *window_handle) { const char *shading_ver; @@ -65,6 +112,12 @@ void GFX_Context_Attach(void *window_handle) LOG_INFO("Attaching to window %p", window_handle); + m_Context.render_mode = -1; + m_Context.window_width = 800; + m_Context.window_height = 600; + m_Context.display_width = 800; + m_Context.display_height = 600; + m_Context.window_handle = window_handle; m_Context.context = SDL_GL_CreateContext(m_Context.window_handle); @@ -90,16 +143,9 @@ void GFX_Context_Attach(void *window_handle) GFX_Context_CheckExtensionSupport("GL_ARB_explicit_attrib_location"); GFX_Context_CheckExtensionSupport("GL_EXT_gpu_shader4"); - // get screen dimensions - SDL_DisplayMode DM; - - SDL_GetDesktopDisplayMode(0, &DM); - m_Context.screen_width = DM.w; - m_Context.screen_height = DM.h; - LOG_INFO("GetDesktopDisplayMode=%dx%d", DM.w, DM.h); - glClearColor(0, 0, 0, 0); glClearDepth(1); + GFX_GL_CheckError(); // VSync defaults to on unless user disabled it in runtime json SDL_GL_SetSwapInterval(1); @@ -114,6 +160,9 @@ void GFX_Context_Detach(void) return; } + if (m_Context.render_mode == GFX_RM_FRAMEBUFFER) { + GFX_FBO_Renderer_Close(&m_Context.renderer_fbo); + } GFX_2D_Renderer_Close(&m_Context.renderer_2d); GFX_3D_Renderer_Close(&m_Context.renderer_3d); @@ -150,9 +199,39 @@ void GFX_Context_SetWindowSize(int32_t width, int32_t height) void GFX_Context_SetDisplaySize(int32_t width, int32_t height) { + if (width == m_Context.display_width + && height == m_Context.display_height) { + return; + } + LOG_INFO("Display size: %dx%d", width, height); + if (width <= 0 || height <= 0) { + LOG_INFO("invalid size, ignoring"); + return; + } + m_Context.display_width = width; m_Context.display_height = height; + if (m_Context.render_mode == GFX_RM_FRAMEBUFFER) { + GFX_FBO_Renderer_Close(&m_Context.renderer_fbo); + GFX_FBO_Renderer_Init(&m_Context.renderer_fbo); + } +} + +void GFX_Context_SetRenderingMode(GFX_RENDER_MODE target_mode) +{ + GFX_RENDER_MODE current_mode = m_Context.render_mode; + if (current_mode == target_mode) { + return; + } + + LOG_INFO("Render mode: %d", target_mode); + if (current_mode == GFX_RM_FRAMEBUFFER) { + GFX_FBO_Renderer_Close(&m_Context.renderer_fbo); + } else if (target_mode == GFX_RM_FRAMEBUFFER) { + GFX_FBO_Renderer_Init(&m_Context.renderer_fbo); + } + m_Context.render_mode = target_mode; } int32_t GFX_Context_GetDisplayWidth(void) @@ -165,69 +244,47 @@ int32_t GFX_Context_GetDisplayHeight(void) return m_Context.display_height; } -int32_t GFX_Context_GetWindowWidth(void) -{ - return m_Context.window_width ? m_Context.window_width - : m_Context.display_width; -} - -int32_t GFX_Context_GetWindowHeight(void) -{ - return m_Context.window_height ? m_Context.window_height - : m_Context.display_height; -} - -int32_t GFX_Context_GetScreenWidth(void) -{ - return m_Context.screen_width; -} - -int32_t GFX_Context_GetScreenHeight(void) -{ - return m_Context.screen_height; -} - -void GFX_Context_SetupViewport(void) -{ - int vp_width = m_Context.window_width; - int vp_height = m_Context.window_height; - - // default to bottom left corner of the window - int vp_x = 0; - int vp_y = 0; - - int hw = m_Context.display_height * vp_width; - int wh = m_Context.display_width * vp_height; - - // create viewport offset if the window has a different - // aspect ratio than the current display mode - if (hw > wh) { - int max_w = wh / m_Context.display_height; - vp_x = (vp_width - max_w) / 2; - vp_width = max_w; - } else if (hw < wh) { - int max_h = hw / m_Context.display_width; - vp_y = (vp_height - max_h) / 2; - vp_height = max_h; - } - - glViewport(vp_x, vp_y, vp_width, vp_height); -} - void GFX_Context_SwapBuffers(void) { glFinish(); + GFX_GL_CheckError(); - if (m_Context.scheduled_screenshot_path) { - GFX_Screenshot_CaptureToFile(m_Context.scheduled_screenshot_path); - Memory_FreePointer(&m_Context.scheduled_screenshot_path); + switch (m_Context.render_mode) { + case GFX_RM_FRAMEBUFFER: + if (m_Context.scheduled_screenshot_path) { + GFX_Screenshot_CaptureToFile(m_Context.scheduled_screenshot_path); + Memory_FreePointer(&m_Context.scheduled_screenshot_path); + } + + GFX_Context_SwitchToWindowViewportAR(); + GFX_FBO_Renderer_Render(&m_Context.renderer_fbo); + + SDL_GL_SwapWindow(m_Context.window_handle); + + GFX_Context_SwitchToWindowViewport(); + GFX_FBO_Renderer_Unbind(&m_Context.renderer_fbo); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + GFX_GL_CheckError(); + + GFX_FBO_Renderer_Bind(&m_Context.renderer_fbo); + GFX_Context_SwitchToDisplayViewport(); + break; + + case GFX_RM_LEGACY: + GFX_Context_SwitchToWindowViewportAR(); + if (m_Context.scheduled_screenshot_path) { + GFX_Screenshot_CaptureToFile(m_Context.scheduled_screenshot_path); + Memory_FreePointer(&m_Context.scheduled_screenshot_path); + } + + SDL_GL_SwapWindow(m_Context.window_handle); + + glDrawBuffer(GL_BACK); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + GFX_GL_CheckError(); + break; } - SDL_GL_SwapWindow(m_Context.window_handle); - - glDrawBuffer(GL_BACK); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - m_Context.is_rendered = false; } @@ -243,6 +300,7 @@ bool GFX_Context_IsRendered(void) void GFX_Context_ScheduleScreenshot(const char *path) { + Memory_FreePointer(&m_Context.scheduled_screenshot_path); m_Context.scheduled_screenshot_path = Memory_DupStr(path); } @@ -255,3 +313,8 @@ GFX_3D_Renderer *GFX_Context_GetRenderer3D(void) { return &m_Context.renderer_3d; } + +GFX_FBO_Renderer *GFX_Context_GetRendererFBO(void) +{ + return &m_Context.renderer_fbo; +} diff --git a/src/gfx/context.h b/src/gfx/context.h index 07ce208c6..4528d3b48 100644 --- a/src/gfx/context.h +++ b/src/gfx/context.h @@ -2,11 +2,17 @@ #include "gfx/2d/2d_renderer.h" #include "gfx/3d/3d_renderer.h" +#include "gfx/fbo/fbo_renderer.h" #include #include -typedef struct GFX_Context GFX_Context; +typedef struct GFX_CONTEXT GFX_CONTEXT; + +typedef enum GFX_RENDER_MODE { + GFX_RM_LEGACY, + GFX_RM_FRAMEBUFFER, +} GFX_RENDER_MODE; void GFX_Context_Attach(void *window_handle); void GFX_Context_Detach(void); @@ -15,16 +21,13 @@ bool GFX_Context_IsFullscreen(void); void GFX_Context_SetFullscreen(bool fullscreen); void GFX_Context_SetWindowSize(int32_t width, int32_t height); void GFX_Context_SetDisplaySize(int32_t width, int32_t height); +void GFX_Context_SetRenderingMode(GFX_RENDER_MODE target_mode); int32_t GFX_Context_GetDisplayWidth(void); int32_t GFX_Context_GetDisplayHeight(void); -int32_t GFX_Context_GetWindowWidth(void); -int32_t GFX_Context_GetWindowHeight(void); -int32_t GFX_Context_GetScreenWidth(void); -int32_t GFX_Context_GetScreenHeight(void); -void GFX_Context_SetupViewport(void); void GFX_Context_SwapBuffers(void); void GFX_Context_SetRendered(void); bool GFX_Context_IsRendered(void); void GFX_Context_ScheduleScreenshot(const char *path); GFX_2D_Renderer *GFX_Context_GetRenderer2D(void); GFX_3D_Renderer *GFX_Context_GetRenderer3D(void); +GFX_FBO_Renderer *GFX_Context_GetRendererFBO(void); diff --git a/src/gfx/fbo/fbo_renderer.c b/src/gfx/fbo/fbo_renderer.c new file mode 100644 index 000000000..f1adb3a12 --- /dev/null +++ b/src/gfx/fbo/fbo_renderer.c @@ -0,0 +1,165 @@ +#include "gfx/fbo/fbo_renderer.h" + +#include "gfx/context.h" +#include "gfx/gl/utils.h" +#include "log.h" + +#include +#include +#include + +void GFX_FBO_Renderer_Init(GFX_FBO_Renderer *renderer) +{ + LOG_INFO(""); + assert(renderer); + + int32_t fbo_width = GFX_Context_GetDisplayWidth(); + int32_t fbo_height = GFX_Context_GetDisplayHeight(); + + GFX_GL_Buffer_Init(&renderer->buffer, GL_ARRAY_BUFFER); + GFX_GL_Buffer_Bind(&renderer->buffer); + GLfloat verts[] = { 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, + 0.0, 1.0, 1.0, 0.0, 1.0, 1.0 }; + GFX_GL_Buffer_Data(&renderer->buffer, sizeof(verts), verts, GL_STATIC_DRAW); + + GFX_GL_VertexArray_Init(&renderer->vertex_array); + GFX_GL_VertexArray_Bind(&renderer->vertex_array); + GFX_GL_VertexArray_Attribute( + &renderer->vertex_array, 0, 2, GL_FLOAT, GL_FALSE, 0, 0); + + GFX_GL_Texture_Init(&renderer->texture, GL_TEXTURE_2D); + + GFX_GL_Sampler_Init(&renderer->sampler); + GFX_GL_Sampler_Bind(&renderer->sampler, 0); + GFX_GL_Sampler_Parameteri( + &renderer->sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + GFX_GL_Sampler_Parameteri( + &renderer->sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + GFX_GL_Sampler_Parameteri( + &renderer->sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + GFX_GL_Sampler_Parameteri( + &renderer->sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + + GFX_GL_Program_Init(&renderer->program); + GFX_GL_Program_AttachShader( + &renderer->program, GL_VERTEX_SHADER, "shaders/fbo.vsh"); + GFX_GL_Program_AttachShader( + &renderer->program, GL_FRAGMENT_SHADER, "shaders/fbo.fsh"); + GFX_GL_Program_Link(&renderer->program); + GFX_GL_Program_FragmentData(&renderer->program, "fragColor"); + + glGenFramebuffers(1, &renderer->fbo); + GFX_GL_CheckError(); + + glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo); + GFX_GL_CheckError(); + + GFX_GL_Texture_Load( + &renderer->texture, NULL, fbo_width, fbo_height, GL_RGB, GL_RGB); + + glFramebufferTexture2D( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + renderer->texture.id, 0); + GFX_GL_CheckError(); + + glGenRenderbuffers(1, &renderer->rbo); + GFX_GL_CheckError(); + + glBindRenderbuffer(GL_RENDERBUFFER, renderer->rbo); + GFX_GL_CheckError(); + + glRenderbufferStorage( + GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, fbo_width, fbo_height); + GFX_GL_CheckError(); + + glBindRenderbuffer(GL_RENDERBUFFER, 0); + GFX_GL_CheckError(); + + glFramebufferRenderbuffer( + GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, + renderer->rbo); + GFX_GL_CheckError(); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + LOG_ERROR("framebuffer is not complete!"); + } +} + +void GFX_FBO_Renderer_Close(GFX_FBO_Renderer *renderer) +{ + LOG_INFO(""); + assert(renderer); + if (!renderer->fbo) { + return; + } + glDeleteFramebuffers(1, &renderer->fbo); + renderer->fbo = 0; + GFX_GL_VertexArray_Close(&renderer->vertex_array); + GFX_GL_Buffer_Close(&renderer->buffer); + GFX_GL_Texture_Close(&renderer->texture); + GFX_GL_Sampler_Close(&renderer->sampler); + GFX_GL_Program_Close(&renderer->program); +} + +void GFX_FBO_Renderer_Render(GFX_FBO_Renderer *renderer) +{ + assert(renderer); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + GFX_GL_CheckError(); + + GFX_GL_Program_Bind(&renderer->program); + GFX_GL_Buffer_Bind(&renderer->buffer); + GFX_GL_VertexArray_Bind(&renderer->vertex_array); + GFX_GL_Texture_Bind(&renderer->texture); + GFX_GL_Sampler_Bind(&renderer->sampler, 0); + + GFX_GL_Sampler_Parameteri( + &renderer->sampler, GL_TEXTURE_MAG_FILTER, + renderer->is_smoothing_enabled ? GL_LINEAR : GL_NEAREST); + GFX_GL_Sampler_Parameteri( + &renderer->sampler, GL_TEXTURE_MIN_FILTER, + renderer->is_smoothing_enabled ? GL_LINEAR : GL_NEAREST); + + GLboolean blend = glIsEnabled(GL_BLEND); + if (blend) { + glDisable(GL_BLEND); + } + + GLboolean depth_test = glIsEnabled(GL_DEPTH_TEST); + if (depth_test) { + glDisable(GL_DEPTH_TEST); + } + + glDrawArrays(GL_TRIANGLES, 0, 6); + GFX_GL_CheckError(); + + if (blend) { + glEnable(GL_BLEND); + } + + if (depth_test) { + glEnable(GL_DEPTH_TEST); + } + GFX_GL_CheckError(); + + glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo); + GFX_GL_CheckError(); +} + +void GFX_FBO_Renderer_SetSmoothingEnabled( + GFX_FBO_Renderer *renderer, bool is_enabled) +{ + assert(renderer); + renderer->is_smoothing_enabled = is_enabled; +} + +void GFX_FBO_Renderer_Bind(const GFX_FBO_Renderer *renderer) +{ + glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo); +} + +void GFX_FBO_Renderer_Unbind(const GFX_FBO_Renderer *renderer) +{ + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} diff --git a/src/gfx/fbo/fbo_renderer.h b/src/gfx/fbo/fbo_renderer.h new file mode 100644 index 000000000..85aac0abc --- /dev/null +++ b/src/gfx/fbo/fbo_renderer.h @@ -0,0 +1,32 @@ +#pragma once + +#include "gfx/gl/buffer.h" +#include "gfx/gl/gl_core_3_3.h" +#include "gfx/gl/program.h" +#include "gfx/gl/sampler.h" +#include "gfx/gl/texture.h" +#include "gfx/gl/vertex_array.h" + +#include +#include + +typedef struct GFX_FBO_Renderer { + GLuint fbo; + GLuint rbo; + + bool is_smoothing_enabled; + + GFX_GL_VertexArray vertex_array; + GFX_GL_Buffer buffer; + GFX_GL_Texture texture; + GFX_GL_Sampler sampler; + GFX_GL_Program program; +} GFX_FBO_Renderer; + +void GFX_FBO_Renderer_Init(GFX_FBO_Renderer *renderer); +void GFX_FBO_Renderer_Close(GFX_FBO_Renderer *renderer); +void GFX_FBO_Renderer_Render(GFX_FBO_Renderer *renderer); +void GFX_FBO_Renderer_SetSmoothingEnabled( + GFX_FBO_Renderer *renderer, bool is_enabled); +void GFX_FBO_Renderer_Bind(const GFX_FBO_Renderer *renderer); +void GFX_FBO_Renderer_Unbind(const GFX_FBO_Renderer *renderer); diff --git a/src/gfx/gl/buffer.c b/src/gfx/gl/buffer.c index 706cc4caa..c1a1fb8c4 100644 --- a/src/gfx/gl/buffer.c +++ b/src/gfx/gl/buffer.c @@ -1,5 +1,7 @@ #include "gfx/gl/buffer.h" +#include "gfx/gl/utils.h" + #include void GFX_GL_Buffer_Init(GFX_GL_Buffer *buf, GLenum target) @@ -7,18 +9,21 @@ void GFX_GL_Buffer_Init(GFX_GL_Buffer *buf, GLenum target) assert(buf); buf->target = target; glGenBuffers(1, &buf->id); + GFX_GL_CheckError(); } void GFX_GL_Buffer_Close(GFX_GL_Buffer *buf) { assert(buf); glDeleteBuffers(1, &buf->id); + GFX_GL_CheckError(); } void GFX_GL_Buffer_Bind(GFX_GL_Buffer *buf) { assert(buf); glBindBuffer(buf->target, buf->id); + GFX_GL_CheckError(); } void GFX_GL_Buffer_Data( @@ -26,6 +31,7 @@ void GFX_GL_Buffer_Data( { assert(buf); glBufferData(buf->target, size, data, usage); + GFX_GL_CheckError(); } void GFX_GL_Buffer_SubData( @@ -33,18 +39,22 @@ void GFX_GL_Buffer_SubData( { assert(buf); glBufferSubData(buf->target, offset, size, data); + GFX_GL_CheckError(); } void *GFX_GL_Buffer_Map(GFX_GL_Buffer *buf, GLenum access) { assert(buf); - return glMapBuffer(buf->target, access); + void *ret = glMapBuffer(buf->target, access); + GFX_GL_CheckError(); + return ret; } void GFX_GL_Buffer_Unmap(GFX_GL_Buffer *buf) { assert(buf); glUnmapBuffer(buf->target); + GFX_GL_CheckError(); } GLint GFX_GL_Buffer_Parameter(GFX_GL_Buffer *buf, GLenum pname) @@ -52,5 +62,6 @@ GLint GFX_GL_Buffer_Parameter(GFX_GL_Buffer *buf, GLenum pname) assert(buf); GLint params = 0; glGetBufferParameteriv(buf->target, pname, ¶ms); + GFX_GL_CheckError(); return params; } diff --git a/src/gfx/gl/program.c b/src/gfx/gl/program.c index a911ee57e..f425088b9 100644 --- a/src/gfx/gl/program.c +++ b/src/gfx/gl/program.c @@ -2,6 +2,7 @@ #include "filesystem.h" #include "game/shell.h" +#include "gfx/gl/utils.h" #include "log.h" #include "memory.h" @@ -12,6 +13,7 @@ bool GFX_GL_Program_Init(GFX_GL_Program *program) { assert(program); program->id = glCreateProgram(); + GFX_GL_CheckError(); if (!program->id) { LOG_ERROR("Can't create shader program"); return false; @@ -23,6 +25,7 @@ void GFX_GL_Program_Close(GFX_GL_Program *program) { if (program->id) { glDeleteProgram(program->id); + GFX_GL_CheckError(); program->id = 0; } } @@ -30,12 +33,14 @@ void GFX_GL_Program_Close(GFX_GL_Program *program) void GFX_GL_Program_Bind(GFX_GL_Program *program) { glUseProgram(program->id); + GFX_GL_CheckError(); } void GFX_GL_Program_AttachShader( GFX_GL_Program *program, GLenum type, const char *path) { GLuint shader_id = glCreateShader(type); + GFX_GL_CheckError(); if (!shader_id) { Shell_ExitSystem("Failed to create shader"); } @@ -46,14 +51,21 @@ void GFX_GL_Program_AttachShader( } glShaderSource(shader_id, 1, (const char **)&content, NULL); + + GFX_GL_CheckError(); glCompileShader(shader_id); + GFX_GL_CheckError(); int compile_status; glGetShaderiv(shader_id, GL_COMPILE_STATUS, &compile_status); + GFX_GL_CheckError(); + if (compile_status != GL_TRUE) { GLsizei info_log_size = 4096; char info_log[info_log_size]; glGetShaderInfoLog(shader_id, info_log_size, &info_log_size, info_log); + GFX_GL_CheckError(); + if (info_log[0]) { Shell_ExitSystemFmt("Shader compilation failed:\n%s", info_log); } else { @@ -62,21 +74,29 @@ void GFX_GL_Program_AttachShader( } Memory_FreePointer(&content); + glAttachShader(program->id, shader_id); + GFX_GL_CheckError(); + glDeleteShader(shader_id); + GFX_GL_CheckError(); } void GFX_GL_Program_Link(GFX_GL_Program *program) { glLinkProgram(program->id); + GFX_GL_CheckError(); GLint linkStatus; glGetProgramiv(program->id, GL_LINK_STATUS, &linkStatus); + GFX_GL_CheckError(); + if (!linkStatus) { GLsizei info_log_size = 4096; char info_log[info_log_size]; glGetProgramInfoLog( program->id, info_log_size, &info_log_size, info_log); + GFX_GL_CheckError(); if (info_log[0]) { Shell_ExitSystemFmt("Shader linking failed:\n%s", info_log); } else { @@ -88,11 +108,13 @@ void GFX_GL_Program_Link(GFX_GL_Program *program) void GFX_GL_Program_FragmentData(GFX_GL_Program *program, const char *name) { glBindFragDataLocation(program->id, 0, name); + GFX_GL_CheckError(); } GLint GFX_GL_Program_UniformLocation(GFX_GL_Program *program, const char *name) { GLint location = glGetUniformLocation(program->id, name); + GFX_GL_CheckError(); if (location == -1) { LOG_INFO("Shader uniform not found: %s", name); } @@ -103,6 +125,7 @@ void GFX_GL_Program_Uniform3f( GFX_GL_Program *program, GLint loc, GLfloat v0, GLfloat v1, GLfloat v2) { glUniform3f(loc, v0, v1, v2); + GFX_GL_CheckError(); } void GFX_GL_Program_Uniform4f( @@ -110,11 +133,13 @@ void GFX_GL_Program_Uniform4f( GLfloat v3) { glUniform4f(loc, v0, v1, v2, v3); + GFX_GL_CheckError(); } void GFX_GL_Program_Uniform1i(GFX_GL_Program *program, GLint loc, GLint v0) { glUniform1i(loc, v0); + GFX_GL_CheckError(); } void GFX_GL_Program_UniformMatrix4fv( @@ -122,4 +147,5 @@ void GFX_GL_Program_UniformMatrix4fv( const GLfloat *value) { glUniformMatrix4fv(loc, count, transpose, value); + GFX_GL_CheckError(); } diff --git a/src/gfx/gl/sampler.c b/src/gfx/gl/sampler.c index d0b4aeb0e..fc940e91b 100644 --- a/src/gfx/gl/sampler.c +++ b/src/gfx/gl/sampler.c @@ -1,28 +1,35 @@ #include "gfx/gl/sampler.h" +#include "gfx/gl/utils.h" + void GFX_GL_Sampler_Init(GFX_GL_Sampler *sampler) { glGenSamplers(1, &sampler->id); + GFX_GL_CheckError(); } void GFX_GL_Sampler_Close(GFX_GL_Sampler *sampler) { glDeleteSamplers(1, &sampler->id); + GFX_GL_CheckError(); } void GFX_GL_Sampler_Bind(GFX_GL_Sampler *sampler, GLuint unit) { glBindSampler(unit, sampler->id); + GFX_GL_CheckError(); } void GFX_GL_Sampler_Parameteri( GFX_GL_Sampler *sampler, GLenum pname, GLint param) { glSamplerParameteri(sampler->id, pname, param); + GFX_GL_CheckError(); } void GFX_GL_Sampler_Parameterf( GFX_GL_Sampler *sampler, GLenum pname, GLfloat param) { glSamplerParameterf(sampler->id, pname, param); + GFX_GL_CheckError(); } diff --git a/src/gfx/gl/texture.c b/src/gfx/gl/texture.c index 32986ebd9..46bea5f85 100644 --- a/src/gfx/gl/texture.c +++ b/src/gfx/gl/texture.c @@ -25,32 +25,36 @@ void GFX_GL_Texture_Init(GFX_GL_Texture *texture, GLenum target) assert(texture); texture->target = target; glGenTextures(1, &texture->id); + GFX_GL_CheckError(); } void GFX_GL_Texture_Close(GFX_GL_Texture *texture) { assert(texture); glDeleteTextures(1, &texture->id); + GFX_GL_CheckError(); } void GFX_GL_Texture_Bind(GFX_GL_Texture *texture) { assert(texture); glBindTexture(texture->target, texture->id); + GFX_GL_CheckError(); } void GFX_GL_Texture_Load( - GFX_GL_Texture *texture, const void *data, int width, int height) + GFX_GL_Texture *texture, const void *data, int width, int height, + GLint internal_format, GLint format) { assert(texture); - assert(data); - - glTexImage2D( - GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, - data); GFX_GL_Texture_Bind(texture); - glGenerateMipmap(GL_TEXTURE_2D); + glTexImage2D( + GL_TEXTURE_2D, 0, internal_format, width, height, 0, format, + GL_UNSIGNED_BYTE, data); + GFX_GL_CheckError(); + + glGenerateMipmap(GL_TEXTURE_2D); GFX_GL_CheckError(); } diff --git a/src/gfx/gl/texture.h b/src/gfx/gl/texture.h index c3272d56b..a64a7ef2a 100644 --- a/src/gfx/gl/texture.h +++ b/src/gfx/gl/texture.h @@ -14,4 +14,5 @@ void GFX_GL_Texture_Init(GFX_GL_Texture *texture, GLenum target); void GFX_GL_Texture_Close(GFX_GL_Texture *texture); void GFX_GL_Texture_Bind(GFX_GL_Texture *texture); void GFX_GL_Texture_Load( - GFX_GL_Texture *texture, const void *data, int width, int height); + GFX_GL_Texture *texture, const void *data, int width, int height, + GLint internal_format, GLint format); diff --git a/src/gfx/gl/vertex_array.c b/src/gfx/gl/vertex_array.c index 9088d616e..ac4f9fbb8 100644 --- a/src/gfx/gl/vertex_array.c +++ b/src/gfx/gl/vertex_array.c @@ -1,23 +1,28 @@ #include "gfx/gl/vertex_array.h" +#include "gfx/gl/utils.h" + #include void GFX_GL_VertexArray_Init(GFX_GL_VertexArray *array) { assert(array); glGenVertexArrays(1, &array->id); + GFX_GL_CheckError(); } void GFX_GL_VertexArray_Close(GFX_GL_VertexArray *array) { assert(array); glDeleteVertexArrays(1, &array->id); + GFX_GL_CheckError(); } void GFX_GL_VertexArray_Bind(GFX_GL_VertexArray *array) { assert(array); glBindVertexArray(array->id); + GFX_GL_CheckError(); } void GFX_GL_VertexArray_Attribute( @@ -26,6 +31,9 @@ void GFX_GL_VertexArray_Attribute( { assert(array); glEnableVertexAttribArray(index); + GFX_GL_CheckError(); + glVertexAttribPointer( index, size, type, normalized, stride, (void *)offset); + GFX_GL_CheckError(); } diff --git a/src/global/types.h b/src/global/types.h index 63aa9b95f..6b42ae8bd 100644 --- a/src/global/types.h +++ b/src/global/types.h @@ -1034,7 +1034,11 @@ typedef enum GAME_STRING_ID { GS_DETAIL_BRIGHTNESS, GS_DETAIL_UI_TEXT_SCALE, GS_DETAIL_UI_BAR_SCALE, + GS_DETAIL_RENDER_MODE, + GS_DETAIL_RENDER_MODE_LEGACY, + GS_DETAIL_RENDER_MODE_FBO, GS_DETAIL_RESOLUTION, + GS_DETAIL_STRING_FMT, GS_DETAIL_FLOAT_FMT, GS_DETAIL_RESOLUTION_FMT, diff --git a/src/specific/s_audio_sample.c b/src/specific/s_audio_sample.c index 41c47767d..a54719e84 100644 --- a/src/specific/s_audio_sample.c +++ b/src/specific/s_audio_sample.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/src/specific/s_audio_stream.c b/src/specific/s_audio_stream.c index eb8597ca3..59652b51c 100644 --- a/src/specific/s_audio_stream.c +++ b/src/specific/s_audio_stream.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/src/specific/s_filesystem.c b/src/specific/s_filesystem.c index 7c06c5c74..3862a23f4 100644 --- a/src/specific/s_filesystem.c +++ b/src/specific/s_filesystem.c @@ -7,6 +7,7 @@ #include #include #include +#include #if defined(_WIN32) #include diff --git a/src/specific/s_fmv.c b/src/specific/s_fmv.c index bf17bb046..68fedb693 100644 --- a/src/specific/s_fmv.c +++ b/src/specific/s_fmv.c @@ -42,7 +42,6 @@ #include #include #include -#include #include #include #include @@ -53,6 +52,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include @@ -2241,7 +2244,7 @@ static void S_FMV_EventLoop(VideoState *is) is->width = event.window.data1; is->height = event.window.data2; is->force_refresh = true; - Output_SetViewport(event.window.data1, event.window.data2); + Output_SetWindowSize(event.window.data1, event.window.data2); break; case SDL_WINDOWEVENT_EXPOSED: @@ -2312,7 +2315,7 @@ cleanup: S_Audio_Init(); - S_Output_ApplyResolution(); + S_Output_ApplyRenderSettings(); return ret; } diff --git a/src/specific/s_input.c b/src/specific/s_input.c index eb3f6f00b..7e5b00e3b 100644 --- a/src/specific/s_input.c +++ b/src/specific/s_input.c @@ -1,6 +1,5 @@ #include "specific/s_input.h" -#include "game/input.h" #include "log.h" #include diff --git a/src/specific/s_output.c b/src/specific/s_output.c index 106df4109..285bb8884 100644 --- a/src/specific/s_output.c +++ b/src/specific/s_output.c @@ -11,6 +11,7 @@ #include "gfx/3d/vertex_stream.h" #include "gfx/blitter.h" #include "gfx/context.h" +#include "gfx/fbo/fbo_renderer.h" #include "global/vars.h" #include "log.h" #include "specific/s_shell.h" @@ -30,6 +31,8 @@ static int m_TextureMap[GFX_MAX_TEXTURES] = { GFX_NO_TEXTURE }; static RGB888 m_ColorPalette[256]; +static GFX_FBO_Renderer *m_RendererFBO = NULL; + static GFX_3D_Renderer *m_Renderer3D = NULL; static bool m_IsPaletteActive = false; static bool m_IsRendering = false; @@ -78,6 +81,8 @@ static void S_Output_SetupRenderContextAndRender(void) S_Output_RenderBegin(); GFX_3D_Renderer_SetSmoothingEnabled( m_Renderer3D, g_Config.rendering.enable_bilinear_filter); + GFX_FBO_Renderer_SetSmoothingEnabled( + m_RendererFBO, g_Config.rendering.enable_bilinear_filter); S_Output_RenderToggle(); } @@ -916,7 +921,7 @@ void S_Output_DrawShadow(PHD_VBUF *vbufs, int clip, int vertex_count) GFX_3D_Renderer_SetBlendingEnabled(m_Renderer3D, false); } -void S_Output_ApplyResolution(void) +void S_Output_ApplyRenderSettings(void) { S_Output_ReleaseSurfaces(); @@ -928,6 +933,7 @@ void S_Output_ApplyResolution(void) m_SurfaceMaxY = Screen_GetResHeight() - 1.0f; GFX_Context_SetDisplaySize(m_SurfaceWidth, m_SurfaceHeight); + GFX_Context_SetRenderingMode(g_Config.rendering.render_mode); { GFX_2D_SurfaceDesc surface_desc = { @@ -955,7 +961,7 @@ void S_Output_ApplyResolution(void) S_Output_SetupRenderContextAndRender(); } -void S_Output_SetViewport(int width, int height) +void S_Output_SetWindowSize(int width, int height) { GFX_Context_SetWindowSize(width, height); } @@ -974,8 +980,9 @@ bool S_Output_Init(void) GFX_Context_Attach(S_Shell_GetWindowHandle()); m_Renderer3D = GFX_Context_GetRenderer3D(); + m_RendererFBO = GFX_Context_GetRendererFBO(); - S_Output_ApplyResolution(); + S_Output_ApplyRenderSettings(); GFX_3D_Renderer_SetPrimType(m_Renderer3D, GFX_3D_PRIM_TRI); @@ -988,6 +995,7 @@ void S_Output_Shutdown(void) S_Output_ReleaseSurfaces(); GFX_Context_Detach(); m_Renderer3D = NULL; + m_RendererFBO = NULL; } void S_Output_DrawFlatTriangle( diff --git a/src/specific/s_output.h b/src/specific/s_output.h index 0ff80d53d..3bc03f3b3 100644 --- a/src/specific/s_output.h +++ b/src/specific/s_output.h @@ -21,9 +21,9 @@ void S_Output_DumpScreen(void); void S_Output_ClearDepthBuffer(void); void S_Output_DrawEmpty(void); -void S_Output_SetViewport(int width, int height); +void S_Output_SetWindowSize(int width, int height); void S_Output_SetFullscreen(bool fullscreen); -void S_Output_ApplyResolution(void); +void S_Output_ApplyRenderSettings(void); void S_Output_SetPalette(RGB888 palette[256]); RGB888 S_Output_GetPaletteColor(uint8_t idx); diff --git a/src/specific/s_picture.c b/src/specific/s_picture.c index f1761ef34..c9a69db58 100644 --- a/src/specific/s_picture.c +++ b/src/specific/s_picture.c @@ -8,6 +8,9 @@ #include #include #include +#include +#include +#include #include #include #include diff --git a/src/specific/s_shell.c b/src/specific/s_shell.c index 266027544..d38236a07 100644 --- a/src/specific/s_shell.c +++ b/src/specific/s_shell.c @@ -10,14 +10,23 @@ #include "log.h" #include "memory.h" -#include - #define SDL_MAIN_HANDLED #ifdef _WIN32 + #include #include #endif #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include static int m_ArgCount = 0; @@ -40,7 +49,7 @@ static void S_Shell_PostWindowResize(void) int width; int height; SDL_GetWindowSize(m_Window, &width, &height); - Output_SetViewport(width, height); + Output_SetWindowSize(width, height); } void S_Shell_ShowFatalError(const char *message) @@ -107,7 +116,7 @@ void S_Shell_SpinMessageLoop(void) break; case SDL_WINDOWEVENT_RESIZED: { - Output_SetViewport(event.window.data1, event.window.data2); + Output_SetWindowSize(event.window.data1, event.window.data2); break; } }