mirror of
https://github.com/open-goal/jak-project
synced 2026-06-21 08:41:48 -04:00
jak2 support
This commit is contained in:
@@ -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<size_t>(fragments.size());
|
||||
} else {
|
||||
fragments.resize(ser.load<size_t>());
|
||||
}
|
||||
for (auto& frag : fragments) {
|
||||
frag.serialize(ser);
|
||||
}
|
||||
}
|
||||
|
||||
void ShadowModelGroup::serialize(Serializer& ser) {
|
||||
ser.from_pod_vector(&vertices);
|
||||
if (ser.is_saving()) {
|
||||
|
||||
@@ -634,18 +634,21 @@ struct ShadowEdge {
|
||||
u8 tri[2];
|
||||
};
|
||||
|
||||
struct ShadowModelFragment {
|
||||
std::vector<ShadowTri> single_tris, double_tris;
|
||||
std::vector<ShadowEdge> 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<ShadowTri> single_tris, double_tris;
|
||||
std::vector<ShadowEdge> single_edges, double_edges;
|
||||
|
||||
u32 first_vertex;
|
||||
u32 num_one_bone_vertices;
|
||||
u32 num_two_bone_vertices;
|
||||
std::vector<ShadowModelFragment> fragments;
|
||||
|
||||
void serialize(Serializer& ser);
|
||||
};
|
||||
|
||||
@@ -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<s32>(header_ref, "qwc-data", dts);
|
||||
ASSERT(size_qwc < 1024 * 1024); // something reasonable
|
||||
std::vector<u8> 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<s32>(header_ref, "num-joints", dts), data.size());
|
||||
// lg::info("name is {}, has {} joints, size {} bytes", name,
|
||||
// read_plain_data_field<s32>(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<s32>(header_ref, "num-joints", dts);
|
||||
shadow_data.name = name;
|
||||
shadow_data.num_joints = num_joints;
|
||||
|
||||
const u32 num_verts = read_plain_data_field<u16>(header_ref, "num-verts", dts);
|
||||
const u32 num_twos = read_plain_data_field<u16>(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<u32>(header_ref, "ofs-verts", dts);
|
||||
const u32 ofs_refs = read_plain_data_field<u32>(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<s32>(header_ref, "qwc-data", dts);
|
||||
const std::string name = read_string_field(tr, "name", dts, false);
|
||||
int num_joints = read_plain_data_field<s32>(header_ref, "num-joints", dts);
|
||||
return extract_shadow_data(file, dts, header_ref, name, size_qwc, num_joints);
|
||||
}
|
||||
|
||||
std::vector<ShadowData> extract_jak2_shadow_data(const LinkedObjectFile& file,
|
||||
const DecompilerTypeSystem& dts,
|
||||
int geo_word_idx) {
|
||||
std::vector<ShadowData> 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<u32>(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<s32>(header_ref, "qwc-data", dts);
|
||||
int num_joints = read_plain_data_field<s32>(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<u32>(tr, "num-joints", dts);
|
||||
uint32_t num_fragments = read_plain_data_field<u32>(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<s32>(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<tfrag3::ShadowVertex> convert_vertices(const ShadowData& data) {
|
||||
std::vector<tfrag3::ShadowVertex> result;
|
||||
|
||||
@@ -311,6 +330,51 @@ std::vector<tfrag3::ShadowEdge> convert_edges(const std::vector<ShadowEdge>& edg
|
||||
return result;
|
||||
}
|
||||
|
||||
void add_data_to_level(tfrag3::ShadowModelGroup& sd, const std::vector<ShadowData>& 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
|
||||
@@ -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
|
||||
|
||||
@@ -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<tfrag3::ShadowVertex> 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<tfrag3::ShadowVertex> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<tfrag3::ShadowVertex>* vertices = nullptr;
|
||||
bool scissor_top = false;
|
||||
int debug_highlight_tri = 0;
|
||||
|
||||
Reference in New Issue
Block a user