From 572efbf9cb25d8d0854889c92d88e2ac3072f0ff Mon Sep 17 00:00:00 2001 From: Hat Kid <6624576+Hat-Kid@users.noreply.github.com> Date: Sat, 9 Sep 2023 16:59:00 +0200 Subject: [PATCH] jak2: add frame rate option to graphics menu (#2962) This PR adds a frame rate option to the graphics menu for some of the most common refresh rates. Jak 2 has much better support for variable frame rates than Jak 1 out of the box, but there are still some edge cases, most prominently the fact that sprites are still limited to the 300 tick system, which is most noticeable on glow sprites. For this, I abused the glow boost debug setting to scale the glow based on the frame rate. While testing, I noticed two other cases that I have also patched, there's likely to be many more that are yet to be found, but aside from that, the game is playable as normal. https://github.com/open-goal/jak-project/assets/6624576/ad4db24f-cd27-4237-a155-0db7008160f3 --- decompiler/config/jak2/all-types.gc | 1 + .../jak2/text/game_custom_text_en-US.json | 3 +- .../opengl_renderer/sprite/GlowRenderer.cpp | 5 ++ .../opengl_renderer/sprite/GlowRenderer.h | 2 + goal_src/jak2/engine/gfx/hw/display.gc | 4 ++ goal_src/jak2/engine/gfx/hw/video.gc | 4 ++ .../jak2/engine/target/board/board-states.gc | 3 +- goal_src/jak2/engine/target/target-anim.gc | 3 +- goal_src/jak2/engine/ui/text-id-h.gc | 1 + goal_src/jak2/kernel/gkernel-h.gc | 8 +++ goal_src/jak2/pc/debug/default-menu-pc.gc | 15 ++++-- goal_src/jak2/pc/features/speedruns.gc | 1 + goal_src/jak2/pc/progress/progress-draw-pc.gc | 43 +++++++++++++++ goal_src/jak2/pc/progress/progress-h-pc.gc | 3 ++ goal_src/jak2/pc/progress/progress-pc.gc | 52 ++++++++++++++++++- .../jak2/pc/progress/progress-static-pc.gc | 2 + 16 files changed, 141 insertions(+), 9 deletions(-) diff --git a/decompiler/config/jak2/all-types.gc b/decompiler/config/jak2/all-types.gc index 6ece65edda..267fbd3c34 100644 --- a/decompiler/config/jak2/all-types.gc +++ b/decompiler/config/jak2/all-types.gc @@ -7362,6 +7362,7 @@ (progress-lod-low #x128b) (progress-lod-high #x128c) (progress-credits #x128d) + (progress-frame-rate #x128e) ) ;; ---text-id-h:text-id diff --git a/game/assets/jak2/text/game_custom_text_en-US.json b/game/assets/jak2/text/game_custom_text_en-US.json index ef549324c2..872b6e4b3b 100644 --- a/game/assets/jak2/text/game_custom_text_en-US.json +++ b/game/assets/jak2/text/game_custom_text_en-US.json @@ -120,5 +120,6 @@ "128a": "Default", "128b": "Low", "128c": "High", - "128d": "Credits" + "128d": "Credits", + "128e": "Frame Rate (Experimental)" } diff --git a/game/graphics/opengl_renderer/sprite/GlowRenderer.cpp b/game/graphics/opengl_renderer/sprite/GlowRenderer.cpp index 0f837196c4..34263b83d9 100644 --- a/game/graphics/opengl_renderer/sprite/GlowRenderer.cpp +++ b/game/graphics/opengl_renderer/sprite/GlowRenderer.cpp @@ -550,6 +550,7 @@ void GlowRenderer::blit_depth(SharedRenderState* render_state) { void GlowRenderer::draw_debug_window() { ImGui::Checkbox("Show Probes", &m_debug.show_probes); ImGui::Checkbox("Show Copy", &m_debug.show_probe_copies); + ImGui::Checkbox("Enable Glow Boost", &m_debug.enable_glow_boost); ImGui::SliderFloat("Boost Glow", &m_debug.glow_boost, 0, 10); ImGui::Text("Count: %d", m_debug.num_sprites); } @@ -808,6 +809,10 @@ void GlowRenderer::draw_sprites(SharedRenderState* render_state, ScopedProfilerN glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); render_state->shaders[ShaderId::GLOW_DRAW].activate(); + if (!m_debug.enable_glow_boost && Gfx::g_global_settings.target_fps > 60.0f) { + // on higher framerates, more glow sprites are drawn, so we scale the boost a bit + m_debug.glow_boost = 60.0f / Gfx::g_global_settings.target_fps; + } glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::GLOW_DRAW].id(), "glow_boost"), m_debug.glow_boost); diff --git a/game/graphics/opengl_renderer/sprite/GlowRenderer.h b/game/graphics/opengl_renderer/sprite/GlowRenderer.h index ed00367703..af1b355e74 100644 --- a/game/graphics/opengl_renderer/sprite/GlowRenderer.h +++ b/game/graphics/opengl_renderer/sprite/GlowRenderer.h @@ -1,5 +1,6 @@ #pragma once +#include "game/graphics/gfx.h" #include "game/graphics/opengl_renderer/sprite/sprite_common.h" class GlowRenderer { @@ -27,6 +28,7 @@ class GlowRenderer { struct { bool show_probes = false; bool show_probe_copies = false; + bool enable_glow_boost = false; int num_sprites = 0; float glow_boost = 1.f; } m_debug; diff --git a/goal_src/jak2/engine/gfx/hw/display.gc b/goal_src/jak2/engine/gfx/hw/display.gc index 7f336a83a8..c2db344666 100644 --- a/goal_src/jak2/engine/gfx/hw/display.gc +++ b/goal_src/jak2/engine/gfx/hw/display.gc @@ -34,6 +34,10 @@ (('pal) (set! (-> obj time-factor) 6.0) ) + ;; pc port note: added custom video mode for high fps + (('custom) + (set! (-> obj time-factor) (/ 300.0 (-> *pc-settings* target-fps))) + ) (else (set! (-> obj time-factor) 5.0) ) diff --git a/goal_src/jak2/engine/gfx/hw/video.gc b/goal_src/jak2/engine/gfx/hw/video.gc index c409b0a04c..72adec2261 100644 --- a/goal_src/jak2/engine/gfx/hw/video.gc +++ b/goal_src/jak2/engine/gfx/hw/video.gc @@ -33,6 +33,10 @@ Will also set a bunch of common settings related to profiling and the camera to (set! *video-mode* 1) (sound-set-fps 50) ) + ;; pc port note: added custom case + (('custom) + (sound-set-fps (-> *pc-settings* target-fps)) + ) ) (set-time-ratios *display* (-> *display* dog-ratio)) (set! (-> *video-params* reset-video-mode) #t) diff --git a/goal_src/jak2/engine/target/board/board-states.gc b/goal_src/jak2/engine/target/board/board-states.gc index a0f394fa7f..b29af61c46 100644 --- a/goal_src/jak2/engine/target/board/board-states.gc +++ b/goal_src/jak2/engine/target/board/board-states.gc @@ -188,7 +188,8 @@ (if (not (-> self control danger-mode)) (target-danger-set! 'board-spin #f) ) - (+! (-> self board trotyv) (* (-> self board spin-control) (-> self clock seconds-per-frame))) + ;; pc port note: patched for high fps + (+! (-> self board trotyv) (* (-> self board spin-control) (seconds-per-frame))) (when (and (< (fabs f28-0) 1092266.6) (< (fabs (-> self board spin-control)) 1092266.6) (< (* 0.9 (fabs (-> self board flip-control))) (fabs f30-0)) diff --git a/goal_src/jak2/engine/target/target-anim.gc b/goal_src/jak2/engine/target/target-anim.gc index f9a417da61..8d5057db51 100644 --- a/goal_src/jak2/engine/target/target-anim.gc +++ b/goal_src/jak2/engine/target/target-anim.gc @@ -919,7 +919,8 @@ ) (until (ja-done? 0) (suspend) - (ja :num! (seek! max (/ (* (fmax 20480.0 (-> self control ctrl-xz-vel)) (-> self clock seconds-per-frame)) + ;; pc port note: patched for high fps + (ja :num! (seek! max (/ (* (fmax 20480.0 (-> self control ctrl-xz-vel)) (seconds-per-frame)) (/ (-> *TARGET-bank* run-up-cycle-dist) (-> *TARGET-bank* run-cycle-length)) ) ) diff --git a/goal_src/jak2/engine/ui/text-id-h.gc b/goal_src/jak2/engine/ui/text-id-h.gc index 4eeea92824..532da27af1 100644 --- a/goal_src/jak2/engine/ui/text-id-h.gc +++ b/goal_src/jak2/engine/ui/text-id-h.gc @@ -690,6 +690,7 @@ (progress-lod-low #x128b) (progress-lod-high #x128c) (progress-credits #x128d) + (progress-frame-rate #x128e) ) ;; ---text-id diff --git a/goal_src/jak2/kernel/gkernel-h.gc b/goal_src/jak2/kernel/gkernel-h.gc index 0e8e7adec9..37a2ed12e8 100644 --- a/goal_src/jak2/kernel/gkernel-h.gc +++ b/goal_src/jak2/kernel/gkernel-h.gc @@ -763,3 +763,11 @@ (defmacro current-time () `(-> PP clock frame-counter) ) + +(defmacro seconds-per-frame () + "Macro for assuming a 16.6 ms frame time at higher frame rates." + `(if (= (get-video-mode) 'custom) + 0.016666668 + (-> PP clock seconds-per-frame) + ) + ) diff --git a/goal_src/jak2/pc/debug/default-menu-pc.gc b/goal_src/jak2/pc/debug/default-menu-pc.gc index 4f4530f948..cad004cbac 100644 --- a/goal_src/jak2/pc/debug/default-menu-pc.gc +++ b/goal_src/jak2/pc/debug/default-menu-pc.gc @@ -882,11 +882,16 @@ (set! (-> *pc-settings* lod-force-actor) 3) )) ) - ;; (menu "Framerate" - ;; (flag "60" 60 dm-frame-rate-pick-func) - ;; (flag "100" 100 dm-frame-rate-pick-func) - ;; (flag "150" 150 dm-frame-rate-pick-func) - ;; ) + (menu "Framerate" + (flag "30" 30 dm-frame-rate-pick-func) + (flag "50" 50 dm-frame-rate-pick-func) + (flag "60" 60 dm-frame-rate-pick-func) + (flag "75" 75 dm-frame-rate-pick-func) + (flag "120" 120 dm-frame-rate-pick-func) + (flag "144" 144 dm-frame-rate-pick-func) + (flag "165" 165 dm-frame-rate-pick-func) + (flag "240" 240 dm-frame-rate-pick-func) + ) (menu "MSAA" (flag "Off" 1 dm-msaa-pick-func) (flag "x2" 2 dm-msaa-pick-func) diff --git a/goal_src/jak2/pc/features/speedruns.gc b/goal_src/jak2/pc/features/speedruns.gc index 7c645e9545..fcb859b58e 100644 --- a/goal_src/jak2/pc/features/speedruns.gc +++ b/goal_src/jak2/pc/features/speedruns.gc @@ -18,6 +18,7 @@ (when category (set! (-> *speedrun-info* category) category)) ;; TODO - ensure any required settings are enabled + (set-frame-rate! *pc-settings* 60 #t) (none) ) diff --git a/goal_src/jak2/pc/progress/progress-draw-pc.gc b/goal_src/jak2/pc/progress/progress-draw-pc.gc index e06d895d30..4bc2b87c90 100644 --- a/goal_src/jak2/pc/progress/progress-draw-pc.gc +++ b/goal_src/jak2/pc/progress/progress-draw-pc.gc @@ -2084,6 +2084,49 @@ (none) ) +(defmethod draw-option menu-frame-rate-option ((obj menu-frame-rate-option) (arg0 progress) (arg1 font-context) (arg2 int) (arg3 symbol)) + (let ((alpha (* 2.0 (- 0.5 (-> arg0 menu-transition))))) + (set-scale! arg1 0.65) + (max! alpha 0.0) + (set! (-> arg1 alpha) alpha) + (set-flags! arg1 (font-flags kerning middle large)) + (+! (-> arg1 origin y) 8.0) + (cond + (arg3 + (set-color! arg1 (font-color progress-force-selected)) + (draw-highlight (the int (+ -1.0 (-> arg1 origin y))) 42 alpha) + (print-game-text (lookup-text! *common-text* (-> obj name) #f) arg1 #f 44 (bucket-id progress)) + (+! (-> arg1 origin y) 22.0) + (set-color! arg1 (font-color progress)) + (set-scale! arg1 0.5) + (set-color! arg1 (font-color progress)) + (+! (-> arg1 origin x) -25.0) + (print-game-text (string-format "~33L~C" 163) arg1 #f 44 (bucket-id progress)) + (+! (-> arg1 origin x) 50.0) + (print-game-text (string-format "~33L~C" 161) arg1 #f 44 (bucket-id progress)) + (+! (-> arg1 origin x) -25.0) + (set-color! arg1 (progress-selected 0)) + (set-flags! arg1 (font-flags kerning middle large)) + (print-game-text (string-format "~D" (-> *frame-rate-options* (-> *progress-state-pc* frame-rate-choice-index))) arg1 #f 44 (bucket-id progress)) + ) + (else + (if (= (-> arg0 option-index) arg2) + (draw-highlight (the int (-> arg1 origin y)) 21 alpha) + ) + (set-scale! arg1 0.65) + (print-game-text (lookup-text! *common-text* (-> obj name) #f) arg1 #f 44 (bucket-id progress)) + (set-scale! arg1 0.5) + (set-color! arg1 (font-color progress)) + (+! (-> arg1 origin y) 22.0) + (set-flags! arg1 (font-flags kerning middle large)) + (print-game-text (string-format "~D" (-> *frame-rate-options* (-> *progress-state-pc* frame-rate-choice-index))) arg1 #f 44 (bucket-id progress)) + ) + ) + (when-not-drawn-decoration + (draw-decoration obj arg1 alpha (text-id progress-root-graphic-options) #f 0.95)) + ) + (none) + ) diff --git a/goal_src/jak2/pc/progress/progress-h-pc.gc b/goal_src/jak2/pc/progress/progress-h-pc.gc index 419c36b425..7c4024a134 100644 --- a/goal_src/jak2/pc/progress/progress-h-pc.gc +++ b/goal_src/jak2/pc/progress/progress-h-pc.gc @@ -35,6 +35,9 @@ () ) +(deftype menu-frame-rate-option (menu-option) + () + ) (deftype menu-music-player-option (menu-option) ((last-move time-frame) diff --git a/goal_src/jak2/pc/progress/progress-pc.gc b/goal_src/jak2/pc/progress/progress-pc.gc index c78a99df22..fdf6198fd5 100644 --- a/goal_src/jak2/pc/progress/progress-pc.gc +++ b/goal_src/jak2/pc/progress/progress-pc.gc @@ -18,6 +18,8 @@ (aspect-ratio-choice-index int8) (aspect-ratio-ratio-index int8) + (frame-rate-choice-index int8) + (music-player-track music-player-track-info) (music-player-flava int8) (music-player-selected symbol) @@ -60,6 +62,21 @@ (('borderless) (set! (-> *progress-state-pc* display-mode-choice-index) 2)) )) +(defun set-progress-frame-rate-index () + "Set the frame rate option index accordingly." + (case (-> *pc-settings* target-fps) + ((30) (set! (-> *progress-state-pc* frame-rate-choice-index) 0)) + ((50) (set! (-> *progress-state-pc* frame-rate-choice-index) 1)) + ((60) (set! (-> *progress-state-pc* frame-rate-choice-index) 2)) + ((75) (set! (-> *progress-state-pc* frame-rate-choice-index) 3)) + ((120) (set! (-> *progress-state-pc* frame-rate-choice-index) 4)) + ((144) (set! (-> *progress-state-pc* frame-rate-choice-index) 5)) + ((165) (set! (-> *progress-state-pc* frame-rate-choice-index) 6)) + ((240) (set! (-> *progress-state-pc* frame-rate-choice-index) 7)) + ;; default to 60 fps + (else (set! (-> *progress-state-pc* frame-rate-choice-index) 2)) + ) + ) (defmethod init-defaults progress ((obj progress)) @@ -136,7 +153,8 @@ ;; set aspect ratio options (set-progress-aspect-ratio-pc-index) (set-progress-display-mode-index) - (set! (-> (the menu-on-off-option (-> *graphic-options-pc* options 2)) value-to-modify) (&-> *pc-settings* vsync?)) + (set-progress-frame-rate-index) + (set! (-> (the menu-on-off-option (-> *graphic-options-pc* options 3)) value-to-modify) (&-> *pc-settings* vsync?)) (set! (-> *progress-state-pc* music-player-track) #f) ) @@ -505,6 +523,38 @@ 0 ) +(defmethod respond-progress menu-frame-rate-option ((obj menu-frame-rate-option) (arg0 progress) (arg1 symbol)) + "Handle progress menu navigation logic." + + (when arg1 + (cond + ((cpad-pressed? 0 triangle) + (set-progress-frame-rate-index)) + ((cpad-pressed? 0 confirm) + (sound-play "generic-beep") + (set-frame-rate! *pc-settings* (-> *frame-rate-options* (-> *progress-state-pc* frame-rate-choice-index)) #t) + ) + (else + (let ((sound-beep? #f)) + (when (cpad-pressed? 0 left l-analog-left) + (true! sound-beep?) + (min-max-wrap-around+! (-> *progress-state-pc* frame-rate-choice-index) -1 0 (1- (-> *frame-rate-options* length))) + (set-frame-rate! *pc-settings* (-> *frame-rate-options* (-> *progress-state-pc* frame-rate-choice-index)) #t) + ) + (when (cpad-pressed? 0 right l-analog-right) + (true! sound-beep?) + (min-max-wrap-around+! (-> *progress-state-pc* frame-rate-choice-index) 1 0 (1- (-> *frame-rate-options* length))) + (set-frame-rate! *pc-settings* (-> *frame-rate-options* (-> *progress-state-pc* frame-rate-choice-index)) #t) + ) + (if sound-beep? + (sound-play "generic-beep") + ) + ) + ) + ) + ) + 0 + ) (defbehavior play-music-player progress ((info music-player-track-info) (flava int)) "play a music track using music player track info." diff --git a/goal_src/jak2/pc/progress/progress-static-pc.gc b/goal_src/jak2/pc/progress/progress-static-pc.gc index a0b7caa80e..fff52baa04 100644 --- a/goal_src/jak2/pc/progress/progress-static-pc.gc +++ b/goal_src/jak2/pc/progress/progress-static-pc.gc @@ -20,11 +20,13 @@ :options (new 'static 'boxed-array :type menu-option (new 'static 'menu-display-mode-option :name (text-id progress-display-mode)) (new 'static 'menu-aspect-ratio-pc-option :name (text-id progress-aspect-ratio)) + (new 'static 'menu-frame-rate-option :name (text-id progress-frame-rate)) (new 'static 'menu-on-off-vsync-option :name (text-id progress-vsync)) ) ) ) +(define *frame-rate-options* (new 'static 'boxed-array :type int16 30 50 60 75 120 144 165 240)) (define *aspect-ratio-custom-options* (new 'static 'menu-option-list