mirror of
https://github.com/open-goal/jak-project
synced 2026-07-10 23:22:17 -04:00
[tie] support per-proto visibility flags (#2212)
Jak 2 adds a feature to disable protos in TIE. It's used to hide things like steps for a future mission in ruins, and also to hide the static version of the tower when it switches to the merc version for the cutscene: 
This commit is contained in:
@@ -209,6 +209,9 @@ void TieTree::serialize(Serializer& ser) {
|
||||
packed_vertices.serialize(ser);
|
||||
ser.from_pod_vector(&colors);
|
||||
bvh.serialize(ser);
|
||||
|
||||
ser.from_ptr(&has_per_proto_visibility_toggle);
|
||||
ser.from_string_vector(&proto_names);
|
||||
}
|
||||
|
||||
void ShrubTree::serialize(Serializer& ser) {
|
||||
|
||||
@@ -73,7 +73,7 @@ struct MemoryUsageTracker {
|
||||
void add(MemoryUsageCategory category, u32 size_bytes) { data[category] += size_bytes; }
|
||||
};
|
||||
|
||||
constexpr int TFRAG3_VERSION = 24;
|
||||
constexpr int TFRAG3_VERSION = 25;
|
||||
|
||||
// These vertices should be uploaded to the GPU at load time and don't change
|
||||
struct PreloadedVertex {
|
||||
@@ -188,7 +188,8 @@ struct StripDraw {
|
||||
struct VisGroup {
|
||||
u32 num_inds = 0; // number of vertex indices in this group
|
||||
u32 num_tris = 0; // number of triangles
|
||||
u32 vis_idx_in_pc_bvh = 0; // the visibility group they belong to (in BVH)
|
||||
u16 vis_idx_in_pc_bvh = 0; // the visibility group they belong to (in BVH)
|
||||
u16 tie_proto_idx = 0; // index of tie proto (tie only)
|
||||
};
|
||||
std::vector<VisGroup> vis_groups;
|
||||
|
||||
@@ -323,6 +324,10 @@ struct TieTree {
|
||||
std::vector<InstancedStripDraw> instanced_wind_draws;
|
||||
std::vector<TieWindInstance> wind_instance_info;
|
||||
|
||||
// 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;
|
||||
|
||||
struct {
|
||||
std::vector<PreloadedVertex> vertices; // mesh vertices
|
||||
std::vector<u32> indices;
|
||||
|
||||
@@ -156,6 +156,17 @@ class Serializer {
|
||||
from_raw_data(vec->data(), sizeof(T) * vec->size());
|
||||
}
|
||||
|
||||
void from_string_vector(std::vector<std::string>* vec) {
|
||||
if (is_saving()) {
|
||||
save<size_t>(vec->size());
|
||||
} else {
|
||||
vec->resize(load<size_t>());
|
||||
}
|
||||
for (auto& str : *vec) {
|
||||
from_str(&str);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Are we saving?
|
||||
*/
|
||||
|
||||
@@ -2053,6 +2053,7 @@ void make_tfrag3_data(std::map<u32, std::vector<GroupedDraw>>& draws,
|
||||
|
||||
for (auto& strip : draw.strips) {
|
||||
tfrag3::StripDraw::VisGroup vgroup;
|
||||
ASSERT(strip.tfrag_id < UINT16_MAX);
|
||||
vgroup.vis_idx_in_pc_bvh = strip.tfrag_id; // associate with the tfrag for culling
|
||||
vgroup.num_inds = strip.verts.size() + 1; // one for the primitive restart!
|
||||
vgroup.num_tris = strip.verts.size() - 2;
|
||||
@@ -2231,7 +2232,7 @@ void extract_tfrag(const level_tools::DrawableTreeTfrag* tree,
|
||||
for (auto& str : draw.vis_groups) {
|
||||
auto it = tfrag_parents.find(str.vis_idx_in_pc_bvh);
|
||||
if (it == tfrag_parents.end()) {
|
||||
str.vis_idx_in_pc_bvh = UINT32_MAX;
|
||||
str.vis_idx_in_pc_bvh = UINT16_MAX;
|
||||
} else {
|
||||
str.vis_idx_in_pc_bvh = it->second;
|
||||
}
|
||||
|
||||
@@ -2026,14 +2026,24 @@ DrawMode process_draw_mode(const AdgifInfo& info, bool use_atest, bool use_decal
|
||||
void add_vertices_and_static_draw(tfrag3::TieTree& tree,
|
||||
tfrag3::Level& lev,
|
||||
const TextureDB& tdb,
|
||||
const std::vector<TieProtoInfo>& protos) {
|
||||
const std::vector<TieProtoInfo>& protos,
|
||||
GameVersion version) {
|
||||
// our current approach for static draws is just to flatten to giant mesh, except for wind stuff.
|
||||
// this map sorts these two types of draws by texture.
|
||||
std::unordered_map<u32, std::vector<u32>> static_draws_by_tex;
|
||||
std::unordered_map<u32, std::vector<u32>> wind_draws_by_tex;
|
||||
|
||||
if (version > GameVersion::Jak1) {
|
||||
tree.has_per_proto_visibility_toggle = true;
|
||||
}
|
||||
|
||||
// loop over all prototypes
|
||||
for (auto& proto : protos) {
|
||||
for (size_t proto_idx = 0; proto_idx < protos.size(); proto_idx++) {
|
||||
const auto& proto = protos[proto_idx];
|
||||
if (tree.has_per_proto_visibility_toggle) {
|
||||
tree.proto_names.push_back(proto.name);
|
||||
}
|
||||
|
||||
if (proto.uses_generic) {
|
||||
// generic ties go through generic
|
||||
continue;
|
||||
@@ -2220,7 +2230,15 @@ void add_vertices_and_static_draw(tfrag3::TieTree& tree,
|
||||
|
||||
// now we have a draw, time to add vertices
|
||||
tfrag3::StripDraw::VisGroup vgroup;
|
||||
vgroup.vis_idx_in_pc_bvh = inst.vis_id; // associate with the instance for culling
|
||||
ASSERT(inst.vis_id < UINT16_MAX);
|
||||
vgroup.vis_idx_in_pc_bvh = inst.vis_id; // associate with the instance for culling
|
||||
|
||||
// only bother with tie proto idx if we use it
|
||||
if (tree.has_per_proto_visibility_toggle) {
|
||||
ASSERT(proto_idx < UINT16_MAX);
|
||||
vgroup.tie_proto_idx = proto_idx;
|
||||
}
|
||||
|
||||
vgroup.num_inds = strip.verts.size() + 1; // one for the primitive restart!
|
||||
vgroup.num_tris = strip.verts.size() - 2;
|
||||
draw_to_add_to->num_triangles += strip.verts.size() - 2;
|
||||
@@ -2284,7 +2302,8 @@ void merge_groups(std::vector<tfrag3::StripDraw::VisGroup>& grps) {
|
||||
std::vector<tfrag3::StripDraw::VisGroup> result;
|
||||
result.push_back(grps.at(0));
|
||||
for (size_t i = 1; i < grps.size(); i++) {
|
||||
if (grps[i].vis_idx_in_pc_bvh == result.back().vis_idx_in_pc_bvh) {
|
||||
if (grps[i].vis_idx_in_pc_bvh == result.back().vis_idx_in_pc_bvh &&
|
||||
grps[i].tie_proto_idx == result.back().tie_proto_idx) {
|
||||
result.back().num_tris += grps[i].num_tris;
|
||||
result.back().num_inds += grps[i].num_inds;
|
||||
} else {
|
||||
@@ -2367,14 +2386,14 @@ void extract_tie(const level_tools::DrawableTreeInstanceTie* tree,
|
||||
auto full_palette = make_big_palette(info);
|
||||
|
||||
// create draws
|
||||
add_vertices_and_static_draw(this_tree, out, tex_db, info);
|
||||
add_vertices_and_static_draw(this_tree, out, tex_db, info, version);
|
||||
|
||||
// remap vis indices and merge
|
||||
for (auto& draw : this_tree.static_draws) {
|
||||
for (auto& str : draw.vis_groups) {
|
||||
auto it = instance_parents.find(str.vis_idx_in_pc_bvh);
|
||||
if (it == instance_parents.end()) {
|
||||
str.vis_idx_in_pc_bvh = UINT32_MAX;
|
||||
str.vis_idx_in_pc_bvh = UINT16_MAX;
|
||||
} else {
|
||||
str.vis_idx_in_pc_bvh = it->second;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "common/global_profiler/GlobalProfiler.h"
|
||||
#include "common/log/log.h"
|
||||
#include "common/util/Assert.h"
|
||||
|
||||
#include "third-party/imgui/imgui.h"
|
||||
|
||||
@@ -120,6 +121,11 @@ void Tie3::update_load(const LevelData* loader_data) {
|
||||
}
|
||||
}
|
||||
|
||||
lod_tree[l_tree].has_proto_visibility = tree.has_per_proto_visibility_toggle;
|
||||
if (tree.has_per_proto_visibility_toggle) {
|
||||
lod_tree[l_tree].proto_visibility.init(tree.proto_names);
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE10);
|
||||
glGenTextures(1, &lod_tree[l_tree].time_of_day_texture);
|
||||
glBindTexture(GL_TEXTURE_1D, lod_tree[l_tree].time_of_day_texture);
|
||||
@@ -139,6 +145,7 @@ void Tie3::update_load(const LevelData* loader_data) {
|
||||
m_wind_vectors.resize(4 * max_wind_idx + 4); // 4x u32's per wind.
|
||||
m_cache.draw_idx_temp.resize(max_draws);
|
||||
m_cache.index_temp.resize(max_inds);
|
||||
|
||||
ASSERT(time_of_day_count <= TIME_OF_DAY_COLOR_COUNT);
|
||||
}
|
||||
|
||||
@@ -361,7 +368,14 @@ void Tie3::render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfi
|
||||
auto wind_data = dma.read_and_advance();
|
||||
ASSERT(wind_data.size_bytes == sizeof(WindWork));
|
||||
memcpy(&m_wind_data, wind_data.data, sizeof(WindWork));
|
||||
} else {
|
||||
}
|
||||
|
||||
const u8* proto_vis_data = nullptr;
|
||||
size_t proto_vis_data_size = 0;
|
||||
if (render_state->version == GameVersion::Jak2) {
|
||||
auto proto_mask_data = dma.read_and_advance();
|
||||
proto_vis_data = proto_mask_data.data;
|
||||
proto_vis_data_size = proto_mask_data.size_bytes;
|
||||
}
|
||||
|
||||
while (dma.current_tag_offset() != render_state->next_bucket) {
|
||||
@@ -390,20 +404,22 @@ void Tie3::render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfi
|
||||
m_has_level = setup_for_level(m_pc_port_data.level_name, render_state);
|
||||
}
|
||||
|
||||
render_all_trees(lod(), settings, render_state, prof);
|
||||
render_all_trees(lod(), settings, render_state, prof, proto_vis_data, proto_vis_data_size);
|
||||
}
|
||||
|
||||
void Tie3::render_all_trees(int geom,
|
||||
const TfragRenderSettings& settings,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof) {
|
||||
ScopedProfilerNode& prof,
|
||||
const u8* proto_vis_data,
|
||||
size_t proto_vis_data_size) {
|
||||
Timer all_tree_timer;
|
||||
if (m_override_level && m_pending_user_level) {
|
||||
m_has_level = setup_for_level(*m_pending_user_level, render_state);
|
||||
m_pending_user_level = {};
|
||||
}
|
||||
for (u32 i = 0; i < m_trees[geom].size(); i++) {
|
||||
render_tree(i, geom, settings, render_state, prof);
|
||||
render_tree(i, geom, settings, render_state, prof, proto_vis_data, proto_vis_data_size);
|
||||
}
|
||||
m_all_tree_time.add(all_tree_timer.getSeconds());
|
||||
}
|
||||
@@ -523,7 +539,9 @@ void Tie3::render_tree(int idx,
|
||||
int geom,
|
||||
const TfragRenderSettings& settings,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof) {
|
||||
ScopedProfilerNode& prof,
|
||||
const u8* proto_vis_data,
|
||||
size_t proto_vis_data_size) {
|
||||
// reset perf
|
||||
Timer tree_timer;
|
||||
auto& tree = m_trees.at(geom).at(idx);
|
||||
@@ -540,6 +558,11 @@ void Tie3::render_tree(int idx,
|
||||
m_color_result.resize(tree.colors->size());
|
||||
}
|
||||
|
||||
// update proto vis mask
|
||||
if (proto_vis_data) {
|
||||
tree.proto_visibility.update(proto_vis_data, proto_vis_data_size);
|
||||
}
|
||||
|
||||
Timer interp_timer;
|
||||
if (m_use_fast_time_of_day) {
|
||||
interp_time_of_day_fast(settings.itimes, tree.tod_cache, m_color_result.data());
|
||||
@@ -588,9 +611,15 @@ void Tie3::render_tree(int idx,
|
||||
make_all_visible_index_list(m_cache.draw_idx_temp.data(), m_cache.index_temp.data(),
|
||||
*tree.draws, tree.index_data, &num_tris);
|
||||
} else {
|
||||
idx_buffer_size = make_index_list_from_vis_string(
|
||||
m_cache.draw_idx_temp.data(), m_cache.index_temp.data(), *tree.draws, m_cache.vis_temp,
|
||||
tree.index_data, &num_tris);
|
||||
if (tree.has_proto_visibility) {
|
||||
idx_buffer_size = make_index_list_from_vis_and_proto_string(
|
||||
m_cache.draw_idx_temp.data(), m_cache.index_temp.data(), *tree.draws, m_cache.vis_temp,
|
||||
tree.proto_visibility.vis_flags, tree.index_data, &num_tris);
|
||||
} else {
|
||||
idx_buffer_size = make_index_list_from_vis_string(
|
||||
m_cache.draw_idx_temp.data(), m_cache.index_temp.data(), *tree.draws, m_cache.vis_temp,
|
||||
tree.index_data, &num_tris);
|
||||
}
|
||||
}
|
||||
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx_buffer_size * sizeof(u32), m_cache.index_temp.data(),
|
||||
@@ -606,9 +635,17 @@ void Tie3::render_tree(int idx,
|
||||
tree.perf.index_time.add(index_timer.getSeconds());
|
||||
} else {
|
||||
Timer index_timer;
|
||||
num_tris = make_multidraws_from_vis_string(
|
||||
m_cache.multidraw_offset_per_stripdraw.data(), m_cache.multidraw_count_buffer.data(),
|
||||
m_cache.multidraw_index_offset_buffer.data(), *tree.draws, m_cache.vis_temp);
|
||||
if (tree.has_proto_visibility) {
|
||||
num_tris = make_multidraws_from_vis_and_proto_string(
|
||||
m_cache.multidraw_offset_per_stripdraw.data(), m_cache.multidraw_count_buffer.data(),
|
||||
m_cache.multidraw_index_offset_buffer.data(), *tree.draws, m_cache.vis_temp,
|
||||
tree.proto_visibility.vis_flags);
|
||||
} else {
|
||||
num_tris = make_multidraws_from_vis_string(
|
||||
m_cache.multidraw_offset_per_stripdraw.data(), m_cache.multidraw_count_buffer.data(),
|
||||
m_cache.multidraw_index_offset_buffer.data(), *tree.draws, m_cache.vis_temp);
|
||||
}
|
||||
|
||||
tree.perf.index_time.add(index_timer.getSeconds());
|
||||
}
|
||||
}
|
||||
@@ -731,6 +768,7 @@ void Tie3::draw_debug_window() {
|
||||
ImGui::Text("draw: %d", perf.draws);
|
||||
ImGui::Text("wind draw: %d", perf.wind_draws);
|
||||
ImGui::Text("total: %.2f", perf.tree_time.get());
|
||||
ImGui::Text("proto vis: %.2f", perf.proto_vis_time.get() * 1000.f);
|
||||
ImGui::Text("cull: %.2f index: %.2f tod: %.2f setup: %.2f draw: %.2f",
|
||||
perf.cull_time.get() * 1000.f, perf.index_time.get() * 1000.f,
|
||||
perf.tod_time.get() * 1000.f, perf.setup_time.get() * 1000.f,
|
||||
@@ -739,3 +777,55 @@ void Tie3::draw_debug_window() {
|
||||
}
|
||||
ImGui::Text("All trees: %.2f", 1000.f * m_all_tree_time.get());
|
||||
}
|
||||
|
||||
void TieProtoVisibility::init(const std::vector<std::string>& names) {
|
||||
vis_flags.resize(names.size());
|
||||
for (auto& x : vis_flags) {
|
||||
x = 1;
|
||||
}
|
||||
all_visible = true;
|
||||
name_to_idx.clear();
|
||||
size_t i = 0;
|
||||
for (auto& name : names) {
|
||||
name_to_idx[name].push_back(i++);
|
||||
}
|
||||
}
|
||||
|
||||
void TieProtoVisibility::update(const u8* data, size_t size) {
|
||||
char name_buffer[256]; // ??
|
||||
|
||||
if (!all_visible) {
|
||||
for (auto& x : vis_flags) {
|
||||
x = 1;
|
||||
}
|
||||
all_visible = true;
|
||||
}
|
||||
|
||||
const u8* end = 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()) {
|
||||
all_visible = false;
|
||||
for (auto x : name_to_idx.at(name_buffer)) {
|
||||
vis_flags[x] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (*data == 0) {
|
||||
if (data >= end) {
|
||||
return;
|
||||
}
|
||||
data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,16 @@
|
||||
#include "game/graphics/opengl_renderer/background/background_common.h"
|
||||
#include "game/graphics/pipelines/opengl.h"
|
||||
|
||||
struct TieProtoVisibility {
|
||||
void init(const std::vector<std::string>& names);
|
||||
void update(const u8* data, size_t size);
|
||||
|
||||
std::vector<u8> vis_flags;
|
||||
std::unordered_map<std::string, std::vector<u32>> name_to_idx;
|
||||
|
||||
bool all_visible = true;
|
||||
};
|
||||
|
||||
class Tie3 : public BucketRenderer {
|
||||
public:
|
||||
Tie3(const std::string& name, int my_id, int level_id);
|
||||
@@ -19,12 +29,16 @@ class Tie3 : public BucketRenderer {
|
||||
void render_all_trees(int geom,
|
||||
const TfragRenderSettings& settings,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof);
|
||||
ScopedProfilerNode& prof,
|
||||
const u8* proto_vis_data,
|
||||
size_t proto_vis_data_size);
|
||||
void render_tree(int idx,
|
||||
int geom,
|
||||
const TfragRenderSettings& settings,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof);
|
||||
ScopedProfilerNode& prof,
|
||||
const u8* proto_vis_data,
|
||||
size_t proto_vis_data_size);
|
||||
bool setup_for_level(const std::string& str, SharedRenderState* render_state);
|
||||
|
||||
struct WindWork {
|
||||
@@ -70,12 +84,16 @@ class Tie3 : public BucketRenderer {
|
||||
GLuint wind_vertex_index_buffer;
|
||||
std::vector<u32> wind_vertex_index_offsets;
|
||||
|
||||
bool has_proto_visibility = false;
|
||||
TieProtoVisibility proto_visibility;
|
||||
|
||||
struct {
|
||||
u32 draws = 0;
|
||||
u32 wind_draws = 0;
|
||||
Filtered<float> cull_time;
|
||||
Filtered<float> index_time;
|
||||
Filtered<float> tod_time;
|
||||
Filtered<float> proto_vis_time;
|
||||
Filtered<float> setup_time;
|
||||
Filtered<float> draw_time;
|
||||
Filtered<float> tree_time;
|
||||
|
||||
@@ -516,7 +516,64 @@ u32 make_multidraws_from_vis_string(std::pair<int, int>* draw_ptrs_out,
|
||||
u64 run_start = 0;
|
||||
for (auto& grp : draw.vis_groups) {
|
||||
sanity_check += grp.num_inds;
|
||||
bool vis = grp.vis_idx_in_pc_bvh == 0xffffffff || vis_data[grp.vis_idx_in_pc_bvh];
|
||||
bool vis = grp.vis_idx_in_pc_bvh == UINT16_MAX || vis_data[grp.vis_idx_in_pc_bvh];
|
||||
if (vis) {
|
||||
num_tris += grp.num_tris;
|
||||
}
|
||||
|
||||
if (building_run) {
|
||||
if (!vis) {
|
||||
building_run = false;
|
||||
counts_out[md_idx] = iidx - run_start;
|
||||
index_offsets_out[md_idx] = (void*)(run_start * sizeof(u32));
|
||||
ds.second++;
|
||||
md_idx++;
|
||||
}
|
||||
} else {
|
||||
if (vis) {
|
||||
building_run = true;
|
||||
run_start = iidx;
|
||||
}
|
||||
}
|
||||
|
||||
iidx += grp.num_inds;
|
||||
}
|
||||
|
||||
if (building_run) {
|
||||
building_run = false;
|
||||
counts_out[md_idx] = iidx - run_start;
|
||||
index_offsets_out[md_idx] = (void*)(run_start * sizeof(u32));
|
||||
ds.second++;
|
||||
md_idx++;
|
||||
}
|
||||
|
||||
draw_ptrs_out[i] = ds;
|
||||
}
|
||||
return num_tris;
|
||||
}
|
||||
|
||||
u32 make_multidraws_from_vis_and_proto_string(std::pair<int, int>* draw_ptrs_out,
|
||||
GLsizei* counts_out,
|
||||
void** index_offsets_out,
|
||||
const std::vector<tfrag3::StripDraw>& draws,
|
||||
const std::vector<u8>& vis_data,
|
||||
const std::vector<u8>& proto_vis_data) {
|
||||
u64 md_idx = 0;
|
||||
u32 num_tris = 0;
|
||||
u32 sanity_check = 0;
|
||||
for (size_t i = 0; i < draws.size(); i++) {
|
||||
const auto& draw = draws[i];
|
||||
u64 iidx = draw.unpacked.idx_of_first_idx_in_full_buffer;
|
||||
ASSERT(sanity_check == iidx);
|
||||
std::pair<int, int> ds;
|
||||
ds.first = md_idx;
|
||||
ds.second = 0;
|
||||
bool building_run = false;
|
||||
u64 run_start = 0;
|
||||
for (auto& grp : draw.vis_groups) {
|
||||
sanity_check += grp.num_inds;
|
||||
bool vis = (grp.vis_idx_in_pc_bvh == UINT16_MAX || vis_data[grp.vis_idx_in_pc_bvh]) &&
|
||||
proto_vis_data[grp.tie_proto_idx];
|
||||
if (vis) {
|
||||
num_tris += grp.num_tris;
|
||||
}
|
||||
@@ -569,7 +626,64 @@ u32 make_index_list_from_vis_string(std::pair<int, int>* group_out,
|
||||
int run_start_out = 0;
|
||||
int run_start_in = 0;
|
||||
for (auto& grp : draw.vis_groups) {
|
||||
bool vis = grp.vis_idx_in_pc_bvh == 0xffffffff || vis_data[grp.vis_idx_in_pc_bvh];
|
||||
bool vis = grp.vis_idx_in_pc_bvh == UINT16_MAX || vis_data[grp.vis_idx_in_pc_bvh];
|
||||
if (vis) {
|
||||
num_tris += grp.num_tris;
|
||||
}
|
||||
|
||||
if (building_run) {
|
||||
if (vis) {
|
||||
idx_buffer_ptr += grp.num_inds;
|
||||
} else {
|
||||
building_run = false;
|
||||
memcpy(&idx_out[run_start_out],
|
||||
idx_in + draw.unpacked.idx_of_first_idx_in_full_buffer + run_start_in,
|
||||
(idx_buffer_ptr - run_start_out) * sizeof(u32));
|
||||
}
|
||||
} else {
|
||||
if (vis) {
|
||||
building_run = true;
|
||||
run_start_out = idx_buffer_ptr;
|
||||
run_start_in = vtx_idx;
|
||||
idx_buffer_ptr += grp.num_inds;
|
||||
}
|
||||
}
|
||||
vtx_idx += grp.num_inds;
|
||||
}
|
||||
|
||||
if (building_run) {
|
||||
memcpy(&idx_out[run_start_out],
|
||||
idx_in + draw.unpacked.idx_of_first_idx_in_full_buffer + run_start_in,
|
||||
(idx_buffer_ptr - run_start_out) * sizeof(u32));
|
||||
}
|
||||
|
||||
ds.second = idx_buffer_ptr - ds.first;
|
||||
group_out[i] = ds;
|
||||
}
|
||||
*num_tris_out = num_tris;
|
||||
return idx_buffer_ptr;
|
||||
}
|
||||
|
||||
u32 make_index_list_from_vis_and_proto_string(std::pair<int, int>* group_out,
|
||||
u32* idx_out,
|
||||
const std::vector<tfrag3::StripDraw>& draws,
|
||||
const std::vector<u8>& vis_data,
|
||||
const std::vector<u8>& proto_vis_data,
|
||||
const u32* idx_in,
|
||||
u32* num_tris_out) {
|
||||
int idx_buffer_ptr = 0;
|
||||
u32 num_tris = 0;
|
||||
for (size_t i = 0; i < draws.size(); i++) {
|
||||
const auto& draw = draws[i];
|
||||
int vtx_idx = 0;
|
||||
std::pair<int, int> ds;
|
||||
ds.first = idx_buffer_ptr;
|
||||
bool building_run = false;
|
||||
int run_start_out = 0;
|
||||
int run_start_in = 0;
|
||||
for (auto& grp : draw.vis_groups) {
|
||||
bool vis = (grp.vis_idx_in_pc_bvh == UINT16_MAX || vis_data[grp.vis_idx_in_pc_bvh]) &&
|
||||
proto_vis_data[grp.tie_proto_idx];
|
||||
if (vis) {
|
||||
num_tris += grp.num_tris;
|
||||
}
|
||||
|
||||
@@ -99,4 +99,19 @@ u32 make_index_list_from_vis_string(std::pair<int, int>* group_out,
|
||||
u32 make_all_visible_index_list(std::pair<int, int>* group_out,
|
||||
u32* idx_out,
|
||||
const std::vector<tfrag3::ShrubDraw>& draws,
|
||||
const u32* idx_in);
|
||||
const u32* idx_in);
|
||||
|
||||
u32 make_multidraws_from_vis_and_proto_string(std::pair<int, int>* draw_ptrs_out,
|
||||
GLsizei* counts_out,
|
||||
void** index_offsets_out,
|
||||
const std::vector<tfrag3::StripDraw>& draws,
|
||||
const std::vector<u8>& vis_data,
|
||||
const std::vector<u8>& proto_vis_data);
|
||||
|
||||
u32 make_index_list_from_vis_and_proto_string(std::pair<int, int>* group_out,
|
||||
u32* idx_out,
|
||||
const std::vector<tfrag3::StripDraw>& draws,
|
||||
const std::vector<u8>& vis_data,
|
||||
const std::vector<u8>& proto_vis_data,
|
||||
const u32* idx_in,
|
||||
u32* num_tris_out);
|
||||
@@ -415,61 +415,63 @@ void Loader::update(TexturePool& texture_pool) {
|
||||
Timer unload_timer;
|
||||
if ((int)m_loaded_tfrag3_levels.size() >= m_max_levels) {
|
||||
auto to_unload = get_most_unloadable_level();
|
||||
auto& lev = m_loaded_tfrag3_levels.at(*to_unload);
|
||||
std::unique_lock<std::mutex> lk(texture_pool.mutex());
|
||||
fmt::print("------------------------- PC unloading {}\n", *to_unload);
|
||||
for (size_t i = 0; i < lev->level->textures.size(); i++) {
|
||||
auto& tex = lev->level->textures[i];
|
||||
if (tex.load_to_pool) {
|
||||
texture_pool.unload_texture(PcTextureId::from_combo_id(tex.combo_id),
|
||||
lev->textures.at(i));
|
||||
if (to_unload) {
|
||||
auto& lev = m_loaded_tfrag3_levels.at(*to_unload);
|
||||
std::unique_lock<std::mutex> lk(texture_pool.mutex());
|
||||
fmt::print("------------------------- PC unloading {}\n", *to_unload);
|
||||
for (size_t i = 0; i < lev->level->textures.size(); i++) {
|
||||
auto& tex = lev->level->textures[i];
|
||||
if (tex.load_to_pool) {
|
||||
texture_pool.unload_texture(PcTextureId::from_combo_id(tex.combo_id),
|
||||
lev->textures.at(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
lk.unlock();
|
||||
for (auto tex : lev->textures) {
|
||||
if (EXTRA_TEX_DEBUG) {
|
||||
for (auto& slot : texture_pool.all_textures()) {
|
||||
if (slot.source) {
|
||||
ASSERT(slot.gpu_texture != tex);
|
||||
} else {
|
||||
ASSERT(slot.gpu_texture != tex);
|
||||
lk.unlock();
|
||||
for (auto tex : lev->textures) {
|
||||
if (EXTRA_TEX_DEBUG) {
|
||||
for (auto& slot : texture_pool.all_textures()) {
|
||||
if (slot.source) {
|
||||
ASSERT(slot.gpu_texture != tex);
|
||||
} else {
|
||||
ASSERT(slot.gpu_texture != tex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, tex);
|
||||
glDeleteTextures(1, &tex);
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, tex);
|
||||
glDeleteTextures(1, &tex);
|
||||
}
|
||||
|
||||
for (auto& tie_geo : lev->tie_data) {
|
||||
for (auto& tie_tree : tie_geo) {
|
||||
glDeleteBuffers(1, &tie_tree.vertex_buffer);
|
||||
if (tie_tree.has_wind) {
|
||||
glDeleteBuffers(1, &tie_tree.wind_indices);
|
||||
for (auto& tie_geo : lev->tie_data) {
|
||||
for (auto& tie_tree : tie_geo) {
|
||||
glDeleteBuffers(1, &tie_tree.vertex_buffer);
|
||||
if (tie_tree.has_wind) {
|
||||
glDeleteBuffers(1, &tie_tree.wind_indices);
|
||||
}
|
||||
glDeleteBuffers(1, &tie_tree.index_buffer);
|
||||
}
|
||||
glDeleteBuffers(1, &tie_tree.index_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& tfrag_geo : lev->tfrag_vertex_data) {
|
||||
for (auto& tfrag_buff : tfrag_geo) {
|
||||
glDeleteBuffers(1, &tfrag_buff);
|
||||
for (auto& tfrag_geo : lev->tfrag_vertex_data) {
|
||||
for (auto& tfrag_buff : tfrag_geo) {
|
||||
glDeleteBuffers(1, &tfrag_buff);
|
||||
}
|
||||
}
|
||||
|
||||
glDeleteBuffers(1, &lev->collide_vertices);
|
||||
glDeleteBuffers(1, &lev->merc_vertices);
|
||||
glDeleteBuffers(1, &lev->merc_indices);
|
||||
|
||||
for (auto& model : lev->level->merc_data.models) {
|
||||
auto& mercs = m_all_merc_models.at(model.name);
|
||||
MercRef ref{&model, lev->load_id};
|
||||
auto it = std::find(mercs.begin(), mercs.end(), ref);
|
||||
ASSERT_MSG(it != mercs.end(), fmt::format("missing merc: {}\n", model.name));
|
||||
mercs.erase(it);
|
||||
}
|
||||
|
||||
m_loaded_tfrag3_levels.erase(*to_unload);
|
||||
}
|
||||
|
||||
glDeleteBuffers(1, &lev->collide_vertices);
|
||||
glDeleteBuffers(1, &lev->merc_vertices);
|
||||
glDeleteBuffers(1, &lev->merc_indices);
|
||||
|
||||
for (auto& model : lev->level->merc_data.models) {
|
||||
auto& mercs = m_all_merc_models.at(model.name);
|
||||
MercRef ref{&model, lev->load_id};
|
||||
auto it = std::find(mercs.begin(), mercs.end(), ref);
|
||||
ASSERT_MSG(it != mercs.end(), fmt::format("missing merc: {}\n", model.name));
|
||||
mercs.erase(it);
|
||||
}
|
||||
|
||||
m_loaded_tfrag3_levels.erase(*to_unload);
|
||||
}
|
||||
|
||||
if (unload_timer.getMs() > 5.f) {
|
||||
|
||||
@@ -515,6 +515,7 @@ s32 format_impl_jak2(uint64_t* args) {
|
||||
|
||||
default:
|
||||
MsgErr("format: unknown code 0x%02x\n", format_ptr[1]);
|
||||
MsgErr("input was %s\n", format_cstring);
|
||||
ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -58,6 +58,58 @@
|
||||
;; definition for function draw-inline-array-prototype-tie-asm
|
||||
;; ERROR: function was not converted to expressions. Cannot decompile.
|
||||
|
||||
(defun pc-add-tie-vis-mask ((lev level) (dma-buf dma-buffer))
|
||||
"Add data so Tie3.cpp can hide 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-tie)
|
||||
(let* ((tie-tree (the drawable-tree-instance-tie tree))
|
||||
(protos (-> tie-tree prototypes prototype-array-tie))
|
||||
)
|
||||
(dotimes (i (-> protos length))
|
||||
(let ((proto (-> protos array-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
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defun instance-tie-patch-buckets ((arg0 dma-buffer) (arg1 level))
|
||||
; (when (logtest? (-> *display* vu1-enable-user) (vu1-renderer-mask tie))
|
||||
; (when (nonzero? (-> *prototype-tie-work* scissor-count))
|
||||
@@ -167,6 +219,7 @@
|
||||
; )
|
||||
; (&+! (-> v1-42 base) 16)
|
||||
(add-pc-tfrag3-data v1-42 arg1)
|
||||
(pc-add-tie-vis-mask arg1 v1-42)
|
||||
(let ((a3-16 (-> v1-42 base)))
|
||||
(let ((a0-20 (the-as dma-packet (-> v1-42 base))))
|
||||
(set! (-> a0-20 dma) (new 'static 'dma-tag :id (dma-tag-id next)))
|
||||
|
||||
@@ -1117,7 +1117,7 @@
|
||||
(else
|
||||
(format
|
||||
0
|
||||
"ERROR: <asg> ~A in spool anim loop for ~A ~D, but not loaded.~"
|
||||
"ERROR: <asg> ~A in spool anim loop for ~A ~D, but not loaded.~%" ;; fixed missing %.
|
||||
self
|
||||
(-> gp-0 anim name)
|
||||
(-> gp-0 part)
|
||||
|
||||
@@ -556,12 +556,12 @@ void extract(const Input& in,
|
||||
auto& grp = draw.vis_groups.emplace_back();
|
||||
grp.num_inds += prim_indices.size();
|
||||
grp.num_tris += draw.num_triangles;
|
||||
grp.vis_idx_in_pc_bvh = UINT32_MAX;
|
||||
grp.vis_idx_in_pc_bvh = UINT16_MAX;
|
||||
} else {
|
||||
auto& grp = draw.vis_groups.back();
|
||||
grp.num_inds += prim_indices.size();
|
||||
grp.num_tris += draw.num_triangles;
|
||||
grp.vis_idx_in_pc_bvh = UINT32_MAX;
|
||||
grp.vis_idx_in_pc_bvh = UINT16_MAX;
|
||||
}
|
||||
|
||||
draw.plain_indices.insert(draw.plain_indices.end(), prim_indices.begin(),
|
||||
|
||||
Reference in New Issue
Block a user