mirror of
https://github.com/open-goal/jak-project
synced 2026-06-02 18:19:07 -04:00
add code to BspHeader to get GOAL types for shrubs
This commit is contained in:
@@ -135,6 +135,10 @@ std::unique_ptr<Drawable> make_draw_node_child(TypedRef ref,
|
||||
auto result = std::make_unique<DrawableActor>();
|
||||
result->read_from_file(ref, dts, stats);
|
||||
return result;
|
||||
} else if (ref.type->get_name() == "instance-shrubbery") {
|
||||
auto result = std::make_unique<shrub_types::InstanceShrubbery>();
|
||||
result->read_from_file(ref, dts, stats);
|
||||
return result;
|
||||
} else {
|
||||
throw Error("Unknown child of draw node: {}\n", ref.type->get_name());
|
||||
}
|
||||
@@ -149,6 +153,8 @@ int get_child_stride(const std::string& type) {
|
||||
return 64;
|
||||
} else if (type == "drawable-actor") {
|
||||
return 32;
|
||||
} else if (type == "instance-shrubbery") {
|
||||
return 80;
|
||||
} else {
|
||||
throw Error("unknown child for stride: {}", type);
|
||||
}
|
||||
@@ -752,6 +758,13 @@ std::unique_ptr<DrawableInlineArray> make_drawable_inline_array(
|
||||
result->read_from_file(ref, dts, stats);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (ref.type->get_name() == "drawable-inline-array-instance-shrub") {
|
||||
auto result = std::make_unique<shrub_types::DrawableInlineArrayInstanceShrub>();
|
||||
result->read_from_file(ref, dts, stats);
|
||||
return result;
|
||||
}
|
||||
|
||||
auto result = std::make_unique<DrawableInlineArrayUnknown>();
|
||||
result->read_from_file(ref, dts, stats);
|
||||
return result;
|
||||
@@ -872,7 +885,6 @@ void PrototypeBucketTie::read_from_file(TypedRef ref,
|
||||
assert(flags == 0 || flags == 2);
|
||||
in_level = read_plain_data_field<u16>(ref, "in-level", dts);
|
||||
utextures = read_plain_data_field<u16>(ref, "utextures", dts);
|
||||
// todo drawables
|
||||
dists.read_from_file(get_field_ref(ref, "dists", dts));
|
||||
rdists.read_from_file(get_field_ref(ref, "rdists", dts));
|
||||
stiffness = read_plain_data_field<float>(ref, "stiffness", dts);
|
||||
@@ -1106,6 +1118,362 @@ std::string DrawableTreeInstanceTie::my_type() const {
|
||||
return "drawable-tree-instance-tie";
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
// shrub
|
||||
//////////////////////////
|
||||
|
||||
namespace shrub_types {
|
||||
|
||||
void DrawableTreeInstanceShrub::read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
level_tools::DrawStats* stats) {
|
||||
// the usual drawable stuff
|
||||
id = read_plain_data_field<s16>(ref, "id", dts);
|
||||
length = read_plain_data_field<s16>(ref, "length", dts);
|
||||
bsphere.read_from_file(get_field_ref(ref, "bsphere", dts));
|
||||
|
||||
// unfortunately, shrub uses the arrays thing differently.
|
||||
// there's just one top level array, and the nodes are a bit scattered in memory below that.
|
||||
// it doesn't have the 8 child rule
|
||||
auto data_ref = get_field_ref(ref, "data", dts);
|
||||
if ((data_ref.byte_offset % 4) != 0) {
|
||||
throw Error("misaligned data array");
|
||||
}
|
||||
for (int idx = 0; idx < length; idx++) {
|
||||
Ref array_slot_ref = data_ref;
|
||||
array_slot_ref.byte_offset += idx * 4;
|
||||
|
||||
Ref object_ref = deref_label(array_slot_ref);
|
||||
object_ref.byte_offset -= 4;
|
||||
|
||||
arrays.push_back(make_drawable_inline_array(typed_ref_from_basic(object_ref, dts), dts, stats));
|
||||
}
|
||||
// confirm that we have the weird shrub pattern and only found one array.
|
||||
assert(length == 1);
|
||||
|
||||
// now, let's try to discover the remaining arrays (instances).
|
||||
// basically we just look after the top level array in memory.
|
||||
// once we find something else (the time of day palette) we know we're at the end.
|
||||
// the game finds these by traversing the tree, but this is a little easier, and gets us
|
||||
// the familiar arrays that we used in tie/tfrag.
|
||||
|
||||
Ref object_ref = deref_label(data_ref);
|
||||
object_ref.byte_offset -= 4;
|
||||
discovered_arrays.push_back(
|
||||
make_drawable_inline_array(typed_ref_from_basic(object_ref, dts), dts, stats));
|
||||
|
||||
bool done = false;
|
||||
object_ref.byte_offset += 16;
|
||||
while (!done) {
|
||||
auto& word = object_ref.data->words_by_seg.at(object_ref.seg).at(object_ref.byte_offset / 4);
|
||||
if (word.kind() == decompiler::LinkedWord::TYPE_PTR) {
|
||||
if (word.symbol_name() == "drawable-inline-array-node") {
|
||||
discovered_arrays.push_back(
|
||||
make_drawable_inline_array(typed_ref_from_basic(object_ref, dts), dts, stats));
|
||||
} else if (word.symbol_name() == "drawable-inline-array-instance-shrub") {
|
||||
discovered_arrays.push_back(
|
||||
make_drawable_inline_array(typed_ref_from_basic(object_ref, dts), dts, stats));
|
||||
} else if (word.symbol_name() == "time-of-day-palette") {
|
||||
done = true;
|
||||
} else {
|
||||
assert(word.symbol_name() == "draw-node" || word.symbol_name() == "instance-shrubbery");
|
||||
}
|
||||
}
|
||||
object_ref.byte_offset += 16;
|
||||
}
|
||||
|
||||
// this "info" thing holds all the prototypes
|
||||
auto pt = deref_label(get_field_ref(ref, "info", dts));
|
||||
pt.byte_offset -= 4;
|
||||
info.read_from_file(typed_ref_from_basic(pt, dts), dts, stats);
|
||||
|
||||
// time of day palette. we'll want these colors in the FR3 file.
|
||||
auto palette = deref_label(get_field_ref(ref, "colors-added", dts));
|
||||
time_of_day.width = deref_u32(palette, 0);
|
||||
assert(time_of_day.width == 8);
|
||||
time_of_day.height = deref_u32(palette, 1);
|
||||
time_of_day.pad = deref_u32(palette, 2);
|
||||
assert(time_of_day.pad == 0);
|
||||
for (int i = 0; i < int(8 * time_of_day.height); i++) {
|
||||
time_of_day.colors.push_back(deref_u32(palette, 3 + i));
|
||||
}
|
||||
}
|
||||
|
||||
std::string DrawableTreeInstanceShrub::my_type() const {
|
||||
return "drawable-tree-instance-shrub";
|
||||
}
|
||||
|
||||
std::string DrawableTreeInstanceShrub::print(const level_tools::PrintSettings& settings,
|
||||
int indent) const {
|
||||
if (!settings.expand_shrub) {
|
||||
return "";
|
||||
}
|
||||
std::string is(indent, ' ');
|
||||
std::string result;
|
||||
int next_indent = indent + 4;
|
||||
result += fmt::format("{}id: {}\n", is, id);
|
||||
result += fmt::format("{}length: {}\n", is, length);
|
||||
result += fmt::format("{}bsphere: {}", is, bsphere.print_meters());
|
||||
|
||||
if (settings.expand_shrub) {
|
||||
for (size_t i = 0; i < discovered_arrays.size(); i++) {
|
||||
result += fmt::format("{}arrays [{}] ({}):\n", is, i, discovered_arrays[i]->my_type());
|
||||
result += discovered_arrays[i]->print(settings, next_indent);
|
||||
}
|
||||
|
||||
result += fmt::format("{}prototypes:\n", is);
|
||||
result += info.print(settings, next_indent);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void InstanceShrubbery::read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
level_tools::DrawStats* /*stats*/) {
|
||||
bsphere.read_from_file(get_field_ref(ref, "bsphere", dts));
|
||||
bucket_index = read_plain_data_field<u16>(ref, "bucket-index", dts);
|
||||
id = read_plain_data_field<s16>(ref, "id", dts);
|
||||
origin.read_from_file(get_field_ref(ref, "origin", dts));
|
||||
wind_index = read_plain_data_field<u16>(ref, "wind-index", dts);
|
||||
color_indices = read_plain_data_field<u32>(ref, "color-indices", dts);
|
||||
flat_normal.read_from_file(get_field_ref(ref, "flat-normal", dts));
|
||||
}
|
||||
|
||||
std::string InstanceShrubbery::print(const level_tools::PrintSettings& /*settings*/,
|
||||
int indent) const {
|
||||
std::string is(indent, ' ');
|
||||
std::string result;
|
||||
result += fmt::format("{}bsphere: {}", is, bsphere.print_meters());
|
||||
result += fmt::format("{}bucket-index: {}\n", is, bucket_index);
|
||||
result += fmt::format("{}flat-normal: {}", is, flat_normal.print_meters());
|
||||
result += fmt::format("{}color-indices: {}\n", is, color_indices);
|
||||
result += fmt::format("{}wind-index: {}\n", is, wind_index);
|
||||
return result;
|
||||
}
|
||||
|
||||
void DrawableInlineArrayInstanceShrub::read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
DrawStats* stats) {
|
||||
id = read_plain_data_field<s16>(ref, "id", dts);
|
||||
length = read_plain_data_field<s16>(ref, "length", dts);
|
||||
bsphere.read_from_file(get_field_ref(ref, "bsphere", dts));
|
||||
|
||||
auto data_ref = get_field_ref(ref, "data", dts);
|
||||
for (int i = 0; i < length; i++) {
|
||||
Ref obj_ref = data_ref;
|
||||
obj_ref.byte_offset += 80 * i; // todo not a constant here
|
||||
auto type = get_type_of_basic(obj_ref);
|
||||
if (type != "instance-shrubbery") {
|
||||
throw Error("bad draw node type: {}", type);
|
||||
}
|
||||
instances.emplace_back();
|
||||
instances.back().read_from_file(typed_ref_from_basic(obj_ref, dts), dts, stats);
|
||||
}
|
||||
}
|
||||
|
||||
std::string DrawableInlineArrayInstanceShrub::print(const PrintSettings& settings,
|
||||
int indent) const {
|
||||
std::string is(indent, ' ');
|
||||
std::string result;
|
||||
int next_indent = indent + 4;
|
||||
result += fmt::format("{}id: {}\n", is, id);
|
||||
result += fmt::format("{}length: {}\n", is, length);
|
||||
result += fmt::format("{}bsphere: {}", is, bsphere.print_meters());
|
||||
|
||||
if (settings.expand_shrub) {
|
||||
for (size_t i = 0; i < instances.size(); i++) {
|
||||
result += fmt::format("{}draw-nodes [{}] ({}):\n", is, i, instances[i].my_type());
|
||||
result += instances[i].print(settings, next_indent);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void PrototypeArrayShrubInfo::read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
level_tools::DrawStats* stats) {
|
||||
prototype_inline_array_shrub.read_from_file(
|
||||
get_and_check_ref_to_basic(ref, "prototype-inline-array-shrub",
|
||||
"prototype-inline-array-shrub", dts),
|
||||
dts, stats);
|
||||
wind_vectors = deref_label(get_field_ref(ref, "wind-vectors", dts));
|
||||
}
|
||||
|
||||
std::string PrototypeArrayShrubInfo::print(const level_tools::PrintSettings& settings,
|
||||
int indent) const {
|
||||
return prototype_inline_array_shrub.print(settings, indent);
|
||||
}
|
||||
|
||||
void PrototypeInlineArrayShrub::read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
level_tools::DrawStats* stats) {
|
||||
length = read_plain_data_field<s16>(ref, "length", dts);
|
||||
auto data_ref = get_field_ref(ref, "data", dts);
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
Ref thing = data_ref;
|
||||
// note: unlike tie, these are stored in an inline array.
|
||||
thing.byte_offset += 112 * i; // todo - not a constant here
|
||||
auto type = get_type_of_basic(thing);
|
||||
if (type != "prototype-bucket-shrub") {
|
||||
throw Error("bad type in PrototypeInlineArrayShrub data: {}\n", type);
|
||||
}
|
||||
data.emplace_back();
|
||||
data.back().read_from_file(typed_ref_from_basic(thing, dts), dts, stats);
|
||||
}
|
||||
}
|
||||
|
||||
std::string PrototypeInlineArrayShrub::print(const level_tools::PrintSettings& settings,
|
||||
int indent) const {
|
||||
std::string is(indent, ' ');
|
||||
std::string result;
|
||||
int next_indent = indent + 4;
|
||||
result += fmt::format("{}length: {}\n", is, length);
|
||||
|
||||
for (u32 i = 0; i < data.size(); i++) {
|
||||
result += fmt::format("{}data [{}]:\n", is, i);
|
||||
result += data[i].print(settings, next_indent);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void PrototypeBucketShrub::read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
level_tools::DrawStats* stats) {
|
||||
name = read_string_field(ref, "name", dts, true);
|
||||
flags = read_plain_data_field<u32>(ref, "flags", dts);
|
||||
if (flags) {
|
||||
// lid in misty has flag 2, not sure what it means yet.
|
||||
fmt::print("proto: {} flags: {}\n", name, flags);
|
||||
}
|
||||
assert(flags == 0 || flags == 2);
|
||||
in_level = read_plain_data_field<u16>(ref, "in-level", dts);
|
||||
utextures = read_plain_data_field<u16>(ref, "utextures", dts);
|
||||
dists.read_from_file(get_field_ref(ref, "dists", dts));
|
||||
rdists.read_from_file(get_field_ref(ref, "rdists", dts));
|
||||
stiffness = read_plain_data_field<float>(ref, "stiffness", dts);
|
||||
// 64 to 112 should be zeros
|
||||
for (int i = 0; i < 12; i++) {
|
||||
assert(deref_u32(ref.ref, 16 + i) == 0);
|
||||
}
|
||||
|
||||
auto geom_start = get_field_ref(ref, "geometry", dts);
|
||||
|
||||
// first geometry is generic and we should always have it.
|
||||
auto generic_geom = deref_label(geom_start);
|
||||
generic_geom.byte_offset -= 4;
|
||||
if (get_type_of_basic(generic_geom) != "prototype-generic-shrub") {
|
||||
throw Error("bad generic shrub type: {}", get_type_of_basic(generic_geom));
|
||||
}
|
||||
geom_start.byte_offset += 4;
|
||||
|
||||
// second is same data, but in prototype-shrubbery form (for normal shrub renderer)
|
||||
auto normal_geom = deref_label(geom_start);
|
||||
normal_geom.byte_offset -= 4;
|
||||
if (get_type_of_basic(normal_geom) != "prototype-shrubbery") {
|
||||
throw Error("bad normal shrub type: {}", get_type_of_basic(normal_geom));
|
||||
}
|
||||
shrubbery_geom.read_from_file(typed_ref_from_basic(normal_geom, dts), dts, stats);
|
||||
geom_start.byte_offset += 4;
|
||||
|
||||
// todo transparent version
|
||||
// todo billboard version.
|
||||
}
|
||||
|
||||
std::string PrototypeBucketShrub::print(const level_tools::PrintSettings& settings,
|
||||
int indent) const {
|
||||
std::string is(indent, ' ');
|
||||
std::string result;
|
||||
result += fmt::format("{}name: {}\n", is, name);
|
||||
result += fmt::format("{}flags: {}\n", is, flags);
|
||||
|
||||
result += fmt::format("{}normal-geometry [1]:\n", is);
|
||||
result += shrubbery_geom.print(settings, indent + 4);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void PrototypeShrubbery::read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
level_tools::DrawStats* stats) {
|
||||
id = read_plain_data_field<s16>(ref, "id", dts);
|
||||
length = read_plain_data_field<s16>(ref, "length", dts);
|
||||
bsphere.read_from_file(get_field_ref(ref, "bsphere", dts));
|
||||
|
||||
auto data_ref = get_field_ref(ref, "data", dts);
|
||||
for (int i = 0; i < length; i++) {
|
||||
Ref obj_ref = data_ref;
|
||||
obj_ref.byte_offset += 32 * i; // todo not a constant here
|
||||
auto type = get_type_of_basic(obj_ref);
|
||||
if (type != "shrubbery") {
|
||||
throw Error("bad draw node type: {}", type);
|
||||
}
|
||||
shrubs.emplace_back();
|
||||
shrubs.back().read_from_file(typed_ref_from_basic(obj_ref, dts), dts, stats);
|
||||
}
|
||||
}
|
||||
|
||||
std::string PrototypeShrubbery::print(const level_tools::PrintSettings& settings,
|
||||
int indent) const {
|
||||
std::string is(indent, ' ');
|
||||
std::string result;
|
||||
int next_indent = indent + 4;
|
||||
result += fmt::format("{}id: {}\n", is, id);
|
||||
result += fmt::format("{}length: {}\n", is, length);
|
||||
result += fmt::format("{}bsphere: {}", is, bsphere.print_meters());
|
||||
|
||||
for (size_t i = 0; i < shrubs.size(); i++) {
|
||||
result += fmt::format("{}draw-nodes [{}] ({}):\n", is, i, shrubs[i].my_type());
|
||||
result += shrubs[i].print(settings, next_indent);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void copy_dma_to_vector(std::vector<u8>* out, Ref data_start, int qwc) {
|
||||
out->resize(qwc * 16);
|
||||
for (int i = 0; i < qwc * 4; i++) {
|
||||
u32 val = deref_u32(data_start, i);
|
||||
memcpy(out->data() + i, &val, 4);
|
||||
}
|
||||
}
|
||||
|
||||
void Shrubbery::read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
level_tools::DrawStats* stats) {
|
||||
// read the easy ones.
|
||||
obj_qwc = read_plain_data_field<u8>(ref, "obj-qwc", dts);
|
||||
vtx_qwc = read_plain_data_field<u8>(ref, "vtx-qwc", dts);
|
||||
col_qwc = read_plain_data_field<u8>(ref, "col-qwc", dts);
|
||||
stq_qwc = read_plain_data_field<u8>(ref, "stq-qwc", dts);
|
||||
|
||||
auto header_data = deref_label(get_field_ref(ref, "header", dts));
|
||||
// guess that the header is 24 * 4 = 96 bytes here.
|
||||
// not sure what it's used for yet.
|
||||
header.resize(24);
|
||||
for (int i = 0; i < 24; i++) {
|
||||
u32 val = deref_u32(header_data, i);
|
||||
memcpy(header.data() + i, &val, 4);
|
||||
}
|
||||
|
||||
copy_dma_to_vector(&obj, deref_label(get_field_ref(ref, "obj", dts)), obj_qwc);
|
||||
copy_dma_to_vector(&vtx, deref_label(get_field_ref(ref, "vtx", dts)), vtx_qwc);
|
||||
copy_dma_to_vector(&col, deref_label(get_field_ref(ref, "col", dts)), col_qwc);
|
||||
copy_dma_to_vector(&stq, deref_label(get_field_ref(ref, "stq", dts)), stq_qwc);
|
||||
copy_dma_to_vector(&textures, deref_label(get_field_ref(ref, "textures", dts)), header[0] * 10);
|
||||
}
|
||||
|
||||
std::string Shrubbery::print(const level_tools::PrintSettings& settings, int indent) const {
|
||||
std::string is(indent, ' ');
|
||||
|
||||
return fmt::format("{} qwcs: {} {} {} {}, tex: {}\n", is, obj_qwc, vtx_qwc, col_qwc, stq_qwc,
|
||||
header[0] * 2);
|
||||
}
|
||||
|
||||
} // namespace shrub_types
|
||||
|
||||
std::unique_ptr<DrawableTree> make_drawable_tree(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
DrawStats* stats) {
|
||||
@@ -1150,6 +1518,12 @@ std::unique_ptr<DrawableTree> make_drawable_tree(TypedRef ref,
|
||||
tree->read_from_file(ref, dts, stats);
|
||||
return tree;
|
||||
}
|
||||
|
||||
if (ref.type->get_name() == "drawable-tree-instance-shrub") {
|
||||
auto tree = std::make_unique<shrub_types::DrawableTreeInstanceShrub>();
|
||||
tree->read_from_file(ref, dts, stats);
|
||||
return tree;
|
||||
}
|
||||
auto tree = std::make_unique<DrawableTreeUnknown>();
|
||||
tree->read_from_file(ref, dts, stats);
|
||||
return tree;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
|
||||
#include "decompiler/util/goal_data_reader.h"
|
||||
|
||||
@@ -13,45 +14,16 @@ class DecompilerTypeSystem;
|
||||
} // namespace decompiler
|
||||
|
||||
namespace level_tools {
|
||||
|
||||
struct Vector {
|
||||
float data[4];
|
||||
|
||||
void read_from_file(Ref ref);
|
||||
|
||||
std::string print(int indent = 0) const;
|
||||
std::string print_meters(int indent = 0) const;
|
||||
};
|
||||
|
||||
struct Matrix4h {
|
||||
u16 data[16];
|
||||
void read_from_file(Ref ref);
|
||||
};
|
||||
|
||||
struct FileInfo {
|
||||
std::string file_type;
|
||||
std::string file_name;
|
||||
u32 major_version;
|
||||
u32 minor_version;
|
||||
|
||||
std::string maya_file_name;
|
||||
std::string tool_debug;
|
||||
std::string mdb_file_name;
|
||||
|
||||
void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts);
|
||||
|
||||
std::string print(int indent = 0) const;
|
||||
};
|
||||
|
||||
struct PrintSettings {
|
||||
bool print_tfrag = true;
|
||||
bool expand_draw_node = true;
|
||||
bool expand_drawable_tree_tfrag = true;
|
||||
bool expand_drawable_tree_trans_tfrag = true;
|
||||
bool expand_drawable_tree_tie_proto = true;
|
||||
bool print_tfrag = false;
|
||||
bool expand_draw_node = false;
|
||||
bool expand_drawable_tree_tfrag = false;
|
||||
bool expand_drawable_tree_trans_tfrag = false;
|
||||
bool expand_drawable_tree_tie_proto = false;
|
||||
bool expand_drawable_tree_tie_proto_data = false;
|
||||
bool expand_drawable_tree_instance_tie = false;
|
||||
bool expand_drawable_tree_actor = false;
|
||||
bool expand_shrub = true;
|
||||
};
|
||||
|
||||
struct DrawStats {
|
||||
@@ -66,6 +38,45 @@ struct DrawStats {
|
||||
std::string print() const;
|
||||
};
|
||||
|
||||
/////////////////////
|
||||
// Common Types
|
||||
/////////////////////
|
||||
|
||||
// a normal vector of 4 floats.
|
||||
struct Vector {
|
||||
float data[4];
|
||||
|
||||
void read_from_file(Ref ref);
|
||||
|
||||
std::string print(int indent = 0) const;
|
||||
std::string print_meters(int indent = 0) const;
|
||||
};
|
||||
|
||||
// a matrix with 16-bit integers.
|
||||
// typically requires some unpacking step to get meaningful values.
|
||||
struct Matrix4h {
|
||||
u16 data[16];
|
||||
void read_from_file(Ref ref);
|
||||
};
|
||||
|
||||
// A time-of-day color palette.
|
||||
// this is just the raw data, doesn't have any unpacking/meaning.
|
||||
struct TimeOfDayPalette {
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 pad;
|
||||
std::vector<u32> colors;
|
||||
};
|
||||
|
||||
/////////////////////
|
||||
// Drawable BVH
|
||||
/////////////////////
|
||||
|
||||
// these types are all generic container types/base classes.
|
||||
// note that the unpacker just greedily chases things and doesn't deduplicate, so comparing
|
||||
// pointers for equality won't tell you if two things are the same game object or not.
|
||||
|
||||
// the base class for everything in the BVH tree system.
|
||||
struct Drawable {
|
||||
virtual void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
@@ -75,8 +86,9 @@ struct Drawable {
|
||||
virtual ~Drawable() = default;
|
||||
};
|
||||
|
||||
struct DrawableInlineArray : public Drawable {};
|
||||
|
||||
// a node in the BVH tree. It's just used for organizing things within a bsphere.
|
||||
// these nodes are always in inline arrays and have between 0 and 8 children.
|
||||
// the leaves of these nodes are some other type of drawable - the thing you actually want to draw.
|
||||
struct DrawNode : public Drawable {
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
@@ -92,6 +104,53 @@ struct DrawNode : public Drawable {
|
||||
float distance = 0;
|
||||
};
|
||||
|
||||
// an inline array of drawable. There are more specific types for the actual arrays.
|
||||
struct DrawableInlineArray : public Drawable {};
|
||||
|
||||
// an inline array of draw nodes. All draw nodes at a level are stored in a drawable inline array.
|
||||
struct DrawableInlineArrayNode : public DrawableInlineArray {
|
||||
s16 id;
|
||||
s16 length;
|
||||
Vector bsphere;
|
||||
|
||||
std::vector<DrawNode> draw_nodes;
|
||||
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
DrawStats* stats) override;
|
||||
std::string print(const PrintSettings& settings, int indent) const override;
|
||||
std::string my_type() const override;
|
||||
};
|
||||
|
||||
// the generic base class for a "tree". A tree is a BVH with between 1 and 8 DrawNode roots.
|
||||
// there's typically a tree per renderer.
|
||||
struct DrawableTree : public Drawable {};
|
||||
|
||||
// how we represent drawable trees that we don't support yet - this isn't a real type in the game.
|
||||
struct DrawableTreeUnknown : public DrawableTree {
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
DrawStats* stats) override;
|
||||
std::string print(const PrintSettings& settings, int indent) const override;
|
||||
std::string my_type() const override;
|
||||
std::string type_name;
|
||||
};
|
||||
|
||||
struct DrawableInlineArrayUnknown : public DrawableInlineArray {
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
DrawStats* stats) override;
|
||||
std::string print(const PrintSettings& settings, int indent) const override;
|
||||
std::string my_type() const override;
|
||||
std::string type_name;
|
||||
};
|
||||
|
||||
/////////////////////
|
||||
// Actors
|
||||
/////////////////////
|
||||
|
||||
// there's a tree for actors - but we don't do anything with it yet.
|
||||
|
||||
struct EntityActor {};
|
||||
|
||||
struct DrawableActor : public Drawable {
|
||||
@@ -107,6 +166,25 @@ struct DrawableActor : public Drawable {
|
||||
std::string my_type() const override { return "drawable-actor"; }
|
||||
};
|
||||
|
||||
struct DrawableTreeActor : public DrawableTree {
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
DrawStats* stats) override;
|
||||
std::string print(const PrintSettings& settings, int indent) const override;
|
||||
std::string my_type() const override;
|
||||
|
||||
s16 id;
|
||||
s16 length;
|
||||
// todo time of day stuff
|
||||
Vector bsphere;
|
||||
|
||||
std::vector<std::unique_ptr<DrawableInlineArray>> arrays;
|
||||
};
|
||||
|
||||
/////////////////////
|
||||
// TFRAG
|
||||
/////////////////////
|
||||
|
||||
struct TFragmentDebugData {
|
||||
u16 num_tris[4];
|
||||
u16 num_dverts[4];
|
||||
@@ -116,6 +194,7 @@ struct TFragmentDebugData {
|
||||
void read_from_file(Ref ref, const decompiler::DecompilerTypeSystem& dts, DrawStats* stats);
|
||||
};
|
||||
|
||||
// the "fragment" is just a collection of data that fits into the VU memory.
|
||||
struct TFragment : public Drawable {
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
@@ -150,6 +229,67 @@ struct TFragment : public Drawable {
|
||||
// generic // 60 - 64
|
||||
};
|
||||
|
||||
// array of tfragments. This is used as part of the BVH tree
|
||||
struct DrawableInlineArrayTFrag : public DrawableInlineArray {
|
||||
s16 id;
|
||||
s16 length;
|
||||
Vector bsphere;
|
||||
|
||||
std::vector<TFragment> tfragments;
|
||||
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
DrawStats* stats) override;
|
||||
std::string print(const PrintSettings& settings, int indent) const override;
|
||||
std::string my_type() const override;
|
||||
};
|
||||
|
||||
// a top-level tfragment tree.
|
||||
// it has a BVH tree of tfragments as well as a time of day palette.
|
||||
struct DrawableTreeTfrag : public DrawableTree {
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
DrawStats* stats) override;
|
||||
std::string print(const PrintSettings& settings, int indent) const override;
|
||||
std::string my_type() const override;
|
||||
|
||||
s16 id;
|
||||
s16 length;
|
||||
TimeOfDayPalette time_of_day;
|
||||
Vector bsphere;
|
||||
|
||||
std::vector<std::unique_ptr<DrawableInlineArray>> arrays;
|
||||
};
|
||||
|
||||
// various specializations of tfragment.
|
||||
|
||||
struct DrawableTreeTransTfrag : public DrawableTreeTfrag {
|
||||
std::string my_type() const override { return "drawable-tree-trans-tfrag"; }
|
||||
};
|
||||
|
||||
struct DrawableTreeLowresTfrag : public DrawableTreeTfrag {
|
||||
std::string my_type() const override { return "drawable-tree-lowres-tfrag"; }
|
||||
};
|
||||
|
||||
struct DrawableTreeDirtTfrag : public DrawableTreeTfrag {
|
||||
std::string my_type() const override { return "drawable-tree-dirt-tfrag"; }
|
||||
};
|
||||
|
||||
struct DrawableTreeIceTfrag : public DrawableTreeTfrag {
|
||||
std::string my_type() const override { return "drawable-tree-ice-tfrag"; }
|
||||
};
|
||||
|
||||
struct DrawableInlineArrayTransTFrag : public DrawableInlineArrayTFrag {
|
||||
std::string my_type() const override { return "drawable-inline-array-trans-tfrag"; }
|
||||
};
|
||||
|
||||
/////////////////////
|
||||
// TIE
|
||||
/////////////////////
|
||||
|
||||
// a tie-fragment is a chunk of geometry that can be sent to the VU.
|
||||
// it's similar to a tfragment, but a bit simpler.
|
||||
// each prototype is made up of fragments.
|
||||
struct TieFragment : public Drawable {
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
@@ -173,6 +313,9 @@ struct TieFragment : public Drawable {
|
||||
// todo, lots more
|
||||
};
|
||||
|
||||
// represents an instance of a prototype.
|
||||
// each instance has its own color data, but the rest of the geometry/texture is shared between
|
||||
// all instances of the same prototype.
|
||||
struct InstanceTie : public Drawable {
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
@@ -181,9 +324,9 @@ struct InstanceTie : public Drawable {
|
||||
std::string my_type() const override { return "instance-tie"; }
|
||||
|
||||
// (bucket-index uint16 :offset 6)
|
||||
u16 bucket_index;
|
||||
u16 bucket_index; // which prototype
|
||||
s16 id;
|
||||
Vector bsphere;
|
||||
Vector bsphere; // where we are located
|
||||
Matrix4h origin;
|
||||
u16 flags;
|
||||
u16 wind_index;
|
||||
@@ -193,101 +336,7 @@ struct InstanceTie : public Drawable {
|
||||
// todo, lots more
|
||||
};
|
||||
|
||||
struct DrawableInlineArrayNode : public DrawableInlineArray {
|
||||
s16 id;
|
||||
s16 length;
|
||||
Vector bsphere;
|
||||
|
||||
std::vector<DrawNode> draw_nodes;
|
||||
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
DrawStats* stats) override;
|
||||
std::string print(const PrintSettings& settings, int indent) const override;
|
||||
std::string my_type() const override;
|
||||
};
|
||||
|
||||
struct DrawableInlineArrayTFrag : public DrawableInlineArray {
|
||||
s16 id;
|
||||
s16 length;
|
||||
Vector bsphere;
|
||||
|
||||
std::vector<TFragment> tfragments;
|
||||
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
DrawStats* stats) override;
|
||||
std::string print(const PrintSettings& settings, int indent) const override;
|
||||
std::string my_type() const override;
|
||||
};
|
||||
|
||||
struct DrawableInlineArrayInstanceTie : public DrawableInlineArray {
|
||||
s16 id;
|
||||
s16 length;
|
||||
Vector bsphere;
|
||||
|
||||
std::vector<InstanceTie> instances;
|
||||
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
DrawStats* stats) override;
|
||||
std::string print(const PrintSettings& settings, int indent) const override;
|
||||
std::string my_type() const override;
|
||||
};
|
||||
|
||||
struct DrawableInlineArrayTransTFrag : public DrawableInlineArrayTFrag {
|
||||
std::string my_type() const override { return "drawable-inline-array-trans-tfrag"; }
|
||||
};
|
||||
|
||||
struct DrawableInlineArrayUnknown : public DrawableInlineArray {
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
DrawStats* stats) override;
|
||||
std::string print(const PrintSettings& settings, int indent) const override;
|
||||
std::string my_type() const override;
|
||||
std::string type_name;
|
||||
};
|
||||
|
||||
struct DrawableTree : public Drawable {};
|
||||
|
||||
struct TimeOfDayPalette {
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 pad;
|
||||
std::vector<u32> colors;
|
||||
};
|
||||
|
||||
struct DrawableTreeTfrag : public DrawableTree {
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
DrawStats* stats) override;
|
||||
std::string print(const PrintSettings& settings, int indent) const override;
|
||||
std::string my_type() const override;
|
||||
|
||||
s16 id;
|
||||
s16 length;
|
||||
// todo time of day stuff
|
||||
TimeOfDayPalette time_of_day;
|
||||
Vector bsphere;
|
||||
|
||||
std::vector<std::unique_ptr<DrawableInlineArray>> arrays;
|
||||
};
|
||||
|
||||
struct DrawableTreeActor : public DrawableTree {
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
DrawStats* stats) override;
|
||||
std::string print(const PrintSettings& settings, int indent) const override;
|
||||
std::string my_type() const override;
|
||||
|
||||
s16 id;
|
||||
s16 length;
|
||||
// todo time of day stuff
|
||||
Vector bsphere;
|
||||
|
||||
std::vector<std::unique_ptr<DrawableInlineArray>> arrays;
|
||||
};
|
||||
|
||||
// a prototype is basically just a collection of fragments
|
||||
struct PrototypeTie : public DrawableInlineArray {
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
@@ -301,6 +350,9 @@ struct PrototypeTie : public DrawableInlineArray {
|
||||
std::vector<TieFragment> tie_fragments;
|
||||
};
|
||||
|
||||
// a prototype bucket is a collection of 4 different prototypes (called geometries), one for each
|
||||
// level of detail. All geometries share the same time of day palette.
|
||||
// the bucket also refers to the fact that it collect instances during actual rendering.
|
||||
struct PrototypeBucketTie {
|
||||
std::string name; // 4 - 8
|
||||
u32 flags; // 8 - 12
|
||||
@@ -337,6 +389,8 @@ struct PrototypeBucketTie {
|
||||
std::string print(const PrintSettings& settings, int indent) const;
|
||||
};
|
||||
|
||||
// an array of all the prototypes. The prototypes aren't stored in a BVH (it wouldn't make sense -
|
||||
// they can be located all over the place)- there is just a plain array.
|
||||
struct PrototypeArrayTie {
|
||||
u32 length;
|
||||
u32 allocated_length;
|
||||
@@ -347,6 +401,8 @@ struct PrototypeArrayTie {
|
||||
std::string print(const PrintSettings& settings, int indent) const;
|
||||
};
|
||||
|
||||
// the reason for this type is somewhat unknown, but it just contains the prototype array and
|
||||
// wind vectors. The wind vector data is all 0's and is updated as the game runs.
|
||||
struct ProxyPrototypeArrayTie {
|
||||
void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, DrawStats* stats);
|
||||
std::string print(const PrintSettings& settings, int indent) const;
|
||||
@@ -355,6 +411,22 @@ struct ProxyPrototypeArrayTie {
|
||||
Ref wind_vectors;
|
||||
};
|
||||
|
||||
// array of instances. These are part of the BVH
|
||||
struct DrawableInlineArrayInstanceTie : public DrawableInlineArray {
|
||||
s16 id;
|
||||
s16 length;
|
||||
Vector bsphere;
|
||||
|
||||
std::vector<InstanceTie> instances;
|
||||
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
DrawStats* stats) override;
|
||||
std::string print(const PrintSettings& settings, int indent) const override;
|
||||
std::string my_type() const override;
|
||||
};
|
||||
|
||||
// TIE tree
|
||||
struct DrawableTreeInstanceTie : public DrawableTree {
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
@@ -370,31 +442,168 @@ struct DrawableTreeInstanceTie : public DrawableTree {
|
||||
std::vector<std::unique_ptr<DrawableInlineArray>> arrays;
|
||||
};
|
||||
|
||||
struct DrawableTreeTransTfrag : public DrawableTreeTfrag {
|
||||
std::string my_type() const override { return "drawable-tree-trans-tfrag"; }
|
||||
};
|
||||
/////////////////////////////////
|
||||
// SHRUB
|
||||
/////////////////////////////////
|
||||
|
||||
struct DrawableTreeLowresTfrag : public DrawableTreeTfrag {
|
||||
std::string my_type() const override { return "drawable-tree-lowres-tfrag"; }
|
||||
};
|
||||
namespace shrub_types {
|
||||
|
||||
struct DrawableTreeDirtTfrag : public DrawableTreeTfrag {
|
||||
std::string my_type() const override { return "drawable-tree-dirt-tfrag"; }
|
||||
};
|
||||
|
||||
struct DrawableTreeIceTfrag : public DrawableTreeTfrag {
|
||||
std::string my_type() const override { return "drawable-tree-ice-tfrag"; }
|
||||
};
|
||||
|
||||
struct DrawableTreeUnknown : public DrawableTree {
|
||||
struct Shrubbery : public level_tools::Drawable {
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
DrawStats* stats) override;
|
||||
std::string print(const PrintSettings& settings, int indent) const override;
|
||||
std::string my_type() const override;
|
||||
std::string type_name;
|
||||
level_tools::DrawStats* stats) override;
|
||||
std::string print(const level_tools::PrintSettings& settings, int indent) const override;
|
||||
std::string my_type() const override { return "shrubbery"; }
|
||||
|
||||
// 4 - textures
|
||||
std::vector<u8> textures;
|
||||
|
||||
std::vector<u32> header;
|
||||
u8 obj_qwc; // 12
|
||||
u8 vtx_qwc; // 13
|
||||
u8 col_qwc; // 14
|
||||
u8 stq_qwc; // 15
|
||||
|
||||
std::vector<u8> obj; // 16
|
||||
std::vector<u8> vtx; // 20
|
||||
std::vector<u8> col; // 24
|
||||
std::vector<u8> stq; // 28
|
||||
};
|
||||
|
||||
struct PrototypeShrubbery : public level_tools::DrawableInlineArray {
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
level_tools::DrawStats* stats) override;
|
||||
std::string print(const level_tools::PrintSettings& settings, int indent) const override;
|
||||
std::string my_type() const override { return "prototype-shrubbery"; }
|
||||
s16 id; // 0
|
||||
s16 length; // 4
|
||||
|
||||
level_tools::Vector bsphere; // 16
|
||||
std::vector<Shrubbery> shrubs; // 32
|
||||
};
|
||||
|
||||
struct Billboard {};
|
||||
|
||||
struct PrototypeBucketShrub {
|
||||
std::string name; // 4
|
||||
u32 flags; // 8
|
||||
u16 in_level; // 12
|
||||
u16 utextures; // 14
|
||||
|
||||
// PrototypeShrubbery geometry[4]; // 16
|
||||
// skip generic, we think it's the same as shrubbery geom.
|
||||
PrototypeShrubbery shrubbery_geom; // 1
|
||||
// todo transparent geom
|
||||
// todo billboard geom
|
||||
|
||||
level_tools::Vector dists; // 32
|
||||
// - near-plane
|
||||
// - near-stiff
|
||||
// - mid-plane
|
||||
// - far-plane
|
||||
level_tools::Vector rdists; // 48
|
||||
// - rlength-near
|
||||
// - rlength-stiff
|
||||
// - rlength-mid
|
||||
// - stiffness
|
||||
|
||||
float stiffness; // - 60
|
||||
|
||||
// the next/last/count/mod stuff is all 0's.
|
||||
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
level_tools::DrawStats* stats);
|
||||
std::string print(const level_tools::PrintSettings& settings, int indent) const;
|
||||
};
|
||||
|
||||
struct PrototypeInlineArrayShrub {
|
||||
s16 id; // 4
|
||||
s16 length; // 6
|
||||
level_tools::Vector bsphere; // 16
|
||||
std::vector<PrototypeBucketShrub> data; // 32
|
||||
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
level_tools::DrawStats* stats);
|
||||
std::string print(const level_tools::PrintSettings& settings, int indent) const;
|
||||
};
|
||||
|
||||
struct PrototypeArrayShrubInfo {
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
level_tools::DrawStats* stats);
|
||||
std::string print(const level_tools::PrintSettings& settings, int indent) const;
|
||||
|
||||
PrototypeInlineArrayShrub prototype_inline_array_shrub;
|
||||
Ref wind_vectors;
|
||||
};
|
||||
|
||||
struct InstanceShrubbery : public level_tools::Drawable {
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
level_tools::DrawStats* stats) override;
|
||||
std::string print(const level_tools::PrintSettings& settings, int indent) const override;
|
||||
std::string my_type() const override { return "instance-shrubbery"; }
|
||||
|
||||
s16 id; // 4
|
||||
u16 bucket_index; // 6
|
||||
level_tools::Vector bsphere; // 16
|
||||
level_tools::Matrix4h origin; // 32
|
||||
u16 wind_index; // 62
|
||||
|
||||
// --- instance-shrubbery ---
|
||||
u32 color_indices; // 8 - unlike tie, I think this is just an integer offset
|
||||
level_tools::Vector flat_normal; // 64 (w is flat_hwidth)
|
||||
};
|
||||
|
||||
struct DrawableInlineArrayInstanceShrub : public level_tools::DrawableInlineArray {
|
||||
s16 id;
|
||||
s16 length;
|
||||
level_tools::Vector bsphere;
|
||||
|
||||
std::vector<InstanceShrubbery> instances;
|
||||
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
level_tools::DrawStats* stats) override;
|
||||
std::string print(const level_tools::PrintSettings& settings, int indent) const override;
|
||||
std::string my_type() const override { return "drawable-inline-array-instance-shrub"; }
|
||||
};
|
||||
|
||||
struct DrawableTreeInstanceShrub : public level_tools::DrawableTree {
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
level_tools::DrawStats* stats) override;
|
||||
std::string print(const level_tools::PrintSettings& settings, int indent) const override;
|
||||
std::string my_type() const override;
|
||||
|
||||
s16 id; // 0
|
||||
s16 length; // 4
|
||||
PrototypeArrayShrubInfo info; // 8
|
||||
TimeOfDayPalette time_of_day;
|
||||
level_tools::Vector bsphere; // 16
|
||||
|
||||
std::vector<std::unique_ptr<level_tools::DrawableInlineArray>> arrays;
|
||||
|
||||
// annoyingly, the shrub tree only has the top level in the array....
|
||||
// so we can't use the above "arrays" like we did in tfrag/tie.
|
||||
// luckily, it seems to be possible to figure out the location of the remaining arrays.
|
||||
// so we add this field to hold the arrays we found.
|
||||
// note that the tree format is not quite the same as tfrag/tie - the 8 child max is no longer
|
||||
// true, and the arrays are not truly by depth (the leaves aren't all the same depth)
|
||||
// this means there may be multiple arrays of instances, and we'll need to check all of them.
|
||||
std::vector<std::unique_ptr<level_tools::DrawableInlineArray>> discovered_arrays;
|
||||
};
|
||||
|
||||
} // namespace shrub_types
|
||||
|
||||
////////////////////////////////
|
||||
// Main Level Type (bsp-header)
|
||||
////////////////////////////////
|
||||
|
||||
// all the different trees are stored in a drawable-tree-array.
|
||||
struct DrawableTreeArray {
|
||||
s16 id;
|
||||
s16 length;
|
||||
@@ -406,11 +615,28 @@ struct DrawableTreeArray {
|
||||
std::vector<std::unique_ptr<DrawableTree>> trees;
|
||||
};
|
||||
|
||||
// levels may remap textures if they provide one that should be shared
|
||||
struct TextureRemap {
|
||||
u32 original_texid;
|
||||
u32 new_texid;
|
||||
};
|
||||
|
||||
// The "file info"
|
||||
struct FileInfo {
|
||||
std::string file_type;
|
||||
std::string file_name;
|
||||
u32 major_version;
|
||||
u32 minor_version;
|
||||
|
||||
std::string maya_file_name;
|
||||
std::string tool_debug;
|
||||
std::string mdb_file_name;
|
||||
|
||||
void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts);
|
||||
|
||||
std::string print(int indent = 0) const;
|
||||
};
|
||||
|
||||
struct BspHeader {
|
||||
// (info file-info :offset 4)
|
||||
FileInfo file_info;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "common/util/FileUtil.h"
|
||||
|
||||
namespace decompiler {
|
||||
using namespace level_tools;
|
||||
|
||||
/// <summary>
|
||||
/// Get the index of the first draw node in an array. Works for node or tfrag.
|
||||
@@ -34,8 +35,8 @@ u16 get_first_idx_shrub(const level_tools::DrawableInlineArray* array) {
|
||||
/// <param name="end"></param>
|
||||
/// <returns></returns>
|
||||
bool verify_node_indices_from_array_shrub(const level_tools::DrawableInlineArray* array,
|
||||
u16 start,
|
||||
u16* end) {
|
||||
u16 start,
|
||||
u16* end) {
|
||||
auto as_shrub_instances =
|
||||
dynamic_cast<const shrub_types::DrawableInlineArrayInstanceShrub*>(array);
|
||||
auto as_nodes = dynamic_cast<const level_tools::DrawableInlineArrayNode*>(array);
|
||||
@@ -447,8 +448,9 @@ void extract_shrub(const shrub_types::DrawableTreeInstanceShrub* tree,
|
||||
}
|
||||
}
|
||||
|
||||
auto info = collect_instance_info(as_instance_array, &tree->info.prototype_array_shrub.data);
|
||||
update_proto_info(&info, map, tex_db, tree->info.prototype_array_shrub.data);
|
||||
auto info =
|
||||
collect_instance_info(as_instance_array, &tree->info.prototype_inline_array_shrub.data);
|
||||
update_proto_info(&info, map, tex_db, tree->info.prototype_inline_array_shrub.data);
|
||||
|
||||
// AHHHH - likely stuck
|
||||
|
||||
|
||||
@@ -7,150 +7,7 @@
|
||||
|
||||
namespace decompiler {
|
||||
|
||||
namespace shrub_types {
|
||||
|
||||
struct Shrubbery : public level_tools::Drawable {
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
level_tools::DrawStats* stats) override;
|
||||
std::string print(const level_tools::PrintSettings& settings, int indent) const override;
|
||||
std::string my_type() const override { return "shrubbery"; }
|
||||
|
||||
// 4 - textures
|
||||
u16 gif_count;
|
||||
std::vector<u8> gif_data;
|
||||
|
||||
u32 header_unknown; // 8
|
||||
u8 obj_qwc; // 12
|
||||
u8 vtx_qwc; // 13
|
||||
u8 col_qwc; // 14
|
||||
u8 stq_qwc; // 15
|
||||
|
||||
u32 obj; // 16
|
||||
u32 vtx; // 20
|
||||
u32 col; // 24
|
||||
u32 steq; // 28
|
||||
};
|
||||
|
||||
struct PrototypeShrubbery : public level_tools::DrawableInlineArray {
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
level_tools::DrawStats* stats) override;
|
||||
std::string print(const level_tools::PrintSettings& settings, int indent) const override;
|
||||
std::string my_type() const override;
|
||||
s16 id; // 0
|
||||
s16 length; // 4
|
||||
|
||||
level_tools::Vector bsphere; // 16
|
||||
std::vector<Shrubbery> shrubs; // 32
|
||||
};
|
||||
|
||||
struct PrototypeBucketShrub {
|
||||
std::string name; // 4
|
||||
u32 flags; // 8
|
||||
u16 in_level; // 12
|
||||
u16 utextures; // 14
|
||||
|
||||
PrototypeShrubbery geometry[4]; // 16
|
||||
|
||||
level_tools::Vector dists; // 32
|
||||
// - near-plane
|
||||
// - near-stiff
|
||||
// - mid-plane
|
||||
// - far-plane
|
||||
level_tools::Vector rdists; // 48
|
||||
// - rlength-near
|
||||
// - rlength-stiff
|
||||
// - rlength-mid
|
||||
// - stiffness
|
||||
|
||||
float stiffness; // - 60
|
||||
|
||||
u32 next[4]; // 64
|
||||
u16 count[4]; // 80 | NOTE - overlayed in places as a 128bit value
|
||||
|
||||
u16 mod_count[4]; // 88
|
||||
Ref last[4]; // 96 | NOTE - overlayed to clear with a single uint128
|
||||
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
level_tools::DrawStats* stats);
|
||||
std::string print(const level_tools::PrintSettings& settings, int indent) const;
|
||||
};
|
||||
|
||||
struct PrototypeArrayShrub {
|
||||
s16 id; // 4
|
||||
s16 length; // 6
|
||||
level_tools::Vector bsphere; // 16
|
||||
std::vector<PrototypeBucketShrub> data; // 32
|
||||
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
level_tools::DrawStats* stats);
|
||||
std::string print(const level_tools::PrintSettings& settings, int indent) const;
|
||||
};
|
||||
|
||||
struct PrototypeArrayShrubInfo {
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
level_tools::DrawStats* stats);
|
||||
std::string print(const level_tools::PrintSettings& settings, int indent) const;
|
||||
|
||||
PrototypeArrayShrub prototype_array_shrub;
|
||||
// todo wind vectors.
|
||||
};
|
||||
|
||||
struct InstanceShrubbery : public level_tools::Drawable {
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
level_tools::DrawStats* stats) override;
|
||||
std::string print(const level_tools::PrintSettings& settings, int indent) const override;
|
||||
std::string my_type() const override { return "instance-shrubbery"; }
|
||||
|
||||
s16 id; // 4
|
||||
u16 bucket_index; // 6
|
||||
level_tools::Vector bsphere; // 16
|
||||
level_tools::Matrix4h origin; // 32
|
||||
u16 flags; // ??
|
||||
u16 wind_index; // 62
|
||||
|
||||
// --- instance-shrubbery ---
|
||||
Ref color_indices; // 8 - can't read this in the first pass because we don't know how long.
|
||||
level_tools::Vector flat_normal; // 64
|
||||
level_tools::Vector flat_hwidth; // 76
|
||||
};
|
||||
|
||||
struct DrawableInlineArrayInstanceShrub : public level_tools::DrawableInlineArray {
|
||||
s16 id;
|
||||
s16 length;
|
||||
level_tools::Vector bsphere;
|
||||
|
||||
std::vector<InstanceShrubbery> instances;
|
||||
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
level_tools::DrawStats* stats) override;
|
||||
std::string print(const level_tools::PrintSettings& settings, int indent) const override;
|
||||
std::string my_type() const override;
|
||||
};
|
||||
|
||||
struct DrawableTreeInstanceShrub : public level_tools::DrawableTree {
|
||||
void read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
level_tools::DrawStats* stats) override;
|
||||
std::string print(const level_tools::PrintSettings& settings, int indent) const override;
|
||||
std::string my_type() const override;
|
||||
|
||||
s16 id; // 0
|
||||
s16 length; // 4
|
||||
PrototypeArrayShrubInfo info; // 8
|
||||
u32 colors_added; // 12
|
||||
level_tools::Vector bsphere; // 16
|
||||
|
||||
std::vector<std::unique_ptr<level_tools::DrawableInlineArray>> arrays;
|
||||
};
|
||||
|
||||
} // namespace shrub_types
|
||||
|
||||
/// <summary>
|
||||
/// Extract shrubs from the level
|
||||
@@ -162,7 +19,7 @@ struct DrawableTreeInstanceShrub : public level_tools::DrawableTree {
|
||||
/// <param name="expected_missing_textures"></param>
|
||||
/// <param name="out"></param>
|
||||
/// <param name="dump_level"></param>
|
||||
void extract_shrub(const shrub_types::DrawableTreeInstanceShrub* tree,
|
||||
void extract_shrub(const level_tools::shrub_types::DrawableTreeInstanceShrub* tree,
|
||||
const std::string& debug_name,
|
||||
const std::vector<level_tools::TextureRemap>& map,
|
||||
const TextureDB& tex_db,
|
||||
|
||||
Reference in New Issue
Block a user