mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 00:57:44 -04:00
[jak2] misc fixes to renderers (#2488)
Fixes decal on tfrag: ![image](https://user-images.githubusercontent.com/48171810/232174352-11153941-e1f9-4472-becb-f266c2a309e5.png) Sets up jak 2 alpha shrub test settings. They are still too dark, but there's no longer incorrect alpha test: ![image](https://user-images.githubusercontent.com/48171810/232174590-f9caa6c5-f190-4c78-b720-5f4055490d47.png) Fix decal on shrub, a feature used in exactly one place in jak 1: ![image](https://user-images.githubusercontent.com/48171810/232174614-8ea65ca5-a183-45f7-ae79-6bf06a937007.png) Fixed issue with u16 overflow in castle on the alpha channel, causing flickering. It barely overflowed, which made me suspicious that we had some error somewhere. But I think that there code is robust against overflows.
This commit is contained in:
parent
ba12d804f7
commit
c7f2a23abf
|
@ -73,7 +73,7 @@ struct MemoryUsageTracker {
|
|||
void add(MemoryUsageCategory category, u32 size_bytes) { data[category] += size_bytes; }
|
||||
};
|
||||
|
||||
constexpr int TFRAG3_VERSION = 33;
|
||||
constexpr int TFRAG3_VERSION = 34;
|
||||
|
||||
// These vertices should be uploaded to the GPU at load time and don't change
|
||||
struct PreloadedVertex {
|
||||
|
|
|
@ -197,7 +197,7 @@ std::vector<level_tools::TextureRemap> extract_bsp_from_level(const ObjectFileDB
|
|||
dynamic_cast<level_tools::shrub_types::DrawableTreeInstanceShrub*>(draw_tree.get());
|
||||
ASSERT(as_shrub_tree);
|
||||
extract_shrub(as_shrub_tree, fmt::format("{}-{}-shrub", dgo_name, i++),
|
||||
bsp_header.texture_remap_table, tex_db, {}, level_data, false);
|
||||
bsp_header.texture_remap_table, tex_db, {}, level_data, false, db.version());
|
||||
} else if (draw_tree->my_type() == "drawable-tree-collide-fragment" && extract_collision) {
|
||||
auto as_collide_frags =
|
||||
dynamic_cast<level_tools::DrawableTreeCollideFragment*>(draw_tree.get());
|
||||
|
|
|
@ -142,7 +142,8 @@ u32 remap_texture(u32 original, const std::vector<level_tools::TextureRemap>& ma
|
|||
DrawSettings adgif_to_draw_mode(const AdGifData& ad,
|
||||
const TextureDB& tdb,
|
||||
const std::vector<level_tools::TextureRemap>& map,
|
||||
int count) {
|
||||
int count,
|
||||
bool alpha_tpage_flag) {
|
||||
// initialize draw mode
|
||||
DrawMode current_mode;
|
||||
current_mode.set_at(true);
|
||||
|
@ -155,13 +156,25 @@ DrawSettings adgif_to_draw_mode(const AdGifData& ad,
|
|||
current_mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_SRC_SRC_SRC);
|
||||
current_mode.enable_fog();
|
||||
|
||||
if (alpha_tpage_flag) {
|
||||
current_mode.set_alpha_test(DrawMode::AlphaTest::NEVER);
|
||||
current_mode.set_aref(0);
|
||||
current_mode.set_alpha_fail(GsTest::AlphaFail::FB_ONLY);
|
||||
}
|
||||
|
||||
// ADGIF 0
|
||||
bool weird = (u8)ad.tex0_addr != (u32)GsRegisterAddress::TEX0_1;
|
||||
if (weird) {
|
||||
lg::info("---------------- WEIRD: 0x{:x}", ad.tex0_addr);
|
||||
lg::info("i have {} verts", count);
|
||||
} else {
|
||||
ASSERT(ad.tex0_data == 0 || ad.tex0_data == 0x800000000); // note: decal?? todo
|
||||
if (ad.tex0_data == 0) {
|
||||
current_mode.set_decal(false);
|
||||
} else if (ad.tex0_data == 0x8'0000'0000) {
|
||||
current_mode.set_decal(true);
|
||||
} else {
|
||||
ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
// tw/th
|
||||
|
@ -241,7 +254,8 @@ DrawSettings adgif_to_draw_mode(const AdGifData& ad,
|
|||
|
||||
ShrubProtoInfo extract_proto(const shrub_types::PrototypeBucketShrub& proto,
|
||||
const TextureDB& tdb,
|
||||
const std::vector<level_tools::TextureRemap>& map) {
|
||||
const std::vector<level_tools::TextureRemap>& map,
|
||||
GameVersion version) {
|
||||
ShrubProtoInfo result;
|
||||
for (int frag_idx = 0; frag_idx < proto.generic_geom.length; frag_idx++) {
|
||||
auto& frag_out = result.frags.emplace_back();
|
||||
|
@ -287,7 +301,11 @@ ShrubProtoInfo extract_proto(const shrub_types::PrototypeBucketShrub& proto,
|
|||
ASSERT(3 * (vert_idx + draw.start_vtx_idx) + 3 <= frag.col.size());
|
||||
}
|
||||
|
||||
draw.settings = adgif_to_draw_mode(ag, tdb, map, count);
|
||||
bool alpha_tpage_flag = false;
|
||||
if (version > GameVersion::Jak1) {
|
||||
alpha_tpage_flag = proto.flags & 0x4; // tpage-alpha
|
||||
}
|
||||
draw.settings = adgif_to_draw_mode(ag, tdb, map, count, alpha_tpage_flag);
|
||||
}
|
||||
|
||||
ASSERT(frag.vtx_cnt * 3 * sizeof(u16) <= frag.vtx.size());
|
||||
|
@ -550,12 +568,13 @@ void extract_shrub(const shrub_types::DrawableTreeInstanceShrub* tree,
|
|||
const TextureDB& tex_db,
|
||||
const std::vector<std::pair<int, int>>& /*expected_missing_textures*/,
|
||||
tfrag3::Level& out,
|
||||
bool dump_level) {
|
||||
bool dump_level,
|
||||
GameVersion version) {
|
||||
auto& tree_out = out.shrub_trees.emplace_back();
|
||||
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));
|
||||
proto_info.push_back(extract_proto(proto, tex_db, map, version));
|
||||
}
|
||||
|
||||
for (auto& arr : tree->discovered_arrays) {
|
||||
|
|
|
@ -24,6 +24,7 @@ void extract_shrub(const level_tools::shrub_types::DrawableTreeInstanceShrub* tr
|
|||
const TextureDB& tex_db,
|
||||
const std::vector<std::pair<int, int>>& expected_missing_textures,
|
||||
tfrag3::Level& out,
|
||||
bool dump_level);
|
||||
bool dump_level,
|
||||
GameVersion version);
|
||||
|
||||
} // namespace decompiler
|
||||
|
|
|
@ -1911,7 +1911,13 @@ void process_draw_mode(std::vector<TFragDraw>& all_draws,
|
|||
update_mode_from_test1(val, mode);
|
||||
break;
|
||||
case GsRegisterAddress::TEX0_1:
|
||||
// ASSERT(val == 0); HACK jak 2 sets this.
|
||||
ASSERT(val == 0 || val == 0x8'0000'0000);
|
||||
if (val == 0x8'0000'0000) {
|
||||
mode.set_decal(true);
|
||||
} else {
|
||||
mode.set_decal(false);
|
||||
}
|
||||
mode.set_tcc(false);
|
||||
break;
|
||||
case GsRegisterAddress::TEX1_1:
|
||||
ASSERT(val == 0x120); // some flag
|
||||
|
|
|
@ -34,6 +34,10 @@ SkyBlendHandler::SkyBlendHandler(const std::string& name,
|
|||
true,
|
||||
level_id) {}
|
||||
|
||||
void SkyBlendHandler::init_shaders(ShaderLibrary& shaders) {
|
||||
m_tfrag_renderer.init_shaders(shaders);
|
||||
}
|
||||
|
||||
void SkyBlendHandler::handle_sky_copies(DmaFollower& dma,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof) {
|
||||
|
|
|
@ -19,6 +19,7 @@ class SkyBlendHandler : public BucketRenderer {
|
|||
std::shared_ptr<SkyBlendCPU> shared_cpu_blender);
|
||||
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
|
||||
void draw_debug_window() override;
|
||||
void init_shaders(ShaderLibrary& shaders) override;
|
||||
|
||||
private:
|
||||
void handle_sky_copies(DmaFollower& dma,
|
||||
|
|
|
@ -10,6 +10,10 @@ Shrub::~Shrub() {
|
|||
discard_tree_cache();
|
||||
}
|
||||
|
||||
void Shrub::init_shaders(ShaderLibrary& shaders) {
|
||||
m_uniforms.decal = glGetUniformLocation(shaders[ShaderId::SHRUB].id(), "decal");
|
||||
}
|
||||
|
||||
void Shrub::render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) {
|
||||
if (!m_enabled) {
|
||||
while (dma.current_tag_offset() != render_state->next_bucket) {
|
||||
|
@ -298,6 +302,8 @@ void Shrub::render_tree(int idx,
|
|||
last_texture = draw.tree_tex_id;
|
||||
}
|
||||
|
||||
glUniform1i(m_uniforms.decal, draw.mode.get_decal() ? 1 : 0);
|
||||
|
||||
auto double_draw = setup_tfrag_shader(render_state, draw.mode, ShaderId::SHRUB);
|
||||
|
||||
prof.add_draw_call();
|
||||
|
|
|
@ -13,6 +13,8 @@ class Shrub : public BucketRenderer {
|
|||
public:
|
||||
Shrub(const std::string& name, int my_id);
|
||||
~Shrub();
|
||||
void init_shaders(ShaderLibrary& shaders) override;
|
||||
|
||||
bool setup_for_level(const std::string& level, SharedRenderState* render_state);
|
||||
void render_all_trees(const TfragRenderSettings& settings,
|
||||
SharedRenderState* render_state,
|
||||
|
@ -53,6 +55,10 @@ class Shrub : public BucketRenderer {
|
|||
} perf;
|
||||
};
|
||||
|
||||
struct {
|
||||
GLuint decal;
|
||||
} m_uniforms;
|
||||
|
||||
std::vector<Tree> m_trees;
|
||||
std::string m_level_name;
|
||||
const std::vector<GLuint>* m_textures;
|
||||
|
|
|
@ -145,6 +145,10 @@ void TFragment::draw_debug_window() {
|
|||
m_tfrag3.draw_debug_window();
|
||||
}
|
||||
|
||||
void TFragment::init_shaders(ShaderLibrary& shaders) {
|
||||
m_tfrag3.init_shaders(shaders);
|
||||
}
|
||||
|
||||
void TFragment::handle_initialization(DmaFollower& dma) {
|
||||
// Set up test (different between different renderers)
|
||||
auto setup_test = dma.read_and_advance();
|
||||
|
|
|
@ -43,6 +43,7 @@ class TFragment : public BucketRenderer {
|
|||
int level_id);
|
||||
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
|
||||
void draw_debug_window() override;
|
||||
void init_shaders(ShaderLibrary& shaders) override;
|
||||
|
||||
private:
|
||||
void handle_initialization(DmaFollower& dma);
|
||||
|
|
|
@ -40,6 +40,10 @@ Tfrag3::~Tfrag3() {
|
|||
glDeleteVertexArrays(1, &m_debug_vao);
|
||||
}
|
||||
|
||||
void Tfrag3::init_shaders(ShaderLibrary& shaders) {
|
||||
m_uniforms.decal = glGetUniformLocation(shaders[ShaderId::TFRAG3].id(), "decal");
|
||||
}
|
||||
|
||||
void Tfrag3::update_load(const std::vector<tfrag3::TFragmentTreeKind>& tree_kinds,
|
||||
const LevelData* loader_data) {
|
||||
const auto* lev_data = loader_data->level.get();
|
||||
|
@ -188,15 +192,25 @@ void Tfrag3::render_tree(int geom,
|
|||
return;
|
||||
}
|
||||
auto& tree = m_cached_trees.at(geom).at(settings.tree_idx);
|
||||
const auto* itimes = settings.itimes;
|
||||
|
||||
if (tree.freeze_itimes) {
|
||||
itimes = tree.itimes_debug;
|
||||
} else {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
tree.itimes_debug[i] = settings.itimes[i];
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(tree.kind != tfrag3::TFragmentTreeKind::INVALID);
|
||||
|
||||
if (m_color_result.size() < tree.colors->size()) {
|
||||
m_color_result.resize(tree.colors->size());
|
||||
}
|
||||
if (m_use_fast_time_of_day) {
|
||||
interp_time_of_day_fast(settings.itimes, tree.tod_cache, m_color_result.data());
|
||||
interp_time_of_day_fast(itimes, tree.tod_cache, m_color_result.data());
|
||||
} else {
|
||||
interp_time_of_day_slow(settings.itimes, *tree.colors, m_color_result.data());
|
||||
interp_time_of_day_slow(itimes, *tree.colors, m_color_result.data());
|
||||
}
|
||||
glActiveTexture(GL_TEXTURE10);
|
||||
glBindTexture(GL_TEXTURE_1D, tree.time_of_day_texture);
|
||||
|
@ -249,6 +263,7 @@ void Tfrag3::render_tree(int geom,
|
|||
ASSERT(m_textures);
|
||||
glBindTexture(GL_TEXTURE_2D, m_textures->at(draw.tree_tex_id));
|
||||
auto double_draw = setup_tfrag_shader(render_state, draw.mode, ShaderId::TFRAG3);
|
||||
glUniform1i(m_uniforms.decal, draw.mode.get_decal() ? 1 : 0);
|
||||
tree.tris_this_frame += draw.num_triangles;
|
||||
tree.draws_this_frame++;
|
||||
|
||||
|
@ -347,7 +362,12 @@ void Tfrag3::draw_debug_window() {
|
|||
ImGui::Checkbox("cull debug (slow)", &tree.cull_debug);
|
||||
ImGui::PopID();
|
||||
if (tree.rendered_this_frame) {
|
||||
ImGui::Checkbox("freeze itimes", &tree.freeze_itimes);
|
||||
ImGui::Text(" tris: %d draws: %d", tree.tris_this_frame, tree.draws_this_frame);
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ImGui::Text(" itimes[%d] 0x%x 0x%x 0x%x 0x%x", j, tree.itimes_debug[j][0],
|
||||
tree.itimes_debug[j][1], tree.itimes_debug[j][2], tree.itimes_debug[j][3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ class Tfrag3 {
|
|||
Tfrag3();
|
||||
~Tfrag3();
|
||||
|
||||
void init_shaders(ShaderLibrary& shaders);
|
||||
void render_all_trees(int geom,
|
||||
const TfragRenderSettings& settings,
|
||||
SharedRenderState* render_state,
|
||||
|
@ -78,8 +79,15 @@ class Tfrag3 {
|
|||
bool allowed = true;
|
||||
bool forced = false;
|
||||
bool cull_debug = false;
|
||||
|
||||
bool freeze_itimes = false;
|
||||
math::Vector<s32, 4> itimes_debug[4];
|
||||
};
|
||||
|
||||
struct {
|
||||
GLuint decal;
|
||||
} m_uniforms;
|
||||
|
||||
struct Cache {
|
||||
std::vector<u8> vis_temp;
|
||||
std::vector<std::pair<int, int>> draw_idx_temp;
|
||||
|
|
|
@ -218,6 +218,7 @@ void interp_time_of_day_slow(const math::Vector<s32, 4> itimes[4],
|
|||
}
|
||||
// result += in[color].rgba[component].cast<float>() * weights[component];
|
||||
}
|
||||
|
||||
result[0] = std::min(result[0], 255.f);
|
||||
result[1] = std::min(result[1], 255.f);
|
||||
result[2] = std::min(result[2], 255.f);
|
||||
|
@ -349,15 +350,15 @@ void interp_time_of_day_fast(const math::Vector<s32, 4> itimes[4],
|
|||
color7 = _mm_mullo_epi16(color7, weights7);
|
||||
|
||||
// add. This order minimizes dependencies.
|
||||
color0 = _mm_add_epi16(color0, color1);
|
||||
color2 = _mm_add_epi16(color2, color3);
|
||||
color4 = _mm_add_epi16(color4, color5);
|
||||
color6 = _mm_add_epi16(color6, color7);
|
||||
color0 = _mm_adds_epi16(color0, color1);
|
||||
color2 = _mm_adds_epi16(color2, color3);
|
||||
color4 = _mm_adds_epi16(color4, color5);
|
||||
color6 = _mm_adds_epi16(color6, color7);
|
||||
|
||||
color0 = _mm_add_epi16(color0, color2);
|
||||
color4 = _mm_add_epi16(color4, color6);
|
||||
color0 = _mm_adds_epi16(color0, color2);
|
||||
color4 = _mm_adds_epi16(color4, color6);
|
||||
|
||||
color0 = _mm_add_epi16(color0, color4);
|
||||
color0 = _mm_adds_epi16(color0, color4);
|
||||
|
||||
// divide, because we multiplied our weights by 2^7.
|
||||
color0 = _mm_srli_epi16(color0, 6);
|
||||
|
@ -404,15 +405,15 @@ void interp_time_of_day_fast(const math::Vector<s32, 4> itimes[4],
|
|||
color7 = _mm_mullo_epi16(color7, weights7);
|
||||
|
||||
// add. This order minimizes dependencies.
|
||||
color0 = _mm_add_epi16(color0, color1);
|
||||
color2 = _mm_add_epi16(color2, color3);
|
||||
color4 = _mm_add_epi16(color4, color5);
|
||||
color6 = _mm_add_epi16(color6, color7);
|
||||
color0 = _mm_adds_epi16(color0, color1);
|
||||
color2 = _mm_adds_epi16(color2, color3);
|
||||
color4 = _mm_adds_epi16(color4, color5);
|
||||
color6 = _mm_adds_epi16(color6, color7);
|
||||
|
||||
color0 = _mm_add_epi16(color0, color2);
|
||||
color4 = _mm_add_epi16(color4, color6);
|
||||
color0 = _mm_adds_epi16(color0, color2);
|
||||
color4 = _mm_adds_epi16(color4, color6);
|
||||
|
||||
color0 = _mm_add_epi16(color0, color4);
|
||||
color0 = _mm_adds_epi16(color0, color4);
|
||||
|
||||
// divide, because we multiplied our weights by 2^7.
|
||||
color0 = _mm_srli_epi16(color0, 6);
|
||||
|
|
|
@ -10,6 +10,7 @@ uniform mat4 camera;
|
|||
uniform float fog_constant;
|
||||
uniform float fog_min;
|
||||
uniform float fog_max;
|
||||
uniform int decal;
|
||||
layout (binding = 10) uniform sampler1D tex_T1; // note, sampled in the vertex shader on purpose.
|
||||
|
||||
out vec4 fragment_color;
|
||||
|
@ -72,6 +73,10 @@ void main() {
|
|||
fragment_color *= tod_color * 4;
|
||||
fragment_color.a *= 2;
|
||||
|
||||
if (decal == 1) {
|
||||
fragment_color.xyz = vec3(1.0, 1.0, 1.0);
|
||||
}
|
||||
|
||||
tex_coord = tex_coord_in;
|
||||
tex_coord.xy /= 4096;
|
||||
}
|
||||
|
|
|
@ -64,14 +64,15 @@ void main() {
|
|||
transformed.y *= SCISSOR_ADJUST * HEIGHT_SCALE;
|
||||
gl_Position = transformed;
|
||||
|
||||
// time of day lookup
|
||||
fragment_color = texelFetch(tex_T1, time_of_day_index, 0);
|
||||
// color adjustment
|
||||
fragment_color *= 2;
|
||||
fragment_color.a *= 2;
|
||||
|
||||
if (decal == 1) {
|
||||
fragment_color = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
} else {
|
||||
// time of day lookup
|
||||
fragment_color = texelFetch(tex_T1, time_of_day_index, 0);
|
||||
// color adjustment
|
||||
fragment_color *= 2;
|
||||
fragment_color.a *= 2;
|
||||
// tfrag/tie always use TCC=RGB, so even with decal, alpha comes from fragment.
|
||||
fragment_color.xyz = vec3(1.0, 1.0, 1.0);
|
||||
}
|
||||
|
||||
// fog hack
|
||||
|
|
Loading…
Reference in a new issue