jak-project/decompiler/level_extractor/BspHeader.h
water111 5b04be2fa0
Add hfrag, clean up some background renderer stuff (#3509)
This adds hfrag, but with a few remaining issues:
- The textures aren't animated. Instead, it just uses one texture.
- The texture filtering isn't as good as at it could be.

I also cleaned up a few issues with the background renderers:
- Cleaned up some stuff that is common to hfrag, tie, tfrag, shrub
- Moved time-of-day color packing stuff to FR3 creation, rather than at
level load. This appears to reduce the frame time spikes when a level is
first drawn by about 5 or 6 ms in big levels.
- Cleaned up the x86 specific stuff used in time of day. Now there's
only one place where we have an `ifdef`, rather than spreading it all
over the rendering code.
2024-05-09 20:11:43 -04:00

928 lines
30 KiB
C++

#pragma once
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "common/common_types.h"
#include "common/math/Vector.h"
#include "common/versions/versions.h"
#include "decompiler/level_extractor/common_formats.h"
#include "decompiler/util/goal_data_reader.h"
namespace decompiler {
class LinkedObjectFile;
class DecompilerTypeSystem;
} // namespace decompiler
namespace level_tools {
struct PrintSettings {
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 = false;
bool expand_collide = false;
};
/////////////////////
// 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;
std::string print_decimal(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;
void read_from_file(Ref ref);
};
/////////////////////
// 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,
GameVersion version) = 0;
virtual std::string print(const PrintSettings& settings, int indent) const = 0;
virtual std::string my_type() const = 0;
virtual ~Drawable() = default;
};
// 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,
GameVersion version) override;
std::string print(const PrintSettings& settings, int indent) const override;
std::string my_type() const override;
s16 id;
Vector bsphere;
u8 child_count = 0;
u8 flags = 0;
std::vector<std::unique_ptr<Drawable>> children;
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,
GameVersion version) 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,
GameVersion version) 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,
GameVersion version) 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.
constexpr float kDefaultKeyFrame = -1000000000.f;
struct Res {
std::string name;
float key_frame = -2;
std::string elt_type;
u16 count;
bool inlined = false;
std::vector<u8> inlined_storage;
std::vector<std::string> strings;
goos::Object script;
};
struct EntityActor {
Vector trans;
u32 aid = 0;
// nav mesh
std::string etype;
int task = 0;
u16 vis_id = 0;
Vector quat;
std::vector<Res> res_list;
void read_from_file(TypedRef ref,
const decompiler::DecompilerTypeSystem& dts,
GameVersion version);
};
struct DrawableActor : public Drawable {
Vector bsphere;
EntityActor actor;
void read_from_file(TypedRef ref,
const decompiler::DecompilerTypeSystem& dts,
GameVersion version) override;
std::string print(const PrintSettings& settings, int indent) const override;
std::string my_type() const override { return "drawable-actor"; }
};
struct DrawableTreeActor : public DrawableTree {
void read_from_file(TypedRef ref,
const decompiler::DecompilerTypeSystem& dts,
GameVersion version) 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;
};
/////////////////////
// Collision
/////////////////////
struct CollideFragMesh {
/*
((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)
)
*/
void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts);
std::string print(const PrintSettings& settings, int indent) const;
u16 strip_data_len;
u16 poly_count;
// appears to be integers...
Vector base_trans;
u8 vertex_count;
u8 vertex_data_qwc;
u8 total_qwc;
Ref packed_data;
Ref pat_array;
};
struct CollideFragment {
void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts);
std::string print(const PrintSettings& settings, int indent) const;
Vector bsphere;
CollideFragMesh mesh;
};
struct DrawableInlineArrayCollideFragment : public DrawableInlineArray {
void read_from_file(TypedRef ref,
const decompiler::DecompilerTypeSystem& dts,
GameVersion version) override;
std::string print(const PrintSettings& settings, int indent) const override;
std::string my_type() const override;
std::vector<CollideFragment> collide_fragments;
s16 id;
s16 length;
Vector bsphere;
};
struct DrawableTreeCollideFragment : public DrawableTree {
void read_from_file(TypedRef ref,
const decompiler::DecompilerTypeSystem& dts,
GameVersion version) override;
std::string print(const PrintSettings& settings, int indent) const override;
std::string my_type() const override;
DrawableInlineArrayCollideFragment last_array;
};
/////////////////////
// TFRAG
/////////////////////
struct TFragmentDebugData {
u16 num_tris[4];
u16 num_dverts[4];
bool has_debug_lines;
std::string print(int indent) const;
void read_from_file(Ref ref, const decompiler::DecompilerTypeSystem& dts);
};
// 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,
GameVersion version) override;
std::string print(const PrintSettings& settings, int indent) const override;
std::string my_type() const override { return "tfragment"; }
// 0 - 4 type tag
s16 id; // 4 - 6
u16 color_index; // 6 - 8
TFragmentDebugData debug_data;
// u32 color_indices; // 12 - 16 (or colors?)
Vector bsphere; // 16 - 32
// dma common/level0 // 32 - 36
std::vector<u8> dma_common_and_level0;
// dma base // 36 - 40
std::vector<u8> dma_base;
// dma level 1 // 40 - 44
std::vector<u8> dma_level1;
std::vector<u16> color_indices;
u8 dma_qwc[4];
// shader // 48 - 52
u8 num_shaders; // 52
u8 num_base_colors; // 53
u8 num_level0_colors; // 54
u8 num_level1_colors; // 55
u8 color_offset; // 56
u8 color_count; // 57
// u8 pad0; // 58
// u8 pad1; // 59
// 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,
GameVersion version) 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,
GameVersion version) 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"; }
};
struct DrawableInlineArrayTFragTrans : public DrawableInlineArrayTFrag {
std::string my_type() const override { return "drawable-inline-array-tfrag-trans"; }
};
struct DrawableInlineArrayTFragWater : public DrawableInlineArrayTFrag {
std::string my_type() const override { return "drawable-inline-array-tfrag-water"; }
};
struct DrawableTreeTfragTrans : public DrawableTreeTfrag {
std::string my_type() const override { return "drawable-tree-tfrag-trans"; }
};
struct DrawableTreeTfragWater : public DrawableTreeTfrag {
std::string my_type() const override { return "drawable-tree-tfrag-water"; }
};
/////////////////////
// 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,
GameVersion version) override;
std::string print(const PrintSettings& settings, int indent) const override;
std::string my_type() const override { return "tie-fragment"; }
Vector bsphere;
u16 num_tris;
u16 num_dverts;
u16 tex_count;
u16 gif_count;
u16 vertex_count; // qwc of vertex data.
std::vector<u8> gif_data;
std::vector<u8> point_ref;
std::string debug_label_name;
std::vector<s8> normals; // jak 2
std::vector<u8> generic_data; // jak 1
// 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,
GameVersion version) override;
std::string print(const PrintSettings& settings, int indent) const override;
std::string my_type() const override { return "instance-tie"; }
// (bucket-index uint16 :offset 6)
u16 bucket_index; // which prototype
s16 id;
Vector bsphere; // where we are located
Matrix4h origin;
u16 flags;
u16 wind_index;
Ref color_indices; // can't read this in the first pass because we don't know how long.
// todo, lots more
};
// a prototype is basically just a collection of fragments
struct PrototypeTie : public DrawableInlineArray {
void read_from_file(TypedRef ref,
const decompiler::DecompilerTypeSystem& dts,
GameVersion version) override;
std::string print(const PrintSettings& settings, int indent) const override;
std::string my_type() const override;
s16 id;
s16 length;
Vector bsphere;
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.
// Note: collision extraction is only supported in jak 1.
struct PrototypeBucketTie {
std::string name; // 4 - 8
u32 flags; // 8 - 12
u16 in_level; // 12 - 14
u16 utextures; // 14 - 16
PrototypeTie geometry[4];
Vector dists;
Vector rdists;
u32 next[4];
u16 count[4];
// u16 generic_count[4];
// u32 generic_next[4];
u8 frag_count[4] = {0};
u8 index_start[4];
u16 base_qw[4];
float envmap_rfade;
float envmap_fade_far;
float stiffness;
std::vector<u8> color_index_qwc;
TimeOfDayPalette time_of_day;
bool has_envmap_shader = false;
u8 envmap_shader[5 * 16];
math::Vector<u8, 4> jak2_tint_color; // jak 2 only
// todo collide-frag
DrawableInlineArrayCollideFragment collide_frag;
std::vector<Ref> collide_hash_frags; // jak 2 only
// todo tie-colors
// todo data
void read_from_file(TypedRef ref,
const decompiler::DecompilerTypeSystem& dts,
GameVersion version);
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;
std::string content_type;
std::vector<PrototypeBucketTie> data;
void read_from_file(TypedRef ref,
const decompiler::DecompilerTypeSystem& dts,
GameVersion version);
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,
GameVersion version);
std::string print(const PrintSettings& settings, int indent) const;
PrototypeArrayTie prototype_array_tie;
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,
GameVersion version) 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,
GameVersion version) override;
std::string print(const PrintSettings& settings, int indent) const override;
std::string my_type() const override;
s16 id;
s16 length;
ProxyPrototypeArrayTie prototypes;
Vector bsphere;
std::vector<std::unique_ptr<DrawableInlineArray>> arrays;
};
/////////////////////////////////
// SHRUB
/////////////////////////////////
namespace shrub_types {
struct Shrubbery : public level_tools::Drawable {
void read_from_file(TypedRef ref,
const decompiler::DecompilerTypeSystem& dts,
GameVersion version) 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,
GameVersion version) 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 GenericShrubFragment : public level_tools::Drawable {
void read_from_file(TypedRef ref,
const decompiler::DecompilerTypeSystem& dts,
GameVersion version) override;
std::string print(const level_tools::PrintSettings& settings, int indent) const override;
std::string my_type() const override { return "generic-shrub-fragment"; }
//
// (textures (inline-array adgif-shader) :score 999 :offset 4)
std::vector<u8> textures;
// (vtx-cnt uint32 :score 999 :offset 8)
u32 vtx_cnt;
// (cnt-qwc uint8 :score 999 :offset 12)
u8 cnt_qwc;
// (vtx-qwc uint8 :score 999 :offset 13)
u8 vtx_qwc;
// (col-qwc uint8 :score 999 :offset 14)
u8 col_qwc;
// (stq-qwc uint8 :score 999 :offset 15)
u8 stq_qwc;
// (cnt uint32 :score 999 :offset 16)
std::vector<u8> cnt;
// (vtx uint32 :score 999 :offset 20)
std::vector<u8> vtx;
// (col uint32 :score 999 :offset 24)
std::vector<u8> col;
// (stq uint32 :score 999 :offset 28)
std::vector<u8> stq;
};
// really a drawable-group, but we'll make it drawable here.
struct PrototypeGenericShrub : public level_tools::Drawable {
void read_from_file(TypedRef ref,
const decompiler::DecompilerTypeSystem& dts,
GameVersion version) override;
std::string print(const level_tools::PrintSettings& settings, int indent) const override;
std::string my_type() const override { return "prototype-generic-shrub"; }
s16 length; // 4
level_tools::Vector bsphere; // 16
std::vector<GenericShrubFragment> shrubs; // 32
};
struct PrototypeBucketShrub {
std::string name; // 4
u32 flags; // 8
u16 in_level; // 12
u16 utextures; // 14
// PrototypeShrubbery geometry[4]; // 16
PrototypeGenericShrub generic_geom; // 0
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,
GameVersion version);
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,
GameVersion version);
std::string print(const level_tools::PrintSettings& settings, int indent) const;
};
struct PrototypeArrayShrubInfo {
void read_from_file(TypedRef ref,
const decompiler::DecompilerTypeSystem& dts,
GameVersion version);
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,
GameVersion version) 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,
GameVersion version) 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,
GameVersion version) 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
struct DrawableInlineArrayActor {
std::vector<DrawableActor> drawable_actors;
void read_from_file(TypedRef ref,
const decompiler::DecompilerTypeSystem& dts,
GameVersion version);
};
struct CollideHash {
Ref item_array;
int num_items = 0;
void read_from_file(TypedRef ref,
const decompiler::DecompilerTypeSystem& dts,
GameVersion version);
};
/*
((start-corner vector :inline :offset-assert 32)
(spheres (inline-array vector) :offset-assert 48)
(visids (pointer int16) :offset-assert 52)
(shaders (inline-array adgif-shader) :offset-assert 56)
(colors time-of-day-palette :offset-assert 60)
(montage uint32 :offset-assert 64)
(buckets-far (inline-array hfrag-bucket) :offset-assert 68)
(buckets-mid (inline-array hfrag-bucket) :offset-assert 72)
(buckets-near (inline-array hfrag-bucket) :offset-assert 76)
(verts (inline-array hfrag-vertex) :offset-assert 80) ;; wrong type? 8288
(pat-array (pointer pat-surface) :offset-assert 84)
(pat-length uint16 :offset-assert 88)
(num-buckets-far uint16 :offset-assert 90)
(num-buckets-mid uint16 :offset-assert 92)
(num-buckets-near uint16 :offset-assert 94)
(size uint32 :offset 44 :score 1)
*/
struct HFragmentMontage {
u16 table[16];
};
struct HFragment {
void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts);
static constexpr int kCornersPerEdge = 32;
static constexpr int kNumCorners = kCornersPerEdge * kCornersPerEdge;
static constexpr int kVertsPerEdge = 512;
static constexpr int kNumVerts = 512 * 512;
level_tools::Vector start_corner; // location of corner (0, 0)
std::vector<level_tools::Vector> spheres; // array of bspheres for each "corner"
std::vector<s16> vis_ids; // precomputed vis id for each "corner"
AdGifData shaders[3];
TimeOfDayPalette colors;
HFragmentMontage montage[17];
// buckets??
std::vector<u32> verts;
// pat-array
// pat-length
u16 num_buckets_far = 0;
u16 num_buckets_mid = 0;
u16 num_buckets_near = 0;
u32 size = 0;
};
////////////////////////////////
// Main Level Type (bsp-header)
////////////////////////////////
// all the different trees are stored in a drawable-tree-array.
struct DrawableTreeArray {
s16 id;
s16 length;
void read_from_file(TypedRef ref,
const decompiler::DecompilerTypeSystem& dts,
GameVersion version);
std::string print(const PrintSettings& settings, int indent) const;
std::vector<std::unique_ptr<DrawableTree>> trees;
};
// 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;
// (bsphere vector :inline :offset-assert 16)
Vector bsphere;
// (all-visible-list (pointer uint16) :offset-assert 32)
// (visible-list-length int32 :offset-assert 36)
s32 visible_list_length = -1;
s32 extra_vis_list_length = -1; // jak 2+ only
// (drawable-trees drawable-tree-array :offset-assert 40)
DrawableTreeArray drawable_tree_array;
// (pat pointer :offset-assert 44)
// (pat-length int32 :offset-assert 48)
//
// ;; some sort of texture remapping info
// (texture-remap-table (pointer uint64) :offset-assert 52)
// (texture-remap-table-len int32 :offset-assert 56)
std::vector<TextureRemap> texture_remap_table;
static constexpr int kNumTextureFlags = 10;
u16 texture_flags[kNumTextureFlags]; // jak 2 only
//
// (texture-ids (pointer texture-id) :offset-assert 60)
// (texture-page-count int32 :offset-assert 64)
//
// (unk-zero-0 basic :offset-assert 68)
//
// (name symbol :offset-assert 72)
std::string name;
// (nickname symbol :offset-assert 76)
// (vis-info level-vis-info 8 :offset-assert 80)
// (actors drawable-inline-array-actor :offset-assert 112)
DrawableInlineArrayActor actors;
// (cameras (array entity-camera) :offset-assert 116)
// (nodes (inline-array bsp-node) :offset-assert 120)
//
// (level level :offset-assert 124)
// (current-leaf-idx uint16 :offset-assert 128)
// (unk-data-2 uint16 9 :offset-assert 130)
//
// (boxes box8s-array :offset-assert 148)
// (current-bsp-back-flags uint32 :offset-assert 152)
// (ambients drawable-inline-array-ambient :offset-assert 156)
// (unk-data-4 float :offset-assert 160)
// (unk-data-5 float :offset-assert 164)
// (adgifs adgif-shader-array :offset-assert 168)
// (actor-birth-order (pointer uint32) :offset-assert 172)
// (split-box-indices (pointer uint16) :offset-assert 176)
// (unk-data-8 uint32 55 :offset-assert 180)
// jak 2 only
CollideHash collide_hash;
// jak 3 only
std::optional<HFragment> hfrag;
void read_from_file(const decompiler::LinkedObjectFile& file,
const decompiler::DecompilerTypeSystem& dts,
GameVersion version,
bool only_read_texture_remap = false);
std::string print(const PrintSettings& settings) const;
};
} // namespace level_tools