mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 11:26:18 -04:00
[jak2] Support per-proto shrub visibility (#3228)
Fixes the issue reported in https://github.com/open-goal/jak-project/issues/3168, https://github.com/open-goal/jak-project/issues/3189, https://github.com/open-goal/jak-project/issues/3166, https://github.com/open-goal/jak-project/issues/3152, https://github.com/open-goal/jak-project/issues/3224 where a small part of the pipes in the `strip-grenade` mission appear, but shouldn't.
This commit is contained in:
parent
e38fe70ac4
commit
a01182315b
|
@ -42,6 +42,7 @@ void ShrubDraw::serialize(Serializer& ser) {
|
|||
ser.from_ptr(&num_triangles);
|
||||
ser.from_ptr(&first_index_index);
|
||||
ser.from_ptr(&num_indices);
|
||||
ser.from_ptr(&proto_idx);
|
||||
}
|
||||
|
||||
void InstancedStripDraw::serialize(Serializer& ser) {
|
||||
|
@ -416,6 +417,9 @@ void ShrubTree::serialize(Serializer& ser) {
|
|||
for (auto& draw : static_draws) {
|
||||
draw.serialize(ser);
|
||||
}
|
||||
|
||||
ser.from_ptr(&has_per_proto_visibility_toggle);
|
||||
ser.from_string_vector(&proto_names);
|
||||
}
|
||||
|
||||
void BVH::serialize(Serializer& ser) {
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace tfrag3 {
|
|||
// - if changing any large things (vertices, vis, bvh, colors, textures) update get_memory_usage
|
||||
// - if adding a new category to the memory usage, update extract_level to print it.
|
||||
|
||||
constexpr int TFRAG3_VERSION = 38;
|
||||
constexpr int TFRAG3_VERSION = 39;
|
||||
|
||||
enum MemoryUsageCategory {
|
||||
TEXTURE,
|
||||
|
@ -219,6 +219,8 @@ struct ShrubDraw {
|
|||
|
||||
// for debug counting.
|
||||
u32 num_triangles = 0;
|
||||
|
||||
u16 proto_idx = 0;
|
||||
void serialize(Serializer& ser);
|
||||
};
|
||||
|
||||
|
@ -430,6 +432,10 @@ struct ShrubTree {
|
|||
std::vector<ShrubGpuVertex> vertices; // mesh vertices
|
||||
} unpacked;
|
||||
|
||||
// jak 2 and later can toggle on and off visibility per proto by name
|
||||
bool has_per_proto_visibility_toggle = false;
|
||||
std::vector<std::string> proto_names;
|
||||
|
||||
void serialize(Serializer& ser);
|
||||
void memory_usage(MemoryUsageTracker* tracker) const;
|
||||
void unpack();
|
||||
|
|
|
@ -21,8 +21,8 @@ struct FormFormattingConfig {
|
|||
bool combine_first_two_lines =
|
||||
false; // NOTE - basically hang, but will probably stick around after hang is gone, may be
|
||||
// redundant (inline_until_index!)
|
||||
std::function<std::optional<int>(const std::vector<std::string>& curr_lines)> inline_until_index =
|
||||
[](std::vector<std::string> curr_lines) { return std::nullopt; };
|
||||
std::function<std::optional<int>(const std::vector<std::string>& /*curr_lines*/)>
|
||||
inline_until_index = [](std::vector<std::string> /*curr_lines*/) { return std::nullopt; };
|
||||
bool has_constant_pairs = false;
|
||||
bool prevent_inlining = false; // TODO - duplicate of below
|
||||
std::function<bool(FormFormattingConfig, int num_refs)> should_prevent_inlining =
|
||||
|
|
|
@ -424,7 +424,8 @@ void make_draws(tfrag3::Level& lev,
|
|||
std::vector<std::vector<u32>> indices_regrouped_by_draw;
|
||||
std::unordered_map<u32, std::vector<u32>> static_draws_by_tex;
|
||||
size_t global_vert_counter = 0;
|
||||
for (auto& proto : protos) {
|
||||
for (u32 proto_idx = 0; proto_idx < protos.size(); proto_idx++) {
|
||||
auto& proto = protos[proto_idx];
|
||||
// packed_vert_indices[frag][draw] = {start, end}
|
||||
std::vector<std::vector<std::pair<int, int>>> packed_vert_indices;
|
||||
|
||||
|
@ -509,7 +510,9 @@ void make_draws(tfrag3::Level& lev,
|
|||
std::vector<u32>* verts_to_add_to = nullptr;
|
||||
if (existing_draws_in_tex != static_draws_by_tex.end()) {
|
||||
for (auto idx : existing_draws_in_tex->second) {
|
||||
if (tree_out.static_draws.at(idx).mode == mode) {
|
||||
auto& candidate_draw_out = tree_out.static_draws.at(idx);
|
||||
if (candidate_draw_out.mode == mode && (!tree_out.has_per_proto_visibility_toggle ||
|
||||
candidate_draw_out.proto_idx == proto_idx)) {
|
||||
draw_to_add_to = &tree_out.static_draws[idx];
|
||||
verts_to_add_to = &indices_regrouped_by_draw[idx];
|
||||
}
|
||||
|
@ -523,6 +526,9 @@ void make_draws(tfrag3::Level& lev,
|
|||
draw_to_add_to = &tree_out.static_draws.back();
|
||||
draw_to_add_to->mode = mode;
|
||||
draw_to_add_to->tree_tex_id = idx_in_lev_data;
|
||||
if (tree_out.has_per_proto_visibility_toggle) {
|
||||
draw_to_add_to->proto_idx = proto_idx;
|
||||
}
|
||||
verts_to_add_to = &indices_regrouped_by_draw.emplace_back();
|
||||
}
|
||||
|
||||
|
@ -573,10 +579,16 @@ void extract_shrub(const shrub_types::DrawableTreeInstanceShrub* tree,
|
|||
bool dump_level,
|
||||
GameVersion version) {
|
||||
auto& tree_out = out.shrub_trees.emplace_back();
|
||||
|
||||
if (version > GameVersion::Jak1) {
|
||||
tree_out.has_per_proto_visibility_toggle = true;
|
||||
}
|
||||
|
||||
auto& protos = tree->info.prototype_inline_array_shrub;
|
||||
std::vector<ShrubProtoInfo> proto_info;
|
||||
for (auto& proto : protos.data) {
|
||||
proto_info.push_back(extract_proto(proto, tex_db, map, version));
|
||||
tree_out.proto_names.push_back(proto.name);
|
||||
}
|
||||
|
||||
for (auto& arr : tree->discovered_arrays) {
|
||||
|
|
|
@ -45,6 +45,13 @@ void Shrub::render(DmaFollower& dma, SharedRenderState* render_state, ScopedProf
|
|||
memcpy(&m_pc_port_data, pc_port_data.data, sizeof(TfragPcPortData));
|
||||
m_pc_port_data.level_name[11] = '\0';
|
||||
|
||||
if (render_state->version == GameVersion::Jak2) {
|
||||
// jak 2 proto visibility
|
||||
auto proto_mask_data = dma.read_and_advance();
|
||||
m_proto_vis_data = proto_mask_data.data;
|
||||
m_proto_vis_data_size = proto_mask_data.size_bytes;
|
||||
}
|
||||
|
||||
while (dma.current_tag_offset() != render_state->next_bucket) {
|
||||
dma.read_and_advance();
|
||||
}
|
||||
|
@ -91,6 +98,13 @@ void Shrub::update_load(const LevelData* loader_data) {
|
|||
m_trees[l_tree].vertex_buffer = loader_data->shrub_vertex_data[l_tree];
|
||||
m_trees[l_tree].vert_count = verts;
|
||||
m_trees[l_tree].draws = &tree.static_draws;
|
||||
m_trees[l_tree].proto_vis_mask.clear();
|
||||
m_trees[l_tree].proto_vis_mask.resize(tree.proto_names.size(), true);
|
||||
m_trees[l_tree].proto_name_to_idx.clear();
|
||||
size_t i = 0;
|
||||
for (auto& name : tree.proto_names) {
|
||||
m_trees[l_tree].proto_name_to_idx[name].push_back(i++);
|
||||
}
|
||||
m_trees[l_tree].colors = &tree.time_of_day_colors;
|
||||
m_trees[l_tree].index_data = tree.indices.data();
|
||||
m_trees[l_tree].tod_cache = swizzle_time_of_day(tree.time_of_day_colors);
|
||||
|
@ -216,6 +230,45 @@ void Shrub::render_all_trees(const TfragRenderSettings& settings,
|
|||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
void update_vis_mask(std::vector<bool>& vis_mask,
|
||||
const u8* data,
|
||||
u32 data_size,
|
||||
const std::unordered_map<std::string, std::vector<u32>>& name_to_idx) {
|
||||
char name_buffer[256]; // ??
|
||||
|
||||
for (u32 i = 0; i < vis_mask.size(); i++) {
|
||||
vis_mask[i] = true;
|
||||
}
|
||||
|
||||
const u8* end = data + data_size;
|
||||
while (true) {
|
||||
int name_idx = 0;
|
||||
while (*data) {
|
||||
name_buffer[name_idx++] = *data;
|
||||
data++;
|
||||
}
|
||||
if (name_idx) {
|
||||
ASSERT(name_idx < 254);
|
||||
name_buffer[name_idx] = '\0';
|
||||
const auto& it = name_to_idx.find(name_buffer);
|
||||
if (it != name_to_idx.end()) {
|
||||
for (auto x : name_to_idx.at(name_buffer)) {
|
||||
vis_mask[x] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (*data == 0) {
|
||||
if (data >= end) {
|
||||
return;
|
||||
}
|
||||
data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void Shrub::render_tree(int idx,
|
||||
const TfragRenderSettings& settings,
|
||||
SharedRenderState* render_state,
|
||||
|
@ -259,6 +312,10 @@ void Shrub::render_tree(int idx,
|
|||
glActiveTexture(GL_TEXTURE0);
|
||||
glEnable(GL_PRIMITIVE_RESTART);
|
||||
glPrimitiveRestartIndex(UINT32_MAX);
|
||||
if (m_proto_vis_data) {
|
||||
update_vis_mask(tree.proto_vis_mask, m_proto_vis_data, m_proto_vis_data_size,
|
||||
tree.proto_name_to_idx);
|
||||
}
|
||||
tree.perf.tod_time.add(setup_timer.getSeconds());
|
||||
|
||||
int last_texture = -1;
|
||||
|
@ -282,6 +339,9 @@ void Shrub::render_tree(int idx,
|
|||
|
||||
for (size_t draw_idx = 0; draw_idx < tree.draws->size(); draw_idx++) {
|
||||
const auto& draw = tree.draws->operator[](draw_idx);
|
||||
if (!tree.proto_vis_mask.at(draw.proto_idx)) {
|
||||
continue;
|
||||
}
|
||||
const auto& multidraw_indices = m_cache.multidraw_offset_per_stripdraw[draw_idx];
|
||||
const auto& singledraw_indices = m_cache.draw_idx_temp[draw_idx];
|
||||
|
||||
|
|
|
@ -42,6 +42,8 @@ class Shrub : public BucketRenderer {
|
|||
const std::vector<tfrag3::TimeOfDayColor>* colors = nullptr;
|
||||
const u32* index_data = nullptr;
|
||||
SwizzledTimeOfDay tod_cache;
|
||||
std::vector<bool> proto_vis_mask;
|
||||
std::unordered_map<std::string, std::vector<u32>> proto_name_to_idx;
|
||||
|
||||
struct {
|
||||
u32 draws = 0;
|
||||
|
@ -78,4 +80,6 @@ class Shrub : public BucketRenderer {
|
|||
std::vector<void*> multidraw_index_offset_buffer;
|
||||
} m_cache;
|
||||
TfragPcPortData m_pc_port_data;
|
||||
const u8* m_proto_vis_data = nullptr;
|
||||
int m_proto_vis_data_size = 0;
|
||||
};
|
||||
|
|
|
@ -10,6 +10,58 @@
|
|||
|
||||
;; DECOMP BEGINS
|
||||
|
||||
(defun pc-add-shrub-vis-mask ((dma-buf dma-buffer) (lev level))
|
||||
"Add data so Proto.cpp can disable drawing for disabled protos."
|
||||
(let ((packet (the-as dma-packet (-> dma-buf base))))
|
||||
(set! (-> packet vif0) (new 'static 'vif-tag))
|
||||
(set! (-> packet vif1) (new 'static 'vif-tag :cmd (vif-cmd pc-port)))
|
||||
(set! (-> dma-buf base) (the pointer (&+ packet 16)))
|
||||
|
||||
(let ((lev-trees (-> lev bsp drawable-trees))
|
||||
(data-ptr (the (pointer uint8) (-> dma-buf base)))
|
||||
)
|
||||
(dotimes (tree-idx (-> lev-trees length))
|
||||
(let ((tree (-> lev-trees data tree-idx)))
|
||||
(when (= (-> tree type) drawable-tree-instance-shrub)
|
||||
(let* ((shrub-tree (the drawable-tree-instance-shrub tree))
|
||||
(protos (-> shrub-tree info prototype-inline-array-shrub))
|
||||
)
|
||||
(dotimes (i (-> protos length))
|
||||
(let ((proto (-> protos data i)))
|
||||
(when (logtest? (-> proto flags) (prototype-flags visible))
|
||||
;; invisible!
|
||||
;; (format 0 "invis: ~A~%" (-> proto name))
|
||||
(let ((src (-> proto name data)))
|
||||
(while (nonzero? (-> src))
|
||||
(set! (-> data-ptr) (-> src))
|
||||
(&+! src 1)
|
||||
(&+! data-ptr 1)
|
||||
)
|
||||
(set! (-> data-ptr) 0)
|
||||
(&+! data-ptr 1)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
;; align
|
||||
(while (nonzero? (logand data-ptr #xf))
|
||||
(set! (-> data-ptr) 0)
|
||||
(&+! data-ptr 1)
|
||||
)
|
||||
(set! (-> packet dma) (new 'static 'dma-tag
|
||||
:id (dma-tag-id cnt)
|
||||
:qwc (/ (&- data-ptr (-> dma-buf base)) 16))
|
||||
)
|
||||
(set! (-> dma-buf base) data-ptr)
|
||||
#f
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defmethod login ((this billboard))
|
||||
"Set up the billboard adgif shader"
|
||||
(adgif-shader-login (-> this flat))
|
||||
|
@ -481,6 +533,7 @@
|
|||
(let* ((shrub-dma-buff (-> *display* frames (-> *display* on-screen) global-buf))
|
||||
(dma-start (-> shrub-dma-buff base)))
|
||||
(add-pc-tfrag3-data shrub-dma-buff (-> *level* draw-level *draw-index*))
|
||||
(pc-add-shrub-vis-mask shrub-dma-buff (-> *level* draw-level *draw-index*))
|
||||
(let ((a3-22 (-> shrub-dma-buff base)))
|
||||
(let ((v1-57 (the-as object (-> shrub-dma-buff base))))
|
||||
(set! (-> (the-as dma-packet v1-57) dma) (new 'static 'dma-tag :id (dma-tag-id next)))
|
||||
|
|
Loading…
Reference in a new issue