From 3f75e5d504077cb29d87561acba3e0268e03f3c9 Mon Sep 17 00:00:00 2001 From: Alex <7569514+ManDude@users.noreply.github.com> Date: Tue, 7 Oct 2025 21:53:16 +0100 Subject: [PATCH] Add support for brightness and contrast modifiers (#4041) --- game/graphics/gfx.h | 4 +++ game/graphics/opengl_renderer/Fbo.h | 2 +- .../opengl_renderer/OpenGLRenderer.cpp | 23 +++++++++++++-- .../graphics/opengl_renderer/OpenGLRenderer.h | 9 +++++- .../shaders/post_processing.frag | 13 ++++----- .../shaders/post_processing.vert | 4 +-- game/graphics/pipelines/opengl.cpp | 6 ++++ game/kernel/common/kmachine.cpp | 6 ++++ goal_src/jak1/kernel-defs.gc | 2 ++ goal_src/jak2/kernel-defs.gc | 1 + goal_src/jak3/engine/gfx/blit-displays.gc | 29 +++++++++++++++---- goal_src/jak3/kernel-defs.gc | 1 + 12 files changed, 80 insertions(+), 20 deletions(-) diff --git a/game/graphics/gfx.h b/game/graphics/gfx.h index 90362807e3..5571931555 100644 --- a/game/graphics/gfx.h +++ b/game/graphics/gfx.h @@ -67,6 +67,10 @@ struct GfxGlobalSettings { // multi-sampled anti-aliasing sample count. 1 = disabled. int msaa_samples = 1; + // brightness and contrast values set from GOAL (see jak 3) + int brightness_contrast_color = 0; + int brightness_contrast_alpha = 128; + // current renderer const GfxRendererModule* renderer; diff --git a/game/graphics/opengl_renderer/Fbo.h b/game/graphics/opengl_renderer/Fbo.h index a372c3ca98..146393e6a3 100644 --- a/game/graphics/opengl_renderer/Fbo.h +++ b/game/graphics/opengl_renderer/Fbo.h @@ -48,4 +48,4 @@ struct Fbo { valid = false; } } -}; \ No newline at end of file +}; diff --git a/game/graphics/opengl_renderer/OpenGLRenderer.cpp b/game/graphics/opengl_renderer/OpenGLRenderer.cpp index 62c27ccd7f..99f62d687c 100644 --- a/game/graphics/opengl_renderer/OpenGLRenderer.cpp +++ b/game/graphics/opengl_renderer/OpenGLRenderer.cpp @@ -1024,11 +1024,13 @@ void OpenGLRenderer::render(DmaFollower dma, const RenderOptions& settings) { blit_display(prof); } - // apply effects done with PCRTC registers + // apply effects done with PCRTC registers, as well as blit the framebuffer to the window and + // apply brightness/contrast { g_current_renderer = "pcrtc"; auto prof = m_profiler.root()->make_scoped_child("pcrtc"); - do_pcrtc_effects(settings.pmode_alp_register, &m_render_state, prof); + do_pcrtc_effects(settings.pmode_alp_register, settings.brightness_contrast_color, + settings.brightness_contrast_alpha, &m_render_state, prof); if (settings.gpu_sync) { glFinish(); } @@ -1610,6 +1612,8 @@ void OpenGLRenderer::finish_screenshot(const std::string& output_name, } void OpenGLRenderer::do_pcrtc_effects(float alp, + int brightness_contrast_color, + int brightness_contrast_alpha, SharedRenderState* render_state, ScopedProfilerNode& prof) { Fbo* window_blit_src = nullptr; @@ -1642,9 +1646,22 @@ void OpenGLRenderer::do_pcrtc_effects(float alp, glBindVertexArray(screen_vao); glBindBuffer(GL_ARRAY_BUFFER, screen_vbo); - auto& shader = render_state->shaders[ShaderId::PLAIN_TEXTURE]; + float color = (float)brightness_contrast_color / 128.0f; + float alpha = (float)brightness_contrast_alpha / 128.0f; + auto& shader = render_state->shaders[ShaderId::POST_PROCESSING]; shader.activate(); glUniform1i(glGetUniformLocation(shader.id(), "tex_T0"), 0); + if (brightness_contrast_color < 0) { + // subtractive blend - note that color is already negative + float color_neg = color * alpha; + glUniform4f(glGetUniformLocation(shader.id(), "color_mult"), 1.0f, 1.0f, 1.0f, alpha); + glUniform4f(glGetUniformLocation(shader.id(), "color_add"), color_neg, color_neg, color_neg, + 0.0f); + } else { + // additive blend + glUniform4f(glGetUniformLocation(shader.id(), "color_mult"), 1.0f, 1.0f, 1.0f, alpha); + glUniform4f(glGetUniformLocation(shader.id(), "color_add"), color, color, color, 0.0f); + } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glActiveTexture(GL_TEXTURE0); diff --git a/game/graphics/opengl_renderer/OpenGLRenderer.h b/game/graphics/opengl_renderer/OpenGLRenderer.h index 709c7e6cc1..6867110519 100644 --- a/game/graphics/opengl_renderer/OpenGLRenderer.h +++ b/game/graphics/opengl_renderer/OpenGLRenderer.h @@ -48,6 +48,9 @@ struct RenderOptions { float pmode_alp_register = 1.f; + int brightness_contrast_color = 0; // 0 - no change + int brightness_contrast_alpha = 128; // 128 - no change + // when enabled, does a `glFinish()` after each major rendering pass. This blocks until the GPU // is done working, making it easier to profile GPU utilization. bool gpu_sync = false; @@ -78,7 +81,11 @@ class OpenGLRenderer { void dispatch_buckets_jak2(DmaFollower dma, ScopedProfilerNode& prof, bool sync_after_buckets); void dispatch_buckets_jak3(DmaFollower dma, ScopedProfilerNode& prof, bool sync_after_buckets); - void do_pcrtc_effects(float alp, SharedRenderState* render_state, ScopedProfilerNode& prof); + void do_pcrtc_effects(float alp, + int brightness_contrast_color, + int brightness_contrast_alpha, + SharedRenderState* render_state, + ScopedProfilerNode& prof); void blit_display(ScopedProfilerNode& prof); void init_bucket_renderers_jak1(); void init_bucket_renderers_jak2(); diff --git a/game/graphics/opengl_renderer/shaders/post_processing.frag b/game/graphics/opengl_renderer/shaders/post_processing.frag index 7dc89e4cab..b68f2624e1 100644 --- a/game/graphics/opengl_renderer/shaders/post_processing.frag +++ b/game/graphics/opengl_renderer/shaders/post_processing.frag @@ -1,13 +1,12 @@ #version 410 core -in vec2 screen_pos; - -out vec4 color; - -uniform vec4 fragment_color; - uniform sampler2D tex_T0; +out vec4 color; +in vec2 tex_coord; + +uniform vec4 color_mult; +uniform vec4 color_add; void main() { - color = vec4(texture(tex_T0, screen_pos).rgb * fragment_color.a, 1.0); + color = vec4(texture(tex_T0, tex_coord).rgb * color_mult.rgb * color_mult.a, 1.0) + color_add; } diff --git a/game/graphics/opengl_renderer/shaders/post_processing.vert b/game/graphics/opengl_renderer/shaders/post_processing.vert index 4570bba8c7..de2668ed7e 100644 --- a/game/graphics/opengl_renderer/shaders/post_processing.vert +++ b/game/graphics/opengl_renderer/shaders/post_processing.vert @@ -2,9 +2,9 @@ layout (location = 0) in vec2 position_in; -out vec2 screen_pos; +out vec2 tex_coord; void main() { gl_Position = vec4(position_in, 0, 1.0); - screen_pos = (position_in + 1) / 2; + tex_coord = (position_in + vec2(1.0, 1.0)) * 0.5; } diff --git a/game/graphics/pipelines/opengl.cpp b/game/graphics/pipelines/opengl.cpp index c9582dd7f1..324d07c91c 100644 --- a/game/graphics/pipelines/opengl.cpp +++ b/game/graphics/pipelines/opengl.cpp @@ -398,6 +398,8 @@ void render_game_frame(int game_width, int draw_region_width, int draw_region_height, int msaa_samples, + int brightness_contrast_color, + int brightness_contrast_alpha, bool take_screenshot) { // wait for a copied chain. bool got_chain = false; @@ -419,6 +421,8 @@ void render_game_frame(int game_width, options.draw_region_width = draw_region_width; options.draw_region_height = draw_region_height; options.msaa_samples = msaa_samples; + options.brightness_contrast_color = brightness_contrast_color; + options.brightness_contrast_alpha = brightness_contrast_alpha; options.draw_render_debug_window = g_gfx_data->debug_gui.should_draw_render_debug(); options.draw_profiler_window = g_gfx_data->debug_gui.should_draw_profiler(); options.draw_loader_window = g_gfx_data->debug_gui.should_draw_loader_menu(); @@ -572,6 +576,8 @@ void GLDisplay::render() { render_game_frame( game_res_w, game_res_h, fbuf_w, fbuf_h, Gfx::g_global_settings.lbox_w, Gfx::g_global_settings.lbox_h, Gfx::g_global_settings.msaa_samples, + Gfx::g_global_settings.brightness_contrast_color, + Gfx::g_global_settings.brightness_contrast_alpha, m_take_screenshot_next_frame && g_gfx_data->debug_gui.screenshot_hotkey_enabled); // If we took a screenshot, stop taking them now! if (m_take_screenshot_next_frame) { diff --git a/game/kernel/common/kmachine.cpp b/game/kernel/common/kmachine.cpp index f775cca88d..67f5cd8cb2 100644 --- a/game/kernel/common/kmachine.cpp +++ b/game/kernel/common/kmachine.cpp @@ -916,6 +916,11 @@ void pc_set_letterbox(int w, int h) { Gfx::g_global_settings.lbox_h = h; } +void pc_set_brightness_contrast(s32 color, s32 alpha) { + Gfx::g_global_settings.brightness_contrast_color = color; + Gfx::g_global_settings.brightness_contrast_alpha = alpha; +} + void pc_renderer_tree_set_lod(Gfx::RendererTreeType tree, int lod) { switch (tree) { case Gfx::RendererTreeType::TFRAG3: @@ -1108,6 +1113,7 @@ void init_common_pc_port_functions( make_func_symbol_func("pc-set-msaa", (void*)pc_set_msaa); make_func_symbol_func("pc-set-frame-rate", (void*)pc_set_frame_rate); make_func_symbol_func("pc-set-game-resolution", (void*)pc_set_game_resolution); + make_func_symbol_func("pc-set-brightness-contrast", (void*)pc_set_brightness_contrast); make_func_symbol_func("pc-set-letterbox", (void*)pc_set_letterbox); make_func_symbol_func("pc-renderer-tree-set-lod", (void*)pc_renderer_tree_set_lod); make_func_symbol_func("pc-set-collision-mode", (void*)Gfx::CollisionRendererSetMode); diff --git a/goal_src/jak1/kernel-defs.gc b/goal_src/jak1/kernel-defs.gc index d6feb0f594..53b5629f3d 100644 --- a/goal_src/jak1/kernel-defs.gc +++ b/goal_src/jak1/kernel-defs.gc @@ -564,6 +564,8 @@ (define-extern pc-set-game-resolution (function int int none)) +(define-extern pc-set-brightness-contrast (function int int none)) + (define-extern pc-set-msaa (function int none)) (define-extern pc-set-gfx-hack (function pc-gfx-hack symbol none)) diff --git a/goal_src/jak2/kernel-defs.gc b/goal_src/jak2/kernel-defs.gc index 213f221baf..4da2b9c3f0 100644 --- a/goal_src/jak2/kernel-defs.gc +++ b/goal_src/jak2/kernel-defs.gc @@ -263,6 +263,7 @@ (define-extern pc-sound-set-fade-hack (function int none)) (define-extern pc-set-window-lock (function symbol none)) (define-extern pc-set-game-resolution (function int int none)) +(define-extern pc-set-brightness-contrast (function int int none)) (define-extern pc-set-msaa (function int none)) (define-extern pc-set-gfx-hack (function pc-gfx-hack symbol none)) (define-extern pc-get-unix-timestamp (function int)) diff --git a/goal_src/jak3/engine/gfx/blit-displays.gc b/goal_src/jak3/engine/gfx/blit-displays.gc index f45c893156..94fbfaa21a 100644 --- a/goal_src/jak3/engine/gfx/blit-displays.gc +++ b/goal_src/jak3/engine/gfx/blit-displays.gc @@ -614,13 +614,30 @@ ;; in-place draw on rasterization buffer to apply brightness and contrast. Added to almost ;; the last bucket, so it applies to HUD too. + ;; this type of full-screen draw is done at the end of rendering a frame on PC port, so we just pass the parameters required for it instead (let ((v1-3 (-> *setting-control* user-current))) - (when (or (!= (-> v1-3 contrast) 0.5) (!= (-> v1-3 brightness) 0.5)) - (with-dma-buffer-add-bucket ((s4-0 (-> *display* frames (-> *display* on-screen) global-buf)) - (bucket-id debug-menu) - ) - (draw-brightness-and-contrast this s4-0 (-> v1-3 brightness) (-> v1-3 contrast)) - (reset-display-gs-state *display* s4-0) + (#cond + ((not PC_PORT) + (when (or (!= (-> v1-3 contrast) 0.5) (!= (-> v1-3 brightness) 0.5)) + (with-dma-buffer-add-bucket ((s4-0 (-> *display* frames (-> *display* on-screen) global-buf)) + (bucket-id debug-menu) + ) + (draw-brightness-and-contrast this s4-0 (-> v1-3 brightness) (-> v1-3 contrast)) + (reset-display-gs-state *display* s4-0) + ) + ) + ) + (#t + ;; og:preserve-this always calculate contrast and brightness and pass it to display settings + (let ((contrast (fmax 0.0 (fmin 1.0 (-> v1-3 contrast)))) + (brightness (fmax 0.0 (fmin 1.0 (-> v1-3 brightness)))) + ) + (let ((bc-color (the int (* 64.2509 (+ (- 0.5 contrast) (* 2.0 (fmax 0.0 (+ -0.5 brightness))))))) + (bc-alpha (the int (fmin 255.0 (* 256.0 (fmin 1.0 (* 2.0 brightness)) contrast)))) + ) + (pc-set-brightness-contrast bc-color bc-alpha) + ) + ) ) ) ) diff --git a/goal_src/jak3/kernel-defs.gc b/goal_src/jak3/kernel-defs.gc index ba9dbeb2b4..0ec03dff10 100644 --- a/goal_src/jak3/kernel-defs.gc +++ b/goal_src/jak3/kernel-defs.gc @@ -263,6 +263,7 @@ (define-extern pc-sound-set-fade-hack (function int none)) (define-extern pc-set-window-lock (function symbol none)) (define-extern pc-set-game-resolution (function int int none)) +(define-extern pc-set-brightness-contrast (function int int none)) (define-extern pc-set-msaa (function int none)) (define-extern pc-set-gfx-hack (function pc-gfx-hack symbol none)) (define-extern pc-get-unix-timestamp (function int))