jak2 support

This commit is contained in:
water111
2025-06-18 21:02:30 -04:00
parent d1a3aa1761
commit ca19e25b7f
6 changed files with 338 additions and 224 deletions
+15 -3
View File
@@ -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()) {
+10 -7
View File
@@ -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);
};
+129 -87
View File
@@ -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
+69 -13
View File
@@ -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;