[jak3] Support texture anim in TIE (#3734)

Support animated textures in TIE. Apparently this is also used in jak 2
for robotank and we never noticed??


https://github.com/user-attachments/assets/bfa45a1a-4a96-4b25-817a-4327afcc7c98

Co-authored-by: water111 <awaterford1111445@gmail.com>
This commit is contained in:
water111
2024-10-26 15:47:34 -04:00
committed by GitHub
parent 510b23163f
commit 5bc61c5854
5 changed files with 53 additions and 24 deletions
+2 -2
View File
@@ -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 = 42;
constexpr int TFRAG3_VERSION = 43;
enum MemoryUsageCategory {
TEXTURE,
@@ -241,7 +241,7 @@ struct ShrubDraw {
struct InstancedStripDraw {
DrawMode mode; // the OpenGL draw settings.
u32 tree_tex_id = 0; // the texture that should be bound for the draw
s32 tree_tex_id = 0; // the texture that should be bound for the draw
// the list of vertices in the draw. This includes the restart code of UINT32_MAX that OpenGL
// will use to start a new strip.
+16 -10
View File
@@ -2339,7 +2339,7 @@ TieCategoryInfo get_jak1_tie_category(u32 flags) {
return result;
}
u32 get_or_add_texture(u32 combo_tex, tfrag3::Level& lev, const TextureDB& tdb) {
s32 get_or_add_texture(u32 combo_tex, tfrag3::Level& lev, const TextureDB& tdb) {
if (combo_tex == 0) {
// untextured
combo_tex = (((u32)TextureDB::kPlaceholderWhiteTexturePage) << 16) |
@@ -2348,7 +2348,7 @@ u32 get_or_add_texture(u32 combo_tex, tfrag3::Level& lev, const TextureDB& tdb)
// try looking it up in the existing textures that we have in the C++ renderer data.
// (this is shared with tfrag)
u32 idx_in_lev_data = UINT32_MAX;
s32 idx_in_lev_data = INT32_MAX;
for (u32 i = 0; i < lev.textures.size(); i++) {
if (lev.textures[i].combo_id == combo_tex) {
idx_in_lev_data = i;
@@ -2356,7 +2356,7 @@ u32 get_or_add_texture(u32 combo_tex, tfrag3::Level& lev, const TextureDB& tdb)
}
}
if (idx_in_lev_data == UINT32_MAX) {
if (idx_in_lev_data == INT32_MAX) {
// didn't find it, have to add a new one texture.
auto tex_it = tdb.textures.find(combo_tex);
if (tex_it == tdb.textures.end()) {
@@ -2378,14 +2378,20 @@ u32 get_or_add_texture(u32 combo_tex, tfrag3::Level& lev, const TextureDB& tdb)
new_tex.debug_tpage_name = tdb.tpage_names.at(tex_it->second.page);
new_tex.data = tex_it->second.rgba_bytes;
}
const auto& level_tex = lev.textures.at(idx_in_lev_data);
const auto& it = tdb.animated_tex_output_to_anim_slot.find(level_tex.debug_name);
if (it != tdb.animated_tex_output_to_anim_slot.end()) {
// lg::warn("TIE animated texture: {}", level_tex.debug_name);
return -int(it->second) - 1;
}
return idx_in_lev_data;
}
void handle_wind_draw_for_strip(
tfrag3::TieTree& tree,
std::unordered_map<u32, std::vector<u32>>& wind_draws_by_tex,
std::unordered_map<s32, std::vector<u32>>& wind_draws_by_tex,
const std::vector<std::vector<std::pair<int, int>>>& packed_vert_indices,
u32 idx_in_lev_data,
s32 idx_in_lev_data,
DrawMode mode,
const TieStrip& strip,
const TieInstanceInfo& inst,
@@ -2452,7 +2458,7 @@ void handle_wind_draw_for_strip(
}
void handle_draw_for_strip(tfrag3::TieTree& tree,
std::unordered_map<u32, std::vector<u32>>& static_draws_by_tex,
std::unordered_map<s32, std::vector<u32>>& static_draws_by_tex,
std::vector<tfrag3::StripDraw>& category_draws,
const std::vector<std::vector<std::pair<int, int>>>& packed_vert_indices,
DrawMode mode,
@@ -2542,8 +2548,8 @@ void add_vertices_and_static_draw(tfrag3::TieTree& tree,
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;
std::unordered_map<s32, std::vector<u32>> static_draws_by_tex;
std::unordered_map<s32, std::vector<u32>> wind_draws_by_tex;
std::array<std::vector<tfrag3::StripDraw>, tfrag3::kNumTieCategories> draws_by_category;
@@ -2632,7 +2638,7 @@ void add_vertices_and_static_draw(tfrag3::TieTree& tree,
for (size_t strip_idx = 0; strip_idx < frag.strips.size(); strip_idx++) {
auto& strip = frag.strips[strip_idx];
u32 idx_in_lev_data = get_or_add_texture(strip.adgif.combo_tex, lev, tdb);
s32 idx_in_lev_data = get_or_add_texture(strip.adgif.combo_tex, lev, tdb);
// determine the draw mode
DrawMode mode = process_draw_mode(strip.adgif, frag.prog_info.misc_x == 0,
frag.has_magic_tex0_bit, version, info.category);
@@ -2649,7 +2655,7 @@ void add_vertices_and_static_draw(tfrag3::TieTree& tree,
draws_by_category.at((int)info.category), packed_vert_indices,
mode, idx_in_lev_data, strip, inst, ifrag, proto_idx, frag_idx,
strip_idx, matrix_idx);
u32 envmap_tex_idx =
s32 envmap_tex_idx =
get_or_add_texture(proto.envmap_adgif.value().combo_tex, lev, tdb);
// second pass envmap draw mode, in envmap bucket, envmap-specific draw list
@@ -168,7 +168,8 @@ void OpenGLRenderer::init_bucket_renderers_jak3() {
std::vector{tfrag3::TFragmentTreeKind::NORMAL}, false, i, anim_slot_array());
Tie3* tie = init_bucket_renderer<Tie3>(
fmt::format("tie-l{}-tfrag", i), BucketCategory::TIE,
GET_BUCKET_ID_FOR_LIST(BucketId::TIE_L0_TFRAG, BucketId::TIE_L1_TFRAG, i), i);
GET_BUCKET_ID_FOR_LIST(BucketId::TIE_L0_TFRAG, BucketId::TIE_L1_TFRAG, i), i,
anim_slot_array());
init_bucket_renderer<Tie3AnotherCategory>(
fmt::format("etie-l{}-tfrag", i), BucketCategory::TIE,
GET_BUCKET_ID_FOR_LIST(BucketId::ETIE_L0_TFRAG, BucketId::ETIE_L1_TFRAG, i), tie,
@@ -431,7 +432,8 @@ void OpenGLRenderer::init_bucket_renderers_jak2() {
std::vector{tfrag3::TFragmentTreeKind::NORMAL}, false, i, anim_slot_array());
Tie3* tie = init_bucket_renderer<Tie3>(
fmt::format("tie-l{}-tfrag", i), BucketCategory::TIE,
GET_BUCKET_ID_FOR_LIST(BucketId::TIE_L0_TFRAG, BucketId::TIE_L1_TFRAG, i), i);
GET_BUCKET_ID_FOR_LIST(BucketId::TIE_L0_TFRAG, BucketId::TIE_L1_TFRAG, i), i,
anim_slot_array());
init_bucket_renderer<Tie3AnotherCategory>(
fmt::format("etie-l{}-tfrag", i), BucketCategory::TIE,
GET_BUCKET_ID_FOR_LIST(BucketId::ETIE_L0_TFRAG, BucketId::ETIE_L1_TFRAG, i), tie,
@@ -6,8 +6,15 @@
#include "third-party/imgui/imgui.h"
Tie3::Tie3(const std::string& name, int my_id, int level_id, tfrag3::TieCategory category)
: BucketRenderer(name, my_id), m_level_id(level_id), m_default_category(category) {
Tie3::Tie3(const std::string& name,
int my_id,
int level_id,
const std::vector<GLuint>* anim_slot_array,
tfrag3::TieCategory category)
: BucketRenderer(name, my_id),
m_level_id(level_id),
m_default_category(category),
m_anim_slot_array(anim_slot_array) {
// regardless of how many we use some fixed max
// we won't actually interp or upload to gpu the unused ones, but we need a fixed maximum so
// indexing works properly.
@@ -573,8 +580,12 @@ void Tie3::draw_matching_draws_for_tree(int idx,
}
}
if ((int)draw.tree_tex_id != last_texture) {
glBindTexture(GL_TEXTURE_2D, m_textures->at(draw.tree_tex_id));
if (draw.tree_tex_id != last_texture) {
if (draw.tree_tex_id >= 0) {
glBindTexture(GL_TEXTURE_2D, m_textures->at(draw.tree_tex_id));
} else {
glBindTexture(GL_TEXTURE_2D, m_anim_slot_array->at(-(draw.tree_tex_id + 1)));
}
last_texture = draw.tree_tex_id;
}
@@ -665,8 +676,13 @@ void Tie3::envmap_second_pass_draw(const Tree& tree,
}
}
if ((int)draw.tree_tex_id != last_texture) {
glBindTexture(GL_TEXTURE_2D, m_textures->at(draw.tree_tex_id));
if (draw.tree_tex_id != last_texture) {
if (draw.tree_tex_id >= 0) {
glBindTexture(GL_TEXTURE_2D, m_textures->at(draw.tree_tex_id));
} else {
glBindTexture(GL_TEXTURE_2D, m_anim_slot_array->at(-(draw.tree_tex_id + 1)));
}
last_texture = draw.tree_tex_id;
}
@@ -922,8 +938,12 @@ void Tie3::render_tree_wind(int idx,
for (size_t draw_idx = 0; draw_idx < tree.wind_draws->size(); draw_idx++) {
const auto& draw = tree.wind_draws->operator[](draw_idx);
if ((int)draw.tree_tex_id != last_texture) {
glBindTexture(GL_TEXTURE_2D, m_textures->at(draw.tree_tex_id));
if (draw.tree_tex_id != last_texture) {
if (draw.tree_tex_id >= 0) {
glBindTexture(GL_TEXTURE_2D, m_textures->at(draw.tree_tex_id));
} else {
glBindTexture(GL_TEXTURE_2D, m_anim_slot_array->at(-(draw.tree_tex_id + 1)));
}
last_texture = draw.tree_tex_id;
}
auto double_draw = setup_tfrag_shader(render_state, draw.mode, ShaderId::TFRAG3);
@@ -993,7 +1013,7 @@ void Tie3AnotherCategory::render(DmaFollower& dma,
}
Tie3WithEnvmapJak1::Tie3WithEnvmapJak1(const std::string& name, int my_id, int level_id)
: Tie3(name, my_id, level_id, tfrag3::TieCategory::NORMAL) {}
: Tie3(name, my_id, level_id, nullptr, tfrag3::TieCategory::NORMAL) {}
void Tie3WithEnvmapJak1::render(DmaFollower& dma,
SharedRenderState* render_state,
@@ -30,6 +30,7 @@ class Tie3 : public BucketRenderer {
Tie3(const std::string& name,
int my_id,
int level_id,
const std::vector<GLuint>* anim_slot_array,
tfrag3::TieCategory category = tfrag3::TieCategory::NORMAL);
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
void draw_debug_window() override;
@@ -169,7 +170,7 @@ class Tie3 : public BucketRenderer {
} m_uniforms;
EtieUniforms m_etie_uniforms, m_etie_base_uniforms;
const std::vector<GLuint>* m_anim_slot_array;
static_assert(sizeof(WindWork) == 84 * 16);
};