2022-06-19 20:44:07 -04:00
|
|
|
#include "collide_drawable.h"
|
2022-06-22 23:37:46 -04:00
|
|
|
|
2022-12-22 13:41:33 -05:00
|
|
|
#include <unordered_map>
|
2022-08-05 12:25:35 -04:00
|
|
|
#include <unordered_set>
|
|
|
|
|
2022-06-19 20:44:07 -04:00
|
|
|
#include "common/util/Assert.h"
|
|
|
|
|
2022-06-22 23:37:46 -04:00
|
|
|
#include "goalc/data_compiler/DataObjectGenerator.h"
|
|
|
|
|
2022-06-19 20:44:07 -04:00
|
|
|
/*
|
|
|
|
(deftype drawable (basic)
|
|
|
|
((id int16 :offset-assert 4)
|
|
|
|
(bsphere vector :inline :offset-assert 16)
|
|
|
|
)
|
|
|
|
|
|
|
|
(deftype drawable-group (drawable)
|
|
|
|
((length int16 :offset 6)
|
|
|
|
(data drawable 1 :offset-assert 32)
|
|
|
|
)
|
|
|
|
|
|
|
|
(deftype drawable-tree (drawable-group)
|
|
|
|
()
|
|
|
|
|
|
|
|
(deftype drawable-inline-array (drawable)
|
|
|
|
((length int16 :offset 6) ;; this is kinda weird.
|
|
|
|
)
|
|
|
|
|
|
|
|
(deftype drawable-tree-collide-fragment (drawable-tree)
|
|
|
|
((data-override drawable-inline-array 1 :offset 32)) ;; should be 1 there
|
|
|
|
|
|
|
|
(deftype drawable-inline-array-collide-fragment (drawable-inline-array)
|
|
|
|
((data collide-fragment 1 :inline :offset-assert 32)
|
|
|
|
|
|
|
|
(deftype collide-fragment (drawable)
|
|
|
|
((mesh collide-frag-mesh :offset 8)
|
|
|
|
)
|
|
|
|
:method-count-assert 18
|
|
|
|
:size-assert #x20
|
|
|
|
|
|
|
|
(deftype collide-frag-mesh (basic)
|
|
|
|
((packed-data uint32 :offset-assert 4)
|
|
|
|
(pat-array uint32 :offset-assert 8)
|
|
|
|
(strip-data-len uint16 :offset-assert 12)
|
|
|
|
(poly-count uint16 :offset-assert 14)
|
|
|
|
(base-trans vector :inline :offset-assert 16)
|
|
|
|
;; these go in the w of the vector above.
|
|
|
|
(vertex-count uint8 :offset 28)
|
|
|
|
(vertex-data-qwc uint8 :offset 29)
|
|
|
|
(total-qwc uint8 :offset 30)
|
|
|
|
(unused uint8 :offset 31)
|
|
|
|
)
|
|
|
|
:method-count-assert 9
|
|
|
|
:size-assert #x20
|
|
|
|
|
|
|
|
(deftype draw-node (drawable)
|
|
|
|
((child-count uint8 :offset 6)
|
|
|
|
(flags uint8 :offset 7)
|
|
|
|
(child drawable :offset 8)
|
|
|
|
(distance float :offset 12)
|
|
|
|
)
|
|
|
|
:size-assert #x20
|
|
|
|
|
|
|
|
(deftype drawable-inline-array-node (drawable-inline-array)
|
|
|
|
((data draw-node 1 :inline)
|
|
|
|
(pad uint32)
|
|
|
|
)
|
|
|
|
:method-count-assert 18
|
|
|
|
:size-assert #x44
|
|
|
|
*/
|
|
|
|
|
|
|
|
size_t generate_pat_array(DataObjectGenerator& gen, const std::vector<PatSurface>& pats) {
|
|
|
|
gen.align_to_basic();
|
|
|
|
size_t result = gen.current_offset_bytes();
|
|
|
|
for (auto& pat : pats) {
|
|
|
|
gen.add_word(pat.val);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t generate_packed_collide_data(DataObjectGenerator& gen, const std::vector<u8>& data) {
|
|
|
|
gen.align_to_basic();
|
|
|
|
size_t result = gen.current_offset_bytes();
|
|
|
|
ASSERT((data.size() % 4) == 0);
|
|
|
|
for (size_t i = 0; i < data.size(); i += 4) {
|
|
|
|
u32 word;
|
|
|
|
memcpy(&word, data.data() + i, 4);
|
|
|
|
gen.add_word(word);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t generate_collide_frag_mesh(DataObjectGenerator& gen,
|
|
|
|
const CollideFragMeshData& mesh,
|
|
|
|
size_t packed_data_loc,
|
|
|
|
size_t pat_array_loc) {
|
|
|
|
gen.align_to_basic();
|
|
|
|
gen.add_type_tag("collide-frag-mesh"); // 0
|
|
|
|
size_t result = gen.current_offset_bytes();
|
|
|
|
gen.link_word_to_byte(gen.add_word(0), packed_data_loc); // 4
|
|
|
|
gen.link_word_to_byte(gen.add_word(0), pat_array_loc); // 8
|
|
|
|
gen.add_word(mesh.strip_data_len | (mesh.poly_count << 16)); // 12
|
|
|
|
gen.add_word(mesh.base_trans_xyz_s32.x()); // 16
|
|
|
|
gen.add_word(mesh.base_trans_xyz_s32.y()); // 20
|
|
|
|
gen.add_word(mesh.base_trans_xyz_s32.z()); // 24
|
|
|
|
u32 packed = 0;
|
|
|
|
packed |= mesh.vertex_count;
|
|
|
|
packed |= ((u32)mesh.vertex_data_qwc) << 8;
|
|
|
|
packed |= ((u32)mesh.total_qwc) << 16;
|
|
|
|
gen.add_word(packed); // 28
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t generate_collide_fragment(DataObjectGenerator& gen,
|
|
|
|
const CollideFragMeshData& mesh,
|
|
|
|
size_t frag_mesh_loc) {
|
|
|
|
/*
|
|
|
|
.type collide-fragment
|
|
|
|
.word 0x10000
|
|
|
|
.word L705
|
|
|
|
.word 0x0
|
|
|
|
.word 0x46bf480a
|
|
|
|
.word 0x43dc730b
|
|
|
|
.word 0xb71ed4fe
|
|
|
|
.word 0x46c42e44
|
|
|
|
*/
|
|
|
|
gen.align_to_basic();
|
|
|
|
gen.add_type_tag("collide-fragment");
|
|
|
|
size_t result = gen.current_offset_bytes();
|
|
|
|
gen.add_word(0x10000); // ???
|
|
|
|
gen.link_word_to_byte(gen.add_word(0), frag_mesh_loc);
|
|
|
|
gen.add_word(0);
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
gen.add_word_float(mesh.bsphere[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t generate_collide_fragment_array(DataObjectGenerator& gen,
|
|
|
|
const std::vector<CollideFragMeshData>& meshes,
|
|
|
|
const std::vector<size_t>& frag_mesh_locs,
|
2022-08-05 12:25:35 -04:00
|
|
|
std::vector<size_t>& loc_out) {
|
2022-06-19 20:44:07 -04:00
|
|
|
gen.align_to_basic();
|
|
|
|
gen.add_type_tag("drawable-inline-array-collide-fragment"); // 0
|
|
|
|
size_t result = gen.current_offset_bytes();
|
|
|
|
ASSERT(meshes.size() < UINT16_MAX);
|
|
|
|
gen.add_word(meshes.size() << 16); // 4, 6
|
|
|
|
gen.add_word(0); // 8
|
|
|
|
gen.add_word(0); // 12
|
|
|
|
gen.add_word(0); // 16
|
|
|
|
gen.add_word(0); // 20
|
|
|
|
gen.add_word(0); // 24
|
|
|
|
gen.add_word(0); // 28
|
|
|
|
|
|
|
|
ASSERT(meshes.size() == frag_mesh_locs.size());
|
|
|
|
for (size_t i = 0; i < meshes.size(); i++) {
|
|
|
|
auto& mesh = meshes[i];
|
|
|
|
// should be 8 words here:
|
|
|
|
gen.add_type_tag("collide-fragment"); // 1
|
|
|
|
size_t me = gen.current_offset_bytes();
|
|
|
|
gen.add_word(0x10000); // ???
|
|
|
|
gen.link_word_to_byte(gen.add_word(0), frag_mesh_locs[i]);
|
|
|
|
gen.add_word(0);
|
|
|
|
for (int j = 0; j < 4; j++) {
|
|
|
|
gen.add_word_float(mesh.bsphere[j]);
|
|
|
|
}
|
2022-08-05 12:25:35 -04:00
|
|
|
loc_out.push_back(me);
|
2022-06-19 20:44:07 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-08-05 12:25:35 -04:00
|
|
|
int child_count(const collide::DrawNode* node) {
|
|
|
|
if (node->frag_children.empty()) {
|
|
|
|
return node->draw_node_children.size();
|
|
|
|
} else {
|
|
|
|
return node->frag_children.size();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unordered_map<const collide::DrawNode*, size_t> add_draw_nodes(
|
|
|
|
DataObjectGenerator& gen,
|
|
|
|
const std::vector<const collide::DrawNode*>& nodes,
|
|
|
|
const std::vector<size_t>& frag_locs,
|
|
|
|
size_t& array_out) {
|
|
|
|
std::unordered_map<const collide::DrawNode*, size_t> result;
|
|
|
|
std::unordered_map<size_t, const collide::DrawNode*> back_map;
|
|
|
|
|
2022-06-19 20:44:07 -04:00
|
|
|
gen.align_to_basic();
|
|
|
|
gen.add_type_tag("drawable-inline-array-node"); // 0
|
2022-08-05 12:25:35 -04:00
|
|
|
array_out = gen.current_offset_bytes();
|
|
|
|
ASSERT(nodes.size() < UINT16_MAX);
|
2022-06-19 20:44:07 -04:00
|
|
|
gen.add_word(nodes.size() << 16); // 4, 6
|
|
|
|
gen.add_word(0); // 8
|
|
|
|
gen.add_word(0); // 12
|
|
|
|
gen.add_word(0); // 16
|
|
|
|
gen.add_word(0); // 20
|
|
|
|
gen.add_word(0); // 24
|
|
|
|
gen.add_word(0); // 28
|
|
|
|
|
2022-08-05 12:25:35 -04:00
|
|
|
for (auto& node : nodes) {
|
|
|
|
bool is_draw_node = node->frag_children.empty();
|
|
|
|
|
2022-06-19 20:44:07 -04:00
|
|
|
// should be 8 words here:
|
|
|
|
gen.add_type_tag("draw-node"); // 1
|
|
|
|
size_t me = gen.current_offset_bytes();
|
|
|
|
u32 packed_flags = 0;
|
2022-08-05 12:25:35 -04:00
|
|
|
packed_flags |=
|
|
|
|
((is_draw_node ? node->draw_node_children.size() : node->frag_children.size()) << 16);
|
|
|
|
packed_flags |= ((is_draw_node ? 1 : 0) << 24);
|
|
|
|
gen.add_word(packed_flags); // 2
|
|
|
|
if (is_draw_node) {
|
|
|
|
// gen.link_word_to_byte(gen.add_word(0), result.at(&node->draw_node_children.at(0))); // 3
|
|
|
|
back_map[gen.add_word(0)] = &node->draw_node_children.at(0);
|
|
|
|
} else {
|
|
|
|
gen.link_word_to_byte(gen.add_word(0), frag_locs.at(node->frag_children.at(0)));
|
2022-06-19 20:44:07 -04:00
|
|
|
}
|
2022-08-05 12:25:35 -04:00
|
|
|
|
|
|
|
result[node] = me;
|
|
|
|
|
|
|
|
gen.add_word(0); // 4
|
|
|
|
|
|
|
|
gen.add_word_float(node->bsphere.x()); // 5
|
|
|
|
gen.add_word_float(node->bsphere.y()); // 6
|
|
|
|
gen.add_word_float(node->bsphere.z()); // 7
|
|
|
|
gen.add_word_float(node->bsphere.w()); // 8
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto& [loc, node] : back_map) {
|
|
|
|
gen.link_word_to_byte(loc, result.at(node));
|
2022-06-19 20:44:07 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-08-05 12:25:35 -04:00
|
|
|
std::vector<const collide::DrawNode*> bfs_nodes(const collide::DrawNode& fake_root) {
|
|
|
|
std::vector<const collide::DrawNode*> out;
|
|
|
|
std::unordered_set<const collide::DrawNode*> added;
|
|
|
|
std::vector<const collide::DrawNode*> frontier;
|
|
|
|
for (auto& dnc : fake_root.draw_node_children) {
|
|
|
|
frontier.push_back(&dnc);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (!frontier.empty()) {
|
|
|
|
std::vector<const collide::DrawNode*> next_frontier;
|
|
|
|
|
|
|
|
for (auto x : frontier) {
|
|
|
|
if (added.find(x) != added.end()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
added.insert(x);
|
|
|
|
out.push_back(x);
|
|
|
|
|
|
|
|
for (auto& child : x->draw_node_children) {
|
|
|
|
if (added.find(&child) == added.end()) {
|
|
|
|
next_frontier.push_back(&child);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
frontier = std::move(next_frontier);
|
|
|
|
}
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2022-06-19 20:44:07 -04:00
|
|
|
size_t DrawableTreeCollideFragment::add_to_object_file(DataObjectGenerator& gen) const {
|
|
|
|
// generate pat array
|
|
|
|
size_t pat_array_loc = generate_pat_array(gen, packed_frags.pats);
|
|
|
|
|
|
|
|
// generated packed data
|
|
|
|
std::vector<size_t> packed_data_locs;
|
|
|
|
for (auto& mesh : packed_frags.packed_frag_data) {
|
|
|
|
packed_data_locs.push_back(generate_packed_collide_data(gen, mesh.packed_data));
|
|
|
|
}
|
|
|
|
|
|
|
|
// generate collide frag meshes
|
|
|
|
std::vector<size_t> collide_frag_meshes;
|
|
|
|
for (size_t i = 0; i < packed_data_locs.size(); i++) {
|
|
|
|
collide_frag_meshes.push_back(generate_collide_frag_mesh(gen, packed_frags.packed_frag_data[i],
|
|
|
|
packed_data_locs[i], pat_array_loc));
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<size_t> children_refs;
|
2022-08-05 12:25:35 -04:00
|
|
|
generate_collide_fragment_array(gen, packed_frags.packed_frag_data, collide_frag_meshes,
|
|
|
|
children_refs);
|
|
|
|
|
|
|
|
auto order = bfs_nodes(bvh.fake_root_node);
|
|
|
|
size_t others_array;
|
|
|
|
auto located_nodes = add_draw_nodes(gen, order, children_refs, others_array);
|
|
|
|
|
|
|
|
size_t root_dian = -1;
|
|
|
|
{
|
|
|
|
gen.align_to_basic();
|
|
|
|
gen.add_type_tag("drawable-inline-array-node"); // 0
|
|
|
|
root_dian = gen.current_offset_bytes();
|
|
|
|
gen.add_word(bvh.fake_root_node.draw_node_children.size() << 16); // 4, 6
|
|
|
|
gen.add_word(0); // 8
|
|
|
|
gen.add_word(0); // 12
|
|
|
|
gen.add_word(0); // 16
|
|
|
|
gen.add_word(0); // 20
|
|
|
|
gen.add_word(0); // 24
|
|
|
|
gen.add_word(0); // 28
|
|
|
|
|
|
|
|
for (auto& node : bvh.fake_root_node.draw_node_children) {
|
|
|
|
bool is_draw_node = node.frag_children.empty();
|
|
|
|
|
|
|
|
// should be 8 words here:
|
|
|
|
gen.add_type_tag("draw-node"); // 1
|
|
|
|
|
|
|
|
u32 packed_flags = 0;
|
|
|
|
packed_flags |=
|
|
|
|
((is_draw_node ? node.draw_node_children.size() : node.frag_children.size()) << 16);
|
|
|
|
packed_flags |= ((is_draw_node ? 1 : 0) << 24);
|
|
|
|
gen.add_word(packed_flags); // 2
|
|
|
|
if (is_draw_node) {
|
|
|
|
gen.link_word_to_byte(gen.add_word(0),
|
|
|
|
located_nodes.at(&node.draw_node_children.at(0))); // 3
|
|
|
|
} else {
|
|
|
|
gen.link_word_to_byte(gen.add_word(0), children_refs.at(node.frag_children.at(0)));
|
|
|
|
}
|
|
|
|
|
|
|
|
gen.add_word(0); // 4
|
|
|
|
gen.add_word_float(node.bsphere.x()); // 5
|
|
|
|
gen.add_word_float(node.bsphere.y()); // 6
|
|
|
|
gen.add_word_float(node.bsphere.z()); // 7
|
|
|
|
gen.add_word_float(node.bsphere.w()); // 8
|
|
|
|
}
|
2022-06-19 20:44:07 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
gen.align_to_basic();
|
|
|
|
gen.add_type_tag("drawable-tree-collide-fragment");
|
|
|
|
size_t result = gen.current_offset_bytes();
|
2022-08-05 12:25:35 -04:00
|
|
|
gen.add_word(2 << 16); // todo the minus one here??
|
2022-06-19 20:44:07 -04:00
|
|
|
for (int i = 0; i < 6; i++) {
|
|
|
|
gen.add_word(0);
|
|
|
|
}
|
|
|
|
|
2022-08-05 12:25:35 -04:00
|
|
|
gen.link_word_to_byte(gen.add_word(0), root_dian);
|
|
|
|
gen.link_word_to_byte(gen.add_word(0), others_array);
|
2022-06-19 20:44:07 -04:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|