From cee354474c5587ae94843a5eda90b4f9770f4702 Mon Sep 17 00:00:00 2001 From: water111 Date: Wed, 18 Jun 2025 22:10:22 -0400 Subject: [PATCH] shadows pretty close, something wrong with plane calc in jak2 keira, maybe flags --- decompiler/level_extractor/extract_shadow.cpp | 7 +- .../opengl_renderer/OpenGLRenderer.cpp | 10 +- .../opengl_renderer/foreground/Shadow2.cpp | 17 +++- .../opengl_renderer/foreground/Shadow2.h | 5 +- .../jak1/engine/gfx/shadow/shadow-cpu-h.gc | 3 +- goal_src/jak2/engine/draw/drawable.gc | 17 ++++ .../jak2/engine/gfx/foreground/foreground.gc | 96 +++++++++++++++++++ .../engine/gfx/foreground/shadow-cpu-h.gc | 15 +++ .../jak2/engine/gfx/foreground/shadow-cpu.gc | 30 ++++++ 9 files changed, 189 insertions(+), 11 deletions(-) diff --git a/decompiler/level_extractor/extract_shadow.cpp b/decompiler/level_extractor/extract_shadow.cpp index 8393413305..286e8e932d 100644 --- a/decompiler/level_extractor/extract_shadow.cpp +++ b/decompiler/level_extractor/extract_shadow.cpp @@ -242,6 +242,10 @@ std::vector extract_jak2_shadow_data(const LinkedObjectFile& file, } else if (version == 1) { u32 num_joints = read_plain_data_field(tr, "num-joints", dts); uint32_t num_fragments = read_plain_data_field(tr, "num-fragments", dts); + if (num_fragments == 0) { + lg::error("Shadow geo {} with no fragments! Skipping\n", name); + return {}; + } // lg::info("{} {} fragments", name, num_fragments); auto frags_ref = TypedRef(get_field_ref(tr, "frags", dts), dts.ts.lookup_type("shadow-frag-ref")); @@ -406,7 +410,8 @@ void extract_shadow(const ObjectFileData& ag_data, auto geo_locations = find_objects_with_type(ag_data.linked_data, "shadow-geo"); for (auto loc : geo_locations) { - extract_jak2_shadow_data(ag_data.linked_data, dts, loc); + auto shadow_datas = extract_jak2_shadow_data(ag_data.linked_data, dts, loc); + add_data_to_level(sd, shadow_datas); } } } diff --git a/game/graphics/opengl_renderer/OpenGLRenderer.cpp b/game/graphics/opengl_renderer/OpenGLRenderer.cpp index a9b9c81a7d..36992f86b6 100644 --- a/game/graphics/opengl_renderer/OpenGLRenderer.cpp +++ b/game/graphics/opengl_renderer/OpenGLRenderer.cpp @@ -252,7 +252,7 @@ void OpenGLRenderer::init_bucket_renderers_jak3() { BucketId::MERC_LCOM_SHRUB, m_merc2); // 350 - init_bucket_renderer("shadow", BucketCategory::OTHER, BucketId::SHADOW); + init_bucket_renderer("shadow", BucketCategory::OTHER, BucketId::SHADOW, m_shadow3); // 351 for (int i = 0; i < LEVEL_MAX; i++) { @@ -359,8 +359,8 @@ void OpenGLRenderer::init_bucket_renderers_jak3() { BucketId::GENERIC_SPRITE_3, m_generic2, Generic2::Mode::LIGHTNING); - init_bucket_renderer("shadow2", BucketCategory::OTHER, BucketId::SHADOW2); - init_bucket_renderer("shadow3", BucketCategory::OTHER, BucketId::SHADOW3); + init_bucket_renderer("shadow2", BucketCategory::OTHER, BucketId::SHADOW2, m_shadow3); + init_bucket_renderer("shadow3", BucketCategory::OTHER, BucketId::SHADOW3, m_shadow3); // 575 init_bucket_renderer("tex-warp", BucketCategory::TEX, BucketId::TEX_WARP, m_texture_animator); @@ -551,7 +551,7 @@ void OpenGLRenderer::init_bucket_renderers_jak2() { init_bucket_renderer("gmerc-lcom-tfrag", BucketCategory::GENERIC, BucketId::GMERC_LCOM_TFRAG, m_generic2, Generic2::Mode::NORMAL); - init_bucket_renderer("shadow", BucketCategory::OTHER, BucketId::SHADOW); + init_bucket_renderer("shadow", BucketCategory::OTHER, BucketId::SHADOW, m_shadow3); // 220 init_bucket_renderer("tex-lcom-pris", BucketCategory::TEX, BucketId::TEX_LCOM_PRIS, m_texture_animator); @@ -571,7 +571,7 @@ void OpenGLRenderer::init_bucket_renderers_jak2() { init_bucket_renderer("tex-all-sprite", BucketCategory::TEX, BucketId::TEX_ALL_SPRITE, m_texture_animator); init_bucket_renderer("particles", BucketCategory::SPRITE, BucketId::PARTICLES); - init_bucket_renderer("shadow2", BucketCategory::OTHER, BucketId::SHADOW2); + init_bucket_renderer("shadow2", BucketCategory::OTHER, BucketId::SHADOW2, m_shadow3); init_bucket_renderer("effects", BucketCategory::OTHER, BucketId::EFFECTS, m_generic2, Generic2::Mode::LIGHTNING); init_bucket_renderer("tex-all-warp", BucketCategory::TEX, diff --git a/game/graphics/opengl_renderer/foreground/Shadow2.cpp b/game/graphics/opengl_renderer/foreground/Shadow2.cpp index c8ffcebf97..09a18638ae 100644 --- a/game/graphics/opengl_renderer/foreground/Shadow2.cpp +++ b/game/graphics/opengl_renderer/foreground/Shadow2.cpp @@ -2,7 +2,8 @@ #include "third-party/imgui/imgui.h" -Shadow2::Shadow2(const std::string& name, int my_id) : BucketRenderer(name, my_id) { +Shadow2::Shadow2(const std::string& name, int my_id, std::shared_ptr shadow3) + : BucketRenderer(name, my_id), m_shadow3(shadow3) { m_vertex_buffer.resize(kMaxVerts); m_front_index_buffer.resize(kMaxInds); m_back_index_buffer.resize(kMaxInds); @@ -53,7 +54,11 @@ void Shadow2::init_shaders(ShaderLibrary& shaders) { } void Shadow2::draw_debug_window() { - ImGui::Checkbox("volume", &m_debug_draw_volume); + if (m_using_shadow3) { + m_shadow3->draw_debug_window(); + } else { + ImGui::Checkbox("volume", &m_debug_draw_volume); + } } void Shadow2::reset_buffers() { @@ -71,6 +76,13 @@ void Shadow2::render(DmaFollower& dma, SharedRenderState* render_state, ScopedPr return; } + + m_using_shadow3 = dma.current_tag_vifcode0().kind == VifCode::Kind::PC_PORT; + if (m_using_shadow3) { + m_shadow3->render_jak1(dma, render_state, prof); + return; + } + auto maybe_constants = dma.read_and_advance(); if (maybe_constants.size_bytes == 0 && maybe_constants.vif0() == 0 && maybe_constants.vif1() == 0) { @@ -80,6 +92,7 @@ void Shadow2::render(DmaFollower& dma, SharedRenderState* render_state, ScopedPr reset_buffers(); + // shadow-vu1-constants ASSERT(maybe_constants.size_bytes >= sizeof(ShadowVu1Constants)); FrameConstants frame_constants; diff --git a/game/graphics/opengl_renderer/foreground/Shadow2.h b/game/graphics/opengl_renderer/foreground/Shadow2.h index 08b3a6757f..e07e420bc2 100644 --- a/game/graphics/opengl_renderer/foreground/Shadow2.h +++ b/game/graphics/opengl_renderer/foreground/Shadow2.h @@ -3,12 +3,13 @@ #include "common/math/Vector.h" #include "game/graphics/opengl_renderer/BucketRenderer.h" +#include "game/graphics/opengl_renderer/foreground/Shadow3.h" class Shadow2 : public BucketRenderer { public: static constexpr int kMaxVerts = 8192 * 3 * 2; static constexpr int kMaxInds = kMaxVerts; - Shadow2(const std::string& name, int my_id); + Shadow2(const std::string& name, int my_id, std::shared_ptr shadow3); ~Shadow2(); void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override; void draw_debug_window() override; @@ -94,4 +95,6 @@ class Shadow2 : public BucketRenderer { ScopedProfilerNode& prof, const FrameConstants& constants); u8 m_color[4] = {0, 0, 0, 0}; + std::shared_ptr m_shadow3; + bool m_using_shadow3 = false; }; diff --git a/goal_src/jak1/engine/gfx/shadow/shadow-cpu-h.gc b/goal_src/jak1/engine/gfx/shadow/shadow-cpu-h.gc index 6f0204378a..d3f2796dd9 100644 --- a/goal_src/jak1/engine/gfx/shadow/shadow-cpu-h.gc +++ b/goal_src/jak1/engine/gfx/shadow/shadow-cpu-h.gc @@ -107,8 +107,7 @@ ;; new shadow queue for drawing PC shadows. (declare-type pc-shadow-request structure) (deftype pc-shadow-request (structure) - ( - (dma-next dma-packet :inline) + ((dma-next dma-packet :inline) (settings shadow-settings :inline) (color vector :inline) (geo-name string) ;; name to send to PC renderer diff --git a/goal_src/jak2/engine/draw/drawable.gc b/goal_src/jak2/engine/draw/drawable.gc index fa4eac4a7b..535514c25e 100644 --- a/goal_src/jak2/engine/draw/drawable.gc +++ b/goal_src/jak2/engine/draw/drawable.gc @@ -1449,6 +1449,23 @@ ) ) ) + + ;; og:preserve-this + (let ((v1-0 *pc-shadow-globals*)) + (dotimes (a0-0 2) + (let ((a1-2 (-> v1-0 bucket a0-0))) + (set! (-> a1-2 first) (the-as pointer 0)) + (set! (-> a1-2 next) (the-as pointer 0)) + (set! (-> a1-2 shadow-color) (if (zero? a0-0) + (new 'static 'rgba :r #xf0 :g #xf0 :b #xf0 :a #x80) + (the-as rgba (-> *setting-control* user-current spotlight-color)) + ) + ) + (set! (-> a1-2 constants) (the-as shadow-vu1-constants 0)) + ) + ) + ) + (none) ) diff --git a/goal_src/jak2/engine/gfx/foreground/foreground.gc b/goal_src/jak2/engine/gfx/foreground/foreground.gc index 0321e558d2..65b2c2d288 100644 --- a/goal_src/jak2/engine/gfx/foreground/foreground.gc +++ b/goal_src/jak2/engine/gfx/foreground/foreground.gc @@ -13,6 +13,8 @@ (eye 3) ) +;; when set, use the rewritten PC shadow render (faster) +(define *use-pc-shadow* #t) (def-mips2c foreground-draw-hud (function draw-control dma-buffer float none)) @@ -563,8 +565,102 @@ ) ) +;; og:preserve-this +(defun pc-draw-bones-shadow ((dc draw-control) (mtx pointer) (dma-ptr pointer)) + "Add shadows for this draw-control to the *pc-shadow-queue* to be drawn in pc-shadow-execute-all. + This places a pc-shadow-request in the DMA buffer and adds it to the linked list of requests + for the currently selected run in *pc-shadow-queue*" + + (when (-> dc shadow-ctrl) + ;; update the "center" position of the shadow control, I guess to let some other thing look at it? + (let ((center-pos (-> dc skeleton bones (-> dc shadow-joint-index) position)) + (settings (-> dc shadow-ctrl settings)) + ) + (set! (-> settings center x) (-> center-pos x)) + (set! (-> settings center y) (-> center-pos y)) + (set! (-> settings center z) (-> center-pos z)) + ) + ) + (let* ((pse (the pc-shadow-request dma-ptr)) + (sgeo (-> dc shadow)) + (settings (if (-> dc shadow-ctrl) (-> dc shadow-ctrl settings) *default-shadow-settings*)) + (flags (-> settings flags)) + ) + + ;; if fade is enabled, and we're all the way faded out, disable draw + (when (not (logtest? flags (shadow-flags disable-fade))) + (let ((dist (-> (scratchpad-object foreground-work) distance w))) + (#when PC_PORT + (if (not (-> *pc-settings* ps2-shadow?)) + (set! dist 0.0))) + (if (< (-> settings fade-dist) dist) + (logior! flags (shadow-flags disable-draw)) + ) + ) + ) + + ;; if disabled, early return + (if (logtest? flags (shadow-flags disable-draw)) + (return dma-ptr) + ) + + + ;; settings + (mem-copy! (the pointer (-> pse settings)) (the pointer settings) (size-of shadow-settings)) + + ;; update the "center" position. + (let ((center-pos (-> dc skeleton bones (-> dc shadow-joint-index) position))) + (set! (-> pse settings center x) (-> center-pos x)) + (set! (-> pse settings center y) (-> center-pos y)) + (set! (-> pse settings center z) (-> center-pos z)) + ) + + ;; set the other properties + (set! (-> pse geo-name) (-> sgeo name)) + (set! (-> pse mtx) mtx) + (set! (-> pse num-joints) (-> sgeo num-joints)) + ;; TODO: this is probably the wrong color!!! + (vector-copy! (-> pse color) (-> *time-of-day-context* current-shadow-color)) + + ;; set up linked list. + (let* ((run (-> *pc-shadow-globals* bucket (-> settings shadow-type))) + (next (-> run next)) + ) + + ;; if we're the first in the list, store in the run + (when (zero? (-> run first)) + (format 0 "Setting first to #x~X~%" pse) + (set! (-> run first) (the pointer pse))) + + ;; patch next pointer of previous + (if (nonzero? next) (set! (-> (the (pointer structure) next) 0) pse)) + + ;; remember where to patch for the next one + (set! (-> run next) (&-> pse next)) + + ;; clear our next pointer in case we're last + (set! (-> pse next) (the pc-shadow-request 0)) + + ;; set up next tag at the start, to skip over this data. + ;; this is a bit of a hack, this function gets called when building merc chains, + ;; and inserts a bit of shadow dma that will later be referenced by the shadow bucket. + ;; but the original game did the same thing! + (&+! dma-ptr (size-of pc-shadow-request)) + (set! (-> pse dma-next dma) (new 'static 'dma-tag :id (dma-tag-id next) :addr (the-as int dma-ptr))) + (set! (-> pse dma-next vif0) (new 'static 'vif-tag)) + (set! (-> pse dma-next vif1) (new 'static 'vif-tag)) + ) + + dma-ptr + ) + ) + ;; ERROR: Unsupported inline assembly instruction kind - [lq ra, 32(v1)] (defun foreground-shadow ((draw-ctrl draw-control) (arg1 (inline-array pris-mtx)) (arg2 pointer)) + ;; og:preserve-this + (when *use-pc-shadow* + (return (pc-draw-bones-shadow draw-ctrl (the pointer arg1) arg2)) + ) (local-vars (shadow-settings shadow-settings)) (let ((shadow-geo (-> draw-ctrl shadow)) (dist (-> (scratchpad-object foreground-work) distance w)) diff --git a/goal_src/jak2/engine/gfx/foreground/shadow-cpu-h.gc b/goal_src/jak2/engine/gfx/foreground/shadow-cpu-h.gc index c89f8d374c..620f6547d0 100644 --- a/goal_src/jak2/engine/gfx/foreground/shadow-cpu-h.gc +++ b/goal_src/jak2/engine/gfx/foreground/shadow-cpu-h.gc @@ -137,6 +137,21 @@ (define *shadow-globals* (new 'global 'shadow-globals)) +;; og:preserve-this +;; separate copy of shadow-globals for storing only the PC format requests. +(define *pc-shadow-globals* (new 'global 'shadow-globals)) +(declare-type pc-shadow-request structure) +(deftype pc-shadow-request (structure) + ((dma-next dma-packet :inline) + (settings shadow-settings :inline) + (color vector :inline) + (geo-name string) ;; name to send to PC renderer + (mtx pointer) ;; pointer to DMA memory that will contain bones + (num-joints uint32) ;; number of joints needed for shadow + (next pc-shadow-request) + ) + ) + (deftype shadow-vertex (structure) ((x float :offset-assert 0) (y float :offset-assert 4) diff --git a/goal_src/jak2/engine/gfx/foreground/shadow-cpu.gc b/goal_src/jak2/engine/gfx/foreground/shadow-cpu.gc index b0a0102668..df8a903bb8 100644 --- a/goal_src/jak2/engine/gfx/foreground/shadow-cpu.gc +++ b/goal_src/jak2/engine/gfx/foreground/shadow-cpu.gc @@ -641,9 +641,39 @@ (none) ) +;; og:preserve-this +(defun pc-shadow-execute-all () + "Send PC shadow queue to the PC shadow renderer." + + ;; bail if disabled + (if (not (logtest? (-> *display* vu1-enable-user) (vu1-renderer-mask shadow))) + (return #f) + ) + + (dotimes (i 2) + (when (nonzero? (-> *pc-shadow-globals* bucket i first)) + (with-dma-buffer-add-bucket ((dma-buf (-> (current-frame) global-buf)) (if (zero? i) (bucket-id shadow) (bucket-id shadow2))) + (format 0 "dma bucket ~d from ~X~%" i (-> *pc-shadow-globals* bucket i first)) + (dma-buffer-add-ref-vif2 + dma-buf + 6 + (-> *pc-shadow-globals* bucket i first) + (new 'static 'vif-tag :cmd (vif-cmd pc-port)) + (new 'static 'vif-tag :cmd (vif-cmd pc-port)) + ) + ) + ) + ) + (none) + ) + ;; ERROR: Failed store: (s.h! (+ v1-24 18) 0) at op 58 ;; ERROR: Failed store: (s.h! (+ v1-24 16) 0) at op 59 (defun shadow-execute-all ((arg0 dma-buffer)) + (when *use-pc-shadow* + (pc-shadow-execute-all) + (return #f) + ) (when *debug-segment* (let ((gp-0 (-> *display* frames (-> *display* on-screen) profile-array data 0)) (v1-7 'shadow)