diff --git a/common/custom_data/TFrag3Data.cpp b/common/custom_data/TFrag3Data.cpp index 754e85b67d..25fc742ba9 100644 --- a/common/custom_data/TFrag3Data.cpp +++ b/common/custom_data/TFrag3Data.cpp @@ -587,9 +587,7 @@ void MercModelGroup::serialize(Serializer& ser) { ser.from_pod_vector(&vertices); } -void ShadowModel::serialize(Serializer& ser) { - ser.from_str(&name); - ser.from_ptr(&max_bones); +void ShadowModelFragment::serialize(Serializer& ser) { ser.from_ptr(&first_vertex); ser.from_ptr(&num_one_bone_vertices); ser.from_ptr(&num_two_bone_vertices); @@ -599,6 +597,20 @@ void ShadowModel::serialize(Serializer& ser) { ser.from_pod_vector(&double_edges); } +void ShadowModel::serialize(Serializer& ser) { + ser.from_str(&name); + ser.from_ptr(&max_bones); + + if (ser.is_saving()) { + ser.save(fragments.size()); + } else { + fragments.resize(ser.load()); + } + for (auto& frag : fragments) { + frag.serialize(ser); + } +} + void ShadowModelGroup::serialize(Serializer& ser) { ser.from_pod_vector(&vertices); if (ser.is_saving()) { diff --git a/common/custom_data/Tfrag3Data.h b/common/custom_data/Tfrag3Data.h index 83844e5502..1a03b60a6d 100644 --- a/common/custom_data/Tfrag3Data.h +++ b/common/custom_data/Tfrag3Data.h @@ -634,18 +634,21 @@ struct ShadowEdge { u8 tri[2]; }; +struct ShadowModelFragment { + std::vector single_tris, double_tris; + std::vector single_edges, double_edges; + u32 first_vertex; + u32 num_one_bone_vertices; + u32 num_two_bone_vertices; + void serialize(Serializer& ser); +}; + struct ShadowModel { static constexpr int kMaxVertices = 254; static constexpr int kMaxTris = 254; std::string name; u32 max_bones; - - std::vector single_tris, double_tris; - std::vector single_edges, double_edges; - - u32 first_vertex; - u32 num_one_bone_vertices; - u32 num_two_bone_vertices; + std::vector fragments; void serialize(Serializer& ser); }; diff --git a/decompiler/level_extractor/extract_shadow.cpp b/decompiler/level_extractor/extract_shadow.cpp index f55c503be3..8393413305 100644 --- a/decompiler/level_extractor/extract_shadow.cpp +++ b/decompiler/level_extractor/extract_shadow.cpp @@ -7,38 +7,6 @@ namespace decompiler { -/* -*(deftype shadow-header (structure) -((qwc-data uint32 :offset-assert 0) -(num-joints uint32 :offset-assert 4) -(num-verts uint16 :offset-assert 8) -(num-twos uint16 :offset-assert 10) -(num-single-tris uint16 :offset-assert 12) -(num-single-edges uint16 :offset-assert 14) -(num-double-tris uint16 :offset-assert 16) -(num-double-edges uint16 :offset-assert 18) -(ofs-verts uint32 :offset-assert 20) -(ofs-refs uint32 :offset-assert 24) -(ofs-single-tris uint32 :offset-assert 28) -(ofs-single-edges uint32 :offset-assert 32) -(ofs-double-tris uint32 :offset-assert 36) -(ofs-double-edges uint32 :offset-assert 40) -) -:method-count-assert 9 -:size-assert #x2c -:flag-assert #x90000002c -) - -(deftype shadow-geo (art-element) -((total-size uint32 :offset-assert 32) -(header shadow-header :inline :offset 32) -(rest uint64 :dynamic :offset-assert 80) -) -:method-count-assert 13 -:size-assert #x50 -:flag-assert #xd00000050 -)*/ - struct ShadowVertex { math::Vector3f pos; float weight; @@ -106,37 +74,33 @@ std::string debug_dump_to_ply(const ShadowData& data) { return result; } +constexpr int kHeaderSize = 48; + ShadowData extract_shadow_data(const LinkedObjectFile& file, const DecompilerTypeSystem& dts, - int word_idx) { - Ref ref; - ref.data = &file; - ref.seg = 0; - ref.byte_offset = word_idx * 4; - auto tr = typed_ref_from_basic(ref, dts); - constexpr int kHeaderSize = 48; - + TypedRef header_ref, + const std::string& name, + int size_qwc, + int num_joints) { ShadowData shadow_data; - auto header_ref = TypedRef(get_field_ref(tr, "header", dts), dts.ts.lookup_type("shadow-header")); - u32 size_qwc = read_plain_data_field(header_ref, "qwc-data", dts); ASSERT(size_qwc < 1024 * 1024); // something reasonable std::vector data(size_qwc * 16); Ref shadow_ref = header_ref.ref; shadow_ref.byte_offset += kHeaderSize; memcpy_from_plain_data(data.data(), shadow_ref, size_qwc * 16 - kHeaderSize); - lg::info("name is {}, has {} joints, size {} bytes", read_string_field(tr, "name", dts, false), - read_plain_data_field(header_ref, "num-joints", dts), data.size()); + // lg::info("name is {}, has {} joints, size {} bytes", name, + // read_plain_data_field(header_ref, "num-joints", dts), data.size()); - shadow_data.name = read_string_field(tr, "name", dts, false); - shadow_data.num_joints = read_plain_data_field(header_ref, "num-joints", dts); + shadow_data.name = name; + shadow_data.num_joints = num_joints; const u32 num_verts = read_plain_data_field(header_ref, "num-verts", dts); const u32 num_twos = read_plain_data_field(header_ref, "num-twos", dts); ASSERT(num_verts >= num_twos); const u32 num_ones = num_verts - num_twos; - lg::info(" vert counts {} {}", num_ones, num_twos); + // lg::info(" vert counts {} {}", num_ones, num_twos); const u32 ofs_verts = read_plain_data_field(header_ref, "ofs-verts", dts); const u32 ofs_refs = read_plain_data_field(header_ref, "ofs-refs", dts); @@ -152,8 +116,8 @@ ShadowData extract_shadow_data(const LinkedObjectFile& file, ASSERT(ofs_verts == kHeaderSize); // verts always right after the header - lg::info(" offsets {} {} {} {} {} {}", ofs_verts, ofs_refs, ofs_single_tris, ofs_single_edges, - ofs_double_tris, ofs_double_edges); + // lg::info(" offsets {} {} {} {} {} {}", ofs_verts, ofs_refs, ofs_single_tris, ofs_single_edges, + // ofs_double_tris, ofs_double_edges); // vertices ASSERT(ofs_refs - ofs_verts == 16 * num_verts); @@ -241,6 +205,61 @@ ShadowData extract_shadow_data(const LinkedObjectFile& file, return shadow_data; } +ShadowData extract_jak1_shadow_data(const LinkedObjectFile& file, + const DecompilerTypeSystem& dts, + int geo_word_idx) { + Ref ref; + ref.data = &file; + ref.seg = 0; + ref.byte_offset = geo_word_idx * 4; + auto tr = typed_ref_from_basic(ref, dts); + auto header_ref = TypedRef(get_field_ref(tr, "header", dts), dts.ts.lookup_type("shadow-header")); + u32 size_qwc = read_plain_data_field(header_ref, "qwc-data", dts); + const std::string name = read_string_field(tr, "name", dts, false); + int num_joints = read_plain_data_field(header_ref, "num-joints", dts); + return extract_shadow_data(file, dts, header_ref, name, size_qwc, num_joints); +} + +std::vector extract_jak2_shadow_data(const LinkedObjectFile& file, + const DecompilerTypeSystem& dts, + int geo_word_idx) { + std::vector shadow_datas; + Ref ref; + ref.data = &file; + ref.seg = 0; + ref.byte_offset = geo_word_idx * 4; + auto tr = typed_ref_from_basic(ref, dts); + uint32_t version = read_plain_data_field(tr, "version", dts); + std::string name = read_string_field(tr, "name", dts, false); + + if (version == 0) { + tr.type = dts.ts.lookup_type("shadow-geo-old"); + auto header_ref = + TypedRef(get_field_ref(tr, "header", dts), dts.ts.lookup_type("shadow-frag-header")); + u32 size_qwc = read_plain_data_field(header_ref, "qwc-data", dts); + int num_joints = read_plain_data_field(header_ref, "num-joints", dts); + shadow_datas.push_back(extract_shadow_data(file, dts, header_ref, name, size_qwc, num_joints)); + } 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); + // 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++) { + shadow_datas.push_back( + extract_shadow_data(file, dts, header_ref, name, size_qwc, num_joints)); + frags_ref.ref.byte_offset += 8; + } + } else { + lg::die("unknown version {}\n", version); + } + return shadow_datas; +} + std::vector convert_vertices(const ShadowData& data) { std::vector result; @@ -311,6 +330,51 @@ std::vector convert_edges(const std::vector& edg return result; } +void add_data_to_level(tfrag3::ShadowModelGroup& sd, const std::vector& fragments) { + if (fragments.empty()) { + return; + } + auto& model = sd.models.emplace_back(); + model.name = fragments.front().name; + model.max_bones = fragments.front().num_joints; + + for (auto& in_frag : fragments) { + auto& out_frag = model.fragments.emplace_back(); + + out_frag.single_tris = convert_tris(in_frag.single_tris); + out_frag.double_tris = convert_tris(in_frag.double_tris); + out_frag.single_edges = convert_edges(in_frag.single_edges); + out_frag.double_edges = convert_edges(in_frag.double_edges); + + const u32 vertex_offset = sd.vertices.size(); + + out_frag.first_vertex = vertex_offset; + out_frag.num_one_bone_vertices = in_frag.one_bone_vertices.size(); + out_frag.num_two_bone_vertices = in_frag.two_bone_vertices.size(); + ASSERT(out_frag.num_one_bone_vertices + out_frag.num_two_bone_vertices <= + tfrag3::ShadowModel::kMaxVertices); + ASSERT(out_frag.single_tris.size() + out_frag.double_tris.size() <= + tfrag3::ShadowModel::kMaxTris); + + // insert top vertices + auto vertices = convert_vertices(in_frag); + sd.vertices.insert(sd.vertices.end(), vertices.begin(), vertices.end()); + + // bottom vertices + for (auto& v : vertices) { + v.flags = 1; + } + sd.vertices.insert(sd.vertices.end(), vertices.begin(), vertices.end()); + } + // if (dump_level) { + // auto file_path = file_util::get_file_path( + // {"debug_out/shadow", fmt::format("{}_{}.ply", ag_data.name_in_dgo, i)}); + // file_util::create_dir_if_needed_for_file(file_path); + // file_util::write_text_file(file_path, debug_dump_to_ply(data)); + // } + // i++; +} + void extract_shadow(const ObjectFileData& ag_data, const DecompilerTypeSystem& dts, tfrag3::Level& out, @@ -322,50 +386,28 @@ void extract_shadow(const ObjectFileData& ag_data, if (dump_level) { file_util::create_dir_if_needed(file_util::get_file_path({"debug_out/shadow"})); } - auto geo_locations = find_objects_with_type(ag_data.linked_data, "shadow-geo"); - if (!geo_locations.empty()) { - lg::error("{} has {} shadows", ag_data.name_in_dgo, geo_locations.size()); - } - - int i = 0; auto& sd = out.shadow_data; - for (auto loc : geo_locations) { - const ShadowData data = extract_shadow_data(ag_data.linked_data, dts, loc); - auto& model = sd.models.emplace_back(); - model.name = data.name; - model.max_bones = data.num_joints; - model.single_tris = convert_tris(data.single_tris); - model.double_tris = convert_tris(data.double_tris); - model.single_edges = convert_edges(data.single_edges); - model.double_edges = convert_edges(data.double_edges); + if (version == GameVersion::Jak1) { + auto geo_locations = find_objects_with_type(ag_data.linked_data, "shadow-geo"); + // if (!geo_locations.empty()) { + // lg::error("{} has {} shadows", ag_data.name_in_dgo, geo_locations.size()); + // } - const u32 vertex_offset = sd.vertices.size(); - - model.first_vertex = vertex_offset; - model.num_one_bone_vertices = data.one_bone_vertices.size(); - model.num_two_bone_vertices = data.two_bone_vertices.size(); - ASSERT(model.num_one_bone_vertices + model.num_two_bone_vertices <= - tfrag3::ShadowModel::kMaxVertices); - ASSERT(model.single_tris.size() + model.double_tris.size() <= tfrag3::ShadowModel::kMaxTris); - - // insert top vertices - auto vertices = convert_vertices(data); - sd.vertices.insert(sd.vertices.end(), vertices.begin(), vertices.end()); - - // bottom vertices - for (auto& v : vertices) { - v.flags = 1; + for (auto loc : geo_locations) { + const ShadowData data = extract_jak1_shadow_data(ag_data.linked_data, dts, loc); + add_data_to_level(sd, {data}); } - sd.vertices.insert(sd.vertices.end(), vertices.begin(), vertices.end()); + } else { + // Jak2 has two versions of shadow. The "new" version has multiple fragments. + // Although there is a shadow-geo-old type in GOAL code, it's not actually used in the game + // data: both new and old types simply have shadow-geo type tags. + ASSERT(find_objects_with_type(ag_data.linked_data, "shadow-geo-old").empty()); - if (dump_level) { - auto file_path = file_util::get_file_path( - {"debug_out/shadow", fmt::format("{}_{}.ply", ag_data.name_in_dgo, i)}); - file_util::create_dir_if_needed_for_file(file_path); - file_util::write_text_file(file_path, debug_dump_to_ply(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); } - i++; } } } // namespace decompiler \ No newline at end of file diff --git a/docs/progress-notes/shadow.md b/docs/progress-notes/shadow.md index ba355bdb37..55e56db795 100644 --- a/docs/progress-notes/shadow.md +++ b/docs/progress-notes/shadow.md @@ -896,7 +896,7 @@ B3: ;; case where both tris are set. lbu t4, 3(t3) ;; t4 = tri-0.faces sll r0, r0, 0 lbu t5, 3(t5) ;; t5 = tri-1.faces - sltiu t3, t4, 1 ;; t3 = tri-0.faces < 1 + sltiu t3, t4, 1 ;; t3 = tri-0.faces < 1 = (tri0.faces == 0) == sll r0, r0, 0 beq t4, t5, L70 ;; if facing is equal skip this. sll r0, r0, 0 @@ -919,7 +919,7 @@ L68: ;; case where tri 1 is 255 B6: L69: dsubu t4, t1, t0 ;; t4 = edge idx - sh t3, 2(v1) ;; store (0, or, tri0.faces < 1) + sh t3, 2(v1) ;; store (0, or, tri0.faces == 0) sh t4, 0(v1) ;; store the edge idx. daddiu v1, v1, 4 B7: @@ -938,6 +938,62 @@ L71: daddu sp, sp, r0 ``` +## OOO add-facing-single-tris + +``` +L41: + lw v1, *shadow-data*(s7) + or a3, v1, r0 ;; a3 = shadow-data + lw v1, 20(a1) ;; v1 = num-facing + lw a0, 32(a1) ;; a0 = single-tri-list + beq v1, r0, L43 + daddiu a1, v1, 1 ;; a1 = num-facing + 1 + +B1: + daddiu a1, a1, 3 ;; a1 += 3 + dsra t0, a1, 2 ;; shift right/left to align + dsll a1, t0, 2 + daddiu t0, t0, 1 ;; add one + ld t1, 80(a3) ;; t1 = dma-cnt + daddu t0, t1, t0 ;; setup dma stuff + lw a3, 92(a3) ;; unpack + sd t0, 0(a2) ;; + addiu t0, r0, 16728 + sw r0, 8(a2) + sw a3, 12(a2) + sb a1, 14(a2) + dsll a1, a1, 2 + sh t0, 12(a2) + daddiu a2, a2, 16 + daddu a1, a2, a1 + sq r0, -16(a1) + sw v1, 0(a2) + daddiu a2, a2, 4 +B2: +L42: + lw a3, 0(a0) + daddiu a0, a0, 4 + lw a3, 0(a3) + daddiu v1, v1, -1 + sw a3, 0(a2) + daddiu a2, a2, 4 + bgtz v1, L42 + sll r0, r0, 0 + +B3: + or v1, a1, r0 + lui a0, 5376 + ori a0, a0, 2 + sq r0, 0(v1) + sw a0, 12(v1) + daddiu a2, v1, 16 +B4: +L43: + or v0, a2, r0 + jr ra + daddu sp, sp, r0 +``` + ## Find Facing Double Tris Same as single, but we don't build a list. @@ -961,33 +1017,33 @@ B1: B2: L52: daddiu a3, a3, -1 - lbu t3, 3(t1) + lbu t3, 3(t1) ;; t3 = tri1 sll r0, r0, 0 - lbu t4, 2(t1) + lbu t4, 2(t1) ;; t4 = tri0 beq t3, t2, L53 or t5, r0, r0 -B3: +B3: ;; if tri1 != 255 dsll t4, t4, 2 dsll t3, t3, 2 daddu t4, t4, t0 daddu t3, t3, t0 sll r0, r0, 0 - lbu t4, 3(t4) + lbu t4, 3(t4) ;; t4 = tri0->face sll r0, r0, 0 - lbu t3, 3(t3) - beq t4, t3, L54 + lbu t3, 3(t3) ;; t3 = tri1->face + beq t4, t3, L54 ;; skip if facing equal sll r0, r0, 0 B4: - sltiu t4, t4, 1 + sltiu t4, t4, 1 ;; t4 = (tri0->face == 0) sll r0, r0, 0 - sltu t3, r0, t3 + sltu t3, r0, t3 ;; t3 = (tri1->face != 0) sll r0, r0, 0 sll r0, r0, 0 - sh t4, 2(v1) + sh t4, 2(v1) ;; flip0 = (tri0->face == 0) dsubu t4, t1, a0 - sh t3, 6(v1) + sh t3, 6(v1) ;; flip1 = (tri1->face != 0) sll r0, r0, 0 sh t4, 0(v1) sll r0, r0, 0 @@ -996,7 +1052,7 @@ B4: daddiu v1, v1, 8 B5: -L53: +L53: ;; if tri1 == 255 dsll t3, t4, 2 sll r0, r0, 0 daddu t3, t3, t0 diff --git a/game/graphics/opengl_renderer/foreground/Shadow3.cpp b/game/graphics/opengl_renderer/foreground/Shadow3.cpp index af6558f21d..1e25e11e2d 100644 --- a/game/graphics/opengl_renderer/foreground/Shadow3.cpp +++ b/game/graphics/opengl_renderer/foreground/Shadow3.cpp @@ -105,126 +105,127 @@ void set_uniform(GLint uniform, const math::Vector4f& val) { void Shadow3::draw_model(SharedRenderState* render_state, ShadowRequest* request, ScopedProfilerNode& prof) { - ShadowCPUInput input{ - .origin = request->origin, - .top_plane = request->top_plane, - .bottom_plane = request->bottom_plane, - .light_dir = request->light_dir, - .bones = request->bones, - .model = request->model.model, - .vertices = &request->model.level->level->shadow_data.vertices, - .scissor_top = request->scissor_top, - .debug_highlight_tri = m_debug_tri, - }; - calc_shadow_indices(input, &m_cpu_workspace, &m_cpu_output); - glBindBuffer(GL_UNIFORM_BUFFER, m_opengl.bones_buffer); - glBindBufferRange(GL_UNIFORM_BUFFER, 1, m_opengl.bones_buffer, - sizeof(math::Vector4f) * request->bone_idx, 128 * 16 * 4); - // const auto* geo = request->model.model; - // printf("draw %s\n", geo->name.c_str()); + for (const auto& frag : request->model.model->fragments) { + ShadowCPUInput input{ + .origin = request->origin, + .top_plane = request->top_plane, + .bottom_plane = request->bottom_plane, + .light_dir = request->light_dir, + .bones = request->bones, + .model = &frag, + .vertices = &request->model.level->level->shadow_data.vertices, + .scissor_top = request->scissor_top, + .debug_highlight_tri = m_debug_tri, + }; + calc_shadow_indices(input, &m_cpu_workspace, &m_cpu_output); + glBindBuffer(GL_UNIFORM_BUFFER, m_opengl.bones_buffer); + glBindBufferRange(GL_UNIFORM_BUFFER, 1, m_opengl.bones_buffer, + sizeof(math::Vector4f) * request->bone_idx, 128 * 16 * 4); + // const auto* geo = request->model.model; + // printf("draw %s\n", geo->name.c_str()); - set_uniform(m_uniforms.origin, request->origin); - set_uniform(m_uniforms.top_plane, request->top_plane); - set_uniform(m_uniforms.bottom_plane, request->bottom_plane); - glUniform1i(m_uniforms.scissor_top, request->scissor_top); + set_uniform(m_uniforms.origin, request->origin); + set_uniform(m_uniforms.top_plane, request->top_plane); + set_uniform(m_uniforms.bottom_plane, request->bottom_plane); + glUniform1i(m_uniforms.scissor_top, request->scissor_top); - if (m_hacks) { - auto* model = request->model.model; - int num_verts = model->num_one_bone_vertices + model->num_two_bone_vertices; - std::vector verts; - for (size_t i = 0; i < num_verts; ++i) { - auto& out = verts.emplace_back(); - out.flags = 255; - out.mats[0] = 255; - out.mats[1] = 255; - out.pos[0] = m_cpu_workspace.vertices[i].x(); - out.pos[1] = m_cpu_workspace.vertices[i].y(); - out.pos[2] = m_cpu_workspace.vertices[i].z(); - out.weight = m_cpu_workspace.vertices[i].w(); - } + if (m_hacks) { + int num_verts = frag.num_one_bone_vertices + frag.num_two_bone_vertices; + std::vector verts; + for (size_t i = 0; i < num_verts; ++i) { + auto& out = verts.emplace_back(); + out.flags = 255; + out.mats[0] = 255; + out.mats[1] = 255; + out.pos[0] = m_cpu_workspace.vertices[i].x(); + out.pos[1] = m_cpu_workspace.vertices[i].y(); + out.pos[2] = m_cpu_workspace.vertices[i].z(); + out.weight = m_cpu_workspace.vertices[i].w(); + } - for (size_t i = 0; i < num_verts; ++i) { - auto& out = verts.emplace_back(); - out.flags = 255; - out.mats[0] = 255; - out.mats[1] = 255; - out.pos[0] = m_cpu_workspace.dual_vertices[i].x(); - out.pos[1] = m_cpu_workspace.dual_vertices[i].y(); - out.pos[2] = m_cpu_workspace.dual_vertices[i].z(); - out.weight = m_cpu_workspace.dual_vertices[i].w(); - } + for (size_t i = 0; i < num_verts; ++i) { + auto& out = verts.emplace_back(); + out.flags = 255; + out.mats[0] = 255; + out.mats[1] = 255; + out.pos[0] = m_cpu_workspace.dual_vertices[i].x(); + out.pos[1] = m_cpu_workspace.dual_vertices[i].y(); + out.pos[2] = m_cpu_workspace.dual_vertices[i].z(); + out.weight = m_cpu_workspace.dual_vertices[i].w(); + } - glEnable(GL_DEPTH_TEST); - glDisable(GL_BLEND); - glDepthFunc(GL_GEQUAL); - glDepthMask(GL_TRUE); - glEnable(GL_CULL_FACE); - glCullFace(m_cull_back ? GL_BACK : GL_FRONT); - glBindBuffer(GL_ARRAY_BUFFER, m_opengl.debug_verts); - glBufferData(GL_ARRAY_BUFFER, num_verts * 2 * sizeof(tfrag3::ShadowVertex), verts.data(), - GL_DYNAMIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_opengl.indices); - set_uniform(m_uniforms.debug_color, math::Vector3f(0.5f, 0.5f, 0.5f)); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_cpu_output.num_f0_indices * sizeof(u32), - m_cpu_output.f0_indices, GL_DYNAMIC_DRAW); - glDrawElements(GL_TRIANGLES, m_cpu_output.num_f0_indices, GL_UNSIGNED_INT, nullptr); - set_uniform(m_uniforms.debug_color, math::Vector3f(0.f, 0.f, 0.f)); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glDrawElements(GL_TRIANGLES, m_cpu_output.num_f0_indices, GL_UNSIGNED_INT, nullptr); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_cpu_output.num_f1_indices * sizeof(u32), - m_cpu_output.f1_indices, GL_DYNAMIC_DRAW); - set_uniform(m_uniforms.debug_color, math::Vector3f(0.f, 0.f, 0.f)); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glDrawElements(GL_TRIANGLES, m_cpu_output.num_f1_indices, GL_UNSIGNED_INT, nullptr); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); - set_uniform(m_uniforms.debug_color, math::Vector3f(0.5f, 0.78f, 0.5f)); - glDrawElements(GL_TRIANGLES, m_cpu_output.num_f1_indices, GL_UNSIGNED_INT, nullptr); - - glBindBuffer(GL_ARRAY_BUFFER, request->model.level->shadow_vertices); - glDisable(GL_CULL_FACE); - - } else { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_opengl.indices); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_cpu_output.num_indices * sizeof(u32), - m_cpu_output.indices, GL_DYNAMIC_DRAW); - // enable stencil! - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // no color writes. - glEnable(GL_STENCIL_TEST); - glStencilMask(0xFF); - glEnable(GL_DEPTH_TEST); - glDisable(GL_BLEND); - glDepthFunc(GL_GEQUAL); - glDepthMask(GL_FALSE); // no depth writes. - - if (false) { + glEnable(GL_DEPTH_TEST); + glDisable(GL_BLEND); + glDepthFunc(GL_GEQUAL); + glDepthMask(GL_TRUE); glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - glStencilFunc(GL_ALWAYS, 0, 0); // always pass stencil - glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // increment on depth fail - glDrawElements(GL_TRIANGLES, m_cpu_output.num_indices, GL_UNSIGNED_INT, nullptr); - glCullFace(GL_FRONT); - glStencilFunc(GL_ALWAYS, 0, 0); - glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); // decrement on depth pass. - glDrawElements(GL_TRIANGLES, m_cpu_output.num_indices, GL_UNSIGNED_INT, nullptr); + glCullFace(m_cull_back ? GL_BACK : GL_FRONT); + glBindBuffer(GL_ARRAY_BUFFER, m_opengl.debug_verts); + glBufferData(GL_ARRAY_BUFFER, num_verts * 2 * sizeof(tfrag3::ShadowVertex), verts.data(), + GL_DYNAMIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_opengl.indices); + set_uniform(m_uniforms.debug_color, math::Vector3f(0.5f, 0.5f, 0.5f)); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_cpu_output.num_f0_indices * sizeof(u32), + m_cpu_output.f0_indices, GL_DYNAMIC_DRAW); + glDrawElements(GL_TRIANGLES, m_cpu_output.num_f0_indices, GL_UNSIGNED_INT, nullptr); + set_uniform(m_uniforms.debug_color, math::Vector3f(0.f, 0.f, 0.f)); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glDrawElements(GL_TRIANGLES, m_cpu_output.num_f0_indices, GL_UNSIGNED_INT, nullptr); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_cpu_output.num_f1_indices * sizeof(u32), + m_cpu_output.f1_indices, GL_DYNAMIC_DRAW); + set_uniform(m_uniforms.debug_color, math::Vector3f(0.f, 0.f, 0.f)); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glDrawElements(GL_TRIANGLES, m_cpu_output.num_f1_indices, GL_UNSIGNED_INT, nullptr); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); + set_uniform(m_uniforms.debug_color, math::Vector3f(0.5f, 0.78f, 0.5f)); + glDrawElements(GL_TRIANGLES, m_cpu_output.num_f1_indices, GL_UNSIGNED_INT, nullptr); + + glBindBuffer(GL_ARRAY_BUFFER, request->model.level->shadow_vertices); + glDisable(GL_CULL_FACE); + } else { - glEnable(GL_CULL_FACE); - glCullFace(GL_FRONT); - glStencilFunc(GL_ALWAYS, 0, 0); // always pass stencil - glStencilOp(GL_KEEP, GL_INCR, GL_KEEP); // increment on depth fail - glDrawElements(GL_TRIANGLES, m_cpu_output.num_indices, GL_UNSIGNED_INT, nullptr); - glCullFace(GL_BACK); - glStencilFunc(GL_ALWAYS, 0, 0); - glStencilOp(GL_KEEP, GL_DECR, GL_KEEP); // decrement on depth pass. - glDrawElements(GL_TRIANGLES, m_cpu_output.num_indices, GL_UNSIGNED_INT, nullptr); - } + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_opengl.indices); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_cpu_output.num_indices * sizeof(u32), + m_cpu_output.indices, GL_DYNAMIC_DRAW); + // enable stencil! + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // no color writes. + glEnable(GL_STENCIL_TEST); + glStencilMask(0xFF); + glEnable(GL_DEPTH_TEST); + glDisable(GL_BLEND); + glDepthFunc(GL_GEQUAL); + glDepthMask(GL_FALSE); // no depth writes. - glDisable(GL_CULL_FACE); + if (false) { + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + glStencilFunc(GL_ALWAYS, 0, 0); // always pass stencil + glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // increment on depth fail + glDrawElements(GL_TRIANGLES, m_cpu_output.num_indices, GL_UNSIGNED_INT, nullptr); + glCullFace(GL_FRONT); + glStencilFunc(GL_ALWAYS, 0, 0); + glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); // decrement on depth pass. + glDrawElements(GL_TRIANGLES, m_cpu_output.num_indices, GL_UNSIGNED_INT, nullptr); + } else { + glEnable(GL_CULL_FACE); + glCullFace(GL_FRONT); + glStencilFunc(GL_ALWAYS, 0, 0); // always pass stencil + glStencilOp(GL_KEEP, GL_INCR, GL_KEEP); // increment on depth fail + glDrawElements(GL_TRIANGLES, m_cpu_output.num_indices, GL_UNSIGNED_INT, nullptr); + glCullFace(GL_BACK); + glStencilFunc(GL_ALWAYS, 0, 0); + glStencilOp(GL_KEEP, GL_DECR, GL_KEEP); // decrement on depth pass. + glDrawElements(GL_TRIANGLES, m_cpu_output.num_indices, GL_UNSIGNED_INT, nullptr); + } + + glDisable(GL_CULL_FACE); + } } } diff --git a/game/graphics/opengl_renderer/foreground/Shadow3CPU.h b/game/graphics/opengl_renderer/foreground/Shadow3CPU.h index b2dd970ca3..80ffc36661 100644 --- a/game/graphics/opengl_renderer/foreground/Shadow3CPU.h +++ b/game/graphics/opengl_renderer/foreground/Shadow3CPU.h @@ -7,7 +7,7 @@ struct ShadowCPUInput { math::Vector4f top_plane, bottom_plane; math::Vector3f light_dir; const u8* bones = nullptr; - const tfrag3::ShadowModel* model = nullptr; + const tfrag3::ShadowModelFragment* model = nullptr; std::vector* vertices = nullptr; bool scissor_top = false; int debug_highlight_tri = 0;