diff --git a/common/custom_data/Tfrag3Data.h b/common/custom_data/Tfrag3Data.h index b8ade5e1f0..9b0f19d8ba 100644 --- a/common/custom_data/Tfrag3Data.h +++ b/common/custom_data/Tfrag3Data.h @@ -73,7 +73,7 @@ struct MemoryUsageTracker { void add(MemoryUsageCategory category, u32 size_bytes) { data[category] += size_bytes; } }; -constexpr int TFRAG3_VERSION = 30; +constexpr int TFRAG3_VERSION = 31; // These vertices should be uploaded to the GPU at load time and don't change struct PreloadedVertex { diff --git a/decompiler/level_extractor/MercData.cpp b/decompiler/level_extractor/MercData.cpp index ec8741b3ef..39f5cbc64b 100644 --- a/decompiler/level_extractor/MercData.cpp +++ b/decompiler/level_extractor/MercData.cpp @@ -13,7 +13,7 @@ void MercEyeCtrl::from_ref(TypedRef tr, const DecompilerTypeSystem& dts) { eye_slot = read_plain_data_field(tr, "eye-slot", dts); } -void MercCtrlHeader::from_ref(TypedRef tr, const DecompilerTypeSystem& dts) { +void MercCtrlHeader::from_ref(TypedRef tr, const DecompilerTypeSystem& dts, GameVersion version) { st_magic = read_plain_data_field(tr, "st-magic", dts); xyz_scale = read_plain_data_field(tr, "xyz-scale", dts); st_out_a = read_plain_data_field(tr, "st-out-a", dts); @@ -58,6 +58,16 @@ void MercCtrlHeader::from_ref(TypedRef tr, const DecompilerTypeSystem& dts) { death_effect = read_plain_data_field(tr, "death-effect", dts); use_translucent = read_plain_data_field(tr, "use-translucent", dts); display_this_fragment = read_plain_data_field(tr, "display-this-fragment", dts); + + if (version > GameVersion::Jak1) { + disable_fog = read_plain_data_field(tr, "disable-fog", dts); + use_warp = read_plain_data_field(tr, "use-warp", dts); + ignore_alpha = read_plain_data_field(tr, "ignore-alpha", dts); + force_fade = read_plain_data_field(tr, "force-fade", dts); + disable_envamp = read_plain_data_field(tr, "disable-envmap", dts); + } else { + disable_fog = false; + } } std::string MercCtrlHeader::print() const { @@ -427,12 +437,12 @@ std::string MercEffect::print() { return result; } -void MercCtrl::from_ref(TypedRef tr, const DecompilerTypeSystem& dts) { +void MercCtrl::from_ref(TypedRef tr, const DecompilerTypeSystem& dts, GameVersion version) { name = read_string_field(tr, "name", dts, false); num_joints = read_plain_data_field(tr, "num-joints", dts); auto merc_ctrl_header_ref = TypedRef(get_field_ref(tr, "header", dts), dts.ts.lookup_type("merc-ctrl-header")); - header.from_ref(merc_ctrl_header_ref, dts); + header.from_ref(merc_ctrl_header_ref, dts, version); auto eff_ref = TypedRef(get_field_ref(tr, "effect", dts), dts.ts.lookup_type("merc-effect")); for (u32 i = 0; i < header.effect_count; i++) { diff --git a/decompiler/level_extractor/MercData.h b/decompiler/level_extractor/MercData.h index b16569c9c3..f5a521fa72 100644 --- a/decompiler/level_extractor/MercData.h +++ b/decompiler/level_extractor/MercData.h @@ -7,6 +7,7 @@ #include "common/common_types.h" #include "common/dma/gs.h" #include "common/math/Vector.h" +#include "common/versions.h" #include "decompiler/util/goal_data_reader.h" @@ -63,7 +64,13 @@ struct MercCtrlHeader { u8 use_translucent; u8 display_this_fragment; - void from_ref(TypedRef tr, const DecompilerTypeSystem& dts); + u8 disable_fog = false; // jak 2 only + u8 use_warp = false; + u8 ignore_alpha = false; + u8 force_fade = false; + u8 disable_envamp = false; + + void from_ref(TypedRef tr, const DecompilerTypeSystem& dts, GameVersion version); std::string print() const; }; @@ -213,7 +220,7 @@ struct MercCtrl { MercCtrlHeader header; std::vector effects; - void from_ref(TypedRef tr, const DecompilerTypeSystem& dts); + void from_ref(TypedRef tr, const DecompilerTypeSystem& dts, GameVersion version); void debug_print_blerc(); std::string print(); }; diff --git a/decompiler/level_extractor/extract_merc.cpp b/decompiler/level_extractor/extract_merc.cpp index abbc1ff7a0..9a9f8f9320 100644 --- a/decompiler/level_extractor/extract_merc.cpp +++ b/decompiler/level_extractor/extract_merc.cpp @@ -136,7 +136,7 @@ MercCtrl extract_merc_ctrl(const LinkedObjectFile& file, auto tr = typed_ref_from_basic(ref, dts); MercCtrl ctrl; - ctrl.from_ref(tr, dts); // the merc data import + ctrl.from_ref(tr, dts, file.version); // the merc data import return ctrl; } @@ -228,7 +228,8 @@ void update_mode_from_alpha1(GsAlpha reg, DrawMode& mode) { DrawMode process_draw_mode(const MercShader& info, bool enable_alpha_test, bool enable_alpha_blend, - bool depth_write) { + bool depth_write, + bool fge) { DrawMode mode; /* * (new 'static 'gs-test @@ -270,6 +271,8 @@ DrawMode process_draw_mode(const MercShader& info, mode.set_clamp_s_enable(info.clamp & 0b1); mode.set_clamp_t_enable(info.clamp & 0b100); + mode.set_fog(fge); + return mode; } @@ -769,7 +772,8 @@ ConvertedMercEffect convert_merc_effect(const MercEffect& input_effect, } if (input_effect.extra_info.shader) { result.has_envmap = true; - result.envmap_mode = process_draw_mode(*input_effect.extra_info.shader, false, false, false); + result.envmap_mode = + process_draw_mode(*input_effect.extra_info.shader, false, false, false, false); result.envmap_mode.set_ab(true); u32 new_tex = remap_texture(input_effect.extra_info.shader->original_tex, map); ASSERT(result.envmap_mode.get_tcc_enable()); @@ -910,8 +914,9 @@ ConvertedMercEffect convert_merc_effect(const MercEffect& input_effect, for (size_t i = 0; i < frag.fp_header.shader_cnt; i++) { const auto& shader = frag.shaders.at(i); // update merc state from shader (will hold over to next fragment, if needed) + bool fog = ctrl_header.disable_fog == 0; merc_state.merc_draw_mode.mode = - process_draw_mode(shader, result.has_envmap, use_alpha_blend, depth_write); + process_draw_mode(shader, result.has_envmap, use_alpha_blend, depth_write, fog); if (!merc_state.merc_draw_mode.mode.get_tcc_enable()) { ASSERT(false); } diff --git a/decompiler/level_extractor/extract_tie.cpp b/decompiler/level_extractor/extract_tie.cpp index 3bed0ccfef..388d73da46 100644 --- a/decompiler/level_extractor/extract_tie.cpp +++ b/decompiler/level_extractor/extract_tie.cpp @@ -2550,6 +2550,9 @@ void add_vertices_and_static_draw(tfrag3::TieTree& tree, // bool using_wind = true; // hack, for testing bool using_wind = proto.stiffness != 0.f; + if (version == GameVersion::Jak2) { + using_wind = false; // disable wind on jak 2 for now - not supported in GOAL or C++ yet. + } bool using_envmap = info.uses_envmap; ASSERT(using_envmap == proto.envmap_adgif.has_value()); diff --git a/game/graphics/opengl_renderer/foreground/Merc2.cpp b/game/graphics/opengl_renderer/foreground/Merc2.cpp index 6a8300b23b..acc9813ffe 100644 --- a/game/graphics/opengl_renderer/foreground/Merc2.cpp +++ b/game/graphics/opengl_renderer/foreground/Merc2.cpp @@ -247,14 +247,15 @@ void Merc2::handle_pc_model(const DmaTransfer& setup, u64 enable_mask; u64 ignore_alpha_mask; u8 effect_count; - u8 update_verts; + u8 bitflags; }; auto* flags = (const PcMercFlags*)input_data; int num_effects = flags->effect_count; // mostly just a sanity check ASSERT(num_effects < kMaxEffect); u64 current_ignore_alpha_bits = flags->ignore_alpha_mask; // shader settings u64 current_effect_enable_bits = flags->enable_mask; // mask for game to disable an effect - bool model_uses_mod = flags->update_verts; // if we should update vertices from game. + bool model_uses_mod = flags->bitflags & 1; // if we should update vertices from game. + bool model_disables_fog = (flags->bitflags & 2); input_data += 32; // Next is "fade data", indicating the color/intensity of envmap effect @@ -500,7 +501,8 @@ void Merc2::handle_pc_model(const DmaTransfer& setup, // do fixed draws: for (auto& fdraw : effect.mod.fix_draw) { - alloc_normal_draw(fdraw, ignore_alpha, lev_bucket, first_bone, lights, uses_water); + alloc_normal_draw(fdraw, ignore_alpha, lev_bucket, first_bone, lights, uses_water, + model_disables_fog); if (should_envmap) { try_alloc_envmap_draw(fdraw, effect.envmap_mode, effect.envmap_texture, lev_bucket, fade_buffer + 4 * ei, first_bone, lights, uses_water); @@ -509,7 +511,8 @@ void Merc2::handle_pc_model(const DmaTransfer& setup, // do mod draws for (auto& mdraw : effect.mod.mod_draw) { - auto n = alloc_normal_draw(mdraw, ignore_alpha, lev_bucket, first_bone, lights, uses_water); + auto n = alloc_normal_draw(mdraw, ignore_alpha, lev_bucket, first_bone, lights, uses_water, + model_disables_fog); // modify the draw, set the mod flag and point it to the opengl buffer n->flags |= MOD_VTX; n->mod_vtx_buffer = mod_opengl_buffers[ei]; @@ -530,7 +533,8 @@ void Merc2::handle_pc_model(const DmaTransfer& setup, try_alloc_envmap_draw(draw, effect.envmap_mode, effect.envmap_texture, lev_bucket, fade_buffer + 4 * ei, first_bone, lights, uses_water); } - alloc_normal_draw(draw, ignore_alpha, lev_bucket, first_bone, lights, uses_water); + alloc_normal_draw(draw, ignore_alpha, lev_bucket, first_bone, lights, uses_water, + model_disables_fog); } } } @@ -944,7 +948,8 @@ Merc2::Draw* Merc2::alloc_normal_draw(const tfrag3::MercDraw& mdraw, LevelDrawBucket* lev_bucket, u32 first_bone, u32 lights, - bool jak1_water_mode) { + bool jak1_water_mode, + bool disable_fog) { Draw* draw = &lev_bucket->draws[lev_bucket->next_free_draw++]; draw->flags = 0; draw->first_index = mdraw.first_index; @@ -954,6 +959,12 @@ Merc2::Draw* Merc2::alloc_normal_draw(const tfrag3::MercDraw& mdraw, draw->mode.set_ab(true); draw->mode.disable_depth_write(); } + + if (disable_fog) { + draw->mode.set_fog(false); + // but don't toggle it the other way? + } + draw->texture = mdraw.eye_id == 0xff ? mdraw.tree_tex_id : (0xffffff00 | mdraw.eye_id); draw->first_bone = first_bone; draw->light_idx = lights; @@ -1070,6 +1081,9 @@ void Merc2::do_draws(const Draw* draw_array, int last_tex = -1; int last_light = -1; bool normal_vtx_buffer_bound = true; + + bool fog_on = true; + for (u32 di = 0; di < num_draws; di++) { auto& draw = draw_array[di]; if (draw.flags & MOD_VTX) { @@ -1086,6 +1100,18 @@ void Merc2::do_draws(const Draw* draw_array, } } glUniform1i(uniforms.ignore_alpha, draw.flags & DrawFlags::IGNORE_ALPHA); + + if (fog_on && !draw.mode.get_fog_enable()) { + // on -> off + glUniform4f(uniforms.fog_color, render_state->fog_color[0] / 255.f, + render_state->fog_color[1] / 255.f, render_state->fog_color[2] / 255.f, 0); + fog_on = false; + } else if (!fog_on && draw.mode.get_fog_enable()) { + glUniform4f(uniforms.fog_color, render_state->fog_color[0] / 255.f, + render_state->fog_color[1] / 255.f, render_state->fog_color[2] / 255.f, + render_state->fog_intensity / 255); + fog_on = true; + } bool use_mipmaps_for_filtering = true; if ((int)draw.texture != last_tex) { if (draw.texture < lev->textures.size()) { diff --git a/game/graphics/opengl_renderer/foreground/Merc2.h b/game/graphics/opengl_renderer/foreground/Merc2.h index a6d8a294fe..a0a81df953 100644 --- a/game/graphics/opengl_renderer/foreground/Merc2.h +++ b/game/graphics/opengl_renderer/foreground/Merc2.h @@ -86,7 +86,7 @@ class Merc2 : public BucketRenderer { static constexpr int MAX_SHADER_BONE_VECTORS = 1024 * 32; // ?? static constexpr int MAX_LEVELS = 3; - static constexpr int MAX_DRAWS_PER_LEVEL = 2048; + static constexpr int MAX_DRAWS_PER_LEVEL = 2048 * 2; static constexpr int MAX_ENVMAP_DRAWS_PER_LEVEL = MAX_DRAWS_PER_LEVEL; math::Vector4f m_shader_bone_vector_buffer[MAX_SHADER_BONE_VECTORS]; @@ -200,7 +200,9 @@ class Merc2 : public BucketRenderer { LevelDrawBucket* lev_bucket, u32 first_bone, u32 lights, - bool jak1_water_mode); + bool jak1_water_mode, + bool disable_fog); + Draw* try_alloc_envmap_draw(const tfrag3::MercDraw& mdraw, const DrawMode& envmap_mode, u32 envmap_texture, diff --git a/goal_src/jak1/engine/gfx/foreground/bones.gc b/goal_src/jak1/engine/gfx/foreground/bones.gc index 80fca9917d..38e27e5881 100644 --- a/goal_src/jak1/engine/gfx/foreground/bones.gc +++ b/goal_src/jak1/engine/gfx/foreground/bones.gc @@ -944,11 +944,18 @@ ;; flags 2 qw ;; fades (u32 x N), padding to qw aligned +(defenum pc-merc-bits + :type uint8 + :bitfield #t + (update-verts 0) + (disable-fog 1) + ) + (deftype pc-merc-flags (structure) ((enable-mask uint64) (ignore-alpha-mask uint64) (effect-count uint8) - (update-verts uint8) + (bit-flags pc-merc-bits) ) ) @@ -1055,7 +1062,10 @@ ;; flags (let ((flags (the (pc-merc-flags) dma-buf))) (set! (-> flags effect-count) (-> merc-ctrl header effect-count)) - (set! (-> flags update-verts) (if update-verts 1 0)) + (set! (-> flags bit-flags) (the pc-merc-bits 0)) + (when update-verts + (logior! (-> flags bit-flags) (pc-merc-bits update-verts)) + ) (set! (-> flags enable-mask) enable-mask) (set! (-> flags ignore-alpha-mask) ignore-alpha-mask) ) diff --git a/goal_src/jak2/engine/gfx/foreground/foreground.gc b/goal_src/jak2/engine/gfx/foreground/foreground.gc index 3830eeba87..5642f2c51a 100644 --- a/goal_src/jak2/engine/gfx/foreground/foreground.gc +++ b/goal_src/jak2/engine/gfx/foreground/foreground.gc @@ -630,11 +630,18 @@ ) ) +(defenum pc-merc-bits + :type uint8 + :bitfield #t + (update-verts 0) + (disable-fog 1) + ) + (deftype pc-merc-flags (structure) ((enable-mask uint64) (ignore-alpha-mask uint64) (effect-count uint8) - (update-verts uint8) + (bit-flags pc-merc-bits) ) ) @@ -730,7 +737,13 @@ ;; flags (let ((flags (the (pc-merc-flags) dma-buf))) (set! (-> flags effect-count) (-> merc-ctrl header effect-count)) - (set! (-> flags update-verts) (if update-verts 1 0)) + (set! (-> flags bit-flags) (the pc-merc-bits 0)) + (when update-verts + (logior! (-> flags bit-flags) (pc-merc-bits update-verts)) + ) + (when (logtest? (-> dc status) (draw-control-status disable-fog)) + (logior! (-> flags bit-flags) (pc-merc-bits disable-fog)) + ) (set! (-> flags enable-mask) enable-mask) (set! (-> flags ignore-alpha-mask) ignore-alpha-mask) ) diff --git a/goal_src/jak2/engine/level/level.gc b/goal_src/jak2/engine/level/level.gc index 510b32cc8c..3f7c6ac4b3 100644 --- a/goal_src/jak2/engine/level/level.gc +++ b/goal_src/jak2/engine/level/level.gc @@ -523,16 +523,14 @@ into 7 sections, which might explain the weird sizes in the center. ;; interestingly, if we are in the 'medium' mode, we use the size of the ;; previous object, plus 2048 bytes. Maybe the objects are sorted in decreasing size, ;; so this allows the big ones to load first, then shrink the temp buffer as the rest come in. - ;; also seems to be no way to hit this case - the load-buffer-mode is eventually - ;; forced to small-edge in all cases that I see. -- NOTE: not true! + ;; the "medium" case is hit because the relocate method for `art-group` changes the mode. + ;; if it detects that it runs after textures. (case (-> arg0 load-buffer-mode) (((load-buffer-mode small-center)) (set! (-> arg0 load-buffer-size) (the-as uint (* 1100 1024))) ;; 1100 KB ) (((load-buffer-mode medium)) (set! (-> arg0 load-buffer-size) (+ (-> arg1 length) (* 2 1024))) - (format 0 "believed unused load-buffer-resize case hit.~%") - ; (break!) ) ) diff --git a/goal_src/jak2/kernel/gkernel.gc b/goal_src/jak2/kernel/gkernel.gc index 444074a35a..d30974d793 100644 --- a/goal_src/jak2/kernel/gkernel.gc +++ b/goal_src/jak2/kernel/gkernel.gc @@ -2238,6 +2238,9 @@ (shrink-heap (the dead-pool-heap (-> pp pool)) pp) ) ) + (('dead) + ;; died in init, this is fine. + ) (else (format 0 "GOT UNKNOWN INIT: ~A~%" (-> pp status)) )