diff --git a/decompiler/level_extractor/extract_shadow.cpp b/decompiler/level_extractor/extract_shadow.cpp index 286e8e932d..3cb48c813e 100644 --- a/decompiler/level_extractor/extract_shadow.cpp +++ b/decompiler/level_extractor/extract_shadow.cpp @@ -249,11 +249,10 @@ std::vector extract_jak2_shadow_data(const LinkedObjectFile& file, // lg::info("{} {} fragments", name, num_fragments); auto frags_ref = TypedRef(get_field_ref(tr, "frags", dts), dts.ts.lookup_type("shadow-frag-ref")); - - auto header_ref = TypedRef(deref_label(get_field_ref(frags_ref, "header", dts)), - dts.ts.lookup_type("shadow-frag-header")); - u32 size_qwc = read_plain_data_field(frags_ref, "qwc", dts); for (u32 i = 0; i < num_fragments; i++) { + auto header_ref = TypedRef(deref_label(get_field_ref(frags_ref, "header", dts)), + dts.ts.lookup_type("shadow-frag-header")); + u32 size_qwc = read_plain_data_field(frags_ref, "qwc", dts); shadow_datas.push_back( extract_shadow_data(file, dts, header_ref, name, size_qwc, num_joints)); frags_ref.ref.byte_offset += 8; diff --git a/game/graphics/opengl_renderer/foreground/Shadow3.cpp b/game/graphics/opengl_renderer/foreground/Shadow3.cpp index 1e25e11e2d..d84fc74970 100644 --- a/game/graphics/opengl_renderer/foreground/Shadow3.cpp +++ b/game/graphics/opengl_renderer/foreground/Shadow3.cpp @@ -232,16 +232,58 @@ void Shadow3::draw_model(SharedRenderState* render_state, void Shadow3::finish(SharedRenderState* render_state, ScopedProfilerNode& prof) { // finally, draw shadow. if (!m_hacks) { - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); - // glStencilFunc(GL_GREATER, 0, 0); - glStencilFunc(GL_NOTEQUAL, 0, 0xFF); - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - glDepthFunc(GL_ALWAYS); + if (render_state->version == GameVersion::Jak1) { + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); + glStencilFunc(GL_NOTEQUAL, 0, 0xFF); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glDepthFunc(GL_ALWAYS); + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ONE, GL_ZERO); + m_full_screen_draw.draw(m_color, render_state, prof); - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ONE, GL_ZERO); - m_full_screen_draw.draw(m_color, render_state, prof); + } else { + glStencilFunc(GL_NOTEQUAL, 0, 0xFF); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glDepthFunc(GL_ALWAYS); + + glEnable(GL_BLEND); + glBlendFuncSeparate(GL_ONE, GL_ONE, GL_ONE, GL_ZERO); + + bool have_darken = false; + bool have_lighten = false; + bool lighten_channel[3] = {false, false, false}; + bool darken_channel[3] = {false, false, false}; + for (int i = 0; i < 3; i++) { + if (m_color[i] > 128) { + have_lighten = true; + lighten_channel[i] = true; + } else if (m_color[i] < 128) { + have_darken = true; + darken_channel[i] = true; + } + } + + if (have_darken) { + glColorMask(darken_channel[0], darken_channel[1], darken_channel[2], false); + glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); + m_full_screen_draw.draw( + math::Vector4f((m_color[3] - m_color[0]) / 256.f, (m_color[3] - m_color[1]) / 256.f, + (m_color[3] - m_color[2]) / 256.f, 0) * + 0.5f, + render_state, prof); + } + + if (have_lighten) { + glColorMask(lighten_channel[0], lighten_channel[1], lighten_channel[2], false); + glBlendEquation(GL_FUNC_ADD); + m_full_screen_draw.draw( + math::Vector4f((m_color[0] - m_color[3]) / 256.f, (m_color[1] - m_color[3]) / 256.f, + (m_color[2] - m_color[3]) / 256.f, 0) * + 0.5f, + render_state, prof); + } + } } // restore @@ -293,6 +335,7 @@ void Shadow3::flush_requests(SharedRenderState* render_state, ScopedProfilerNode void Shadow3::first_time_setup(SharedRenderState* render_state) { glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT); + render_state->stencil_dirty = true; render_state->shaders[ShaderId::SHADOW3].activate(); glUniformMatrix4fv(m_uniforms.camera_rot, 1, GL_FALSE, &render_state->camera_rot[0].x()); @@ -314,6 +357,7 @@ void Shadow3::render_jak1(DmaFollower& dma, m_did_first_time_setup = false; while (dma.current_tag_offset() != render_state->next_bucket) { auto data = dma.read_and_advance(); + if (data.vifcode0().kind == VifCode::Kind::PC_PORT) { u32 next = data.data_offset; while (next) { @@ -328,7 +372,7 @@ void Shadow3::render_jak1(DmaFollower& dma, auto model = render_state->loader->get_shadow_model(name); if (!model) { - printf(" SKIP: no model data\n"); + // printf(" SKIP: no model data\n"); continue; } @@ -375,7 +419,9 @@ void Shadow3::render_jak1(DmaFollower& dma, request.bones = g_ee_main_mem + game_request.mtx; request.scissor_top = game_request.settings.flags & kUpperClip; request.color = game_request.color; + request.dist_to_locus = game_request.settings.dist_to_locus; m_color = request.color; + // m_color = {0.2, 0.8, 0.2, 1.}; // copy bones to buffer constexpr int in_stride = 8 * 4 * sizeof(float); @@ -415,9 +461,22 @@ void Shadow3::render_jak1(DmaFollower& dma, chain->head = &request; // detect if the origin is below the clipping plane and if so, move it up. - const float dot = request.bottom_plane.xyz().dot(request.origin); - if (dot + request.bottom_plane.w() > 0) { - request.bottom_plane.w() = -dot; + // the logic for this changed in jak2, to support shadows with negative dist_from_locus + if (render_state->version == GameVersion::Jak1) { + const float dot = request.bottom_plane.xyz().dot(request.origin); + if (dot + request.bottom_plane.w() > 0) { + request.bottom_plane.w() = -dot; + } + } else { + const float bot_offset = request.origin.dot(request.bottom_plane.xyz()); + const float top_offset = request.origin.dot(request.top_plane.xyz()); + if ((request.bottom_plane.w() < bot_offset) && (top_offset < request.top_plane.w())) { + if (request.dist_to_locus > 0) { + request.bottom_plane.w() = -bot_offset; + } else { + request.top_plane.w() = -top_offset; + } + } } const auto& cam_rot = render_state->camera_rot; diff --git a/game/graphics/opengl_renderer/foreground/Shadow3.h b/game/graphics/opengl_renderer/foreground/Shadow3.h index b7be9bff49..49a4b29d7d 100644 --- a/game/graphics/opengl_renderer/foreground/Shadow3.h +++ b/game/graphics/opengl_renderer/foreground/Shadow3.h @@ -40,6 +40,7 @@ class Shadow3 { math::Vector origin; math::Vector4f top_plane, bottom_plane; math::Vector3f light_dir; + float dist_to_locus; math::Vector4f color; ShadowRequest* next = nullptr; const u8* bones = nullptr; diff --git a/goal_src/jak2/engine/gfx/foreground/foreground.gc b/goal_src/jak2/engine/gfx/foreground/foreground.gc index 65b2c2d288..cfe8df49cc 100644 --- a/goal_src/jak2/engine/gfx/foreground/foreground.gc +++ b/goal_src/jak2/engine/gfx/foreground/foreground.gc @@ -629,7 +629,6 @@ ;; 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 diff --git a/goal_src/jak2/engine/gfx/foreground/shadow-cpu.gc b/goal_src/jak2/engine/gfx/foreground/shadow-cpu.gc index df8a903bb8..d225726a73 100644 --- a/goal_src/jak2/engine/gfx/foreground/shadow-cpu.gc +++ b/goal_src/jak2/engine/gfx/foreground/shadow-cpu.gc @@ -652,8 +652,34 @@ (dotimes (i 2) (when (nonzero? (-> *pc-shadow-globals* bucket i first)) + ;; patch the color of each request. + (let ((iter (the pc-shadow-request (-> *pc-shadow-globals* bucket i first))) + (color (new-stack-vector0)) + ) + + (cond + ((= i 0) + (vector-float*! color (-> *time-of-day-context* current-shadow-color) 128.0) + ) + (else + (let ((c (-> *pc-shadow-globals* bucket i shadow-color))) + (set! (-> color x) (the float (-> c r))) + (set! (-> color y) (the float (-> c g))) + (set! (-> color z) (the float (-> c b))) + ) + ) + ) + + (set! (-> color w) (the float (-> *pc-shadow-globals* bucket i shadow-color a))) + + (while (nonzero? iter) + ;(vector-copy! (-> iter color) color) + (set! (-> iter color quad) (-> color quad)) + (set! iter (-> iter next)) + ) + ) + (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