Skip to content

Commit

Permalink
[jak3] Misc texture anim fixes (#3732)
Browse files Browse the repository at this point in the history
- fix issue where animated textures that use the size-override feature,
and aren't being animated would show up as black - fix for black water
in spargus
- fix issue where animated texture uses another animated texture as an
input wouldn't get the animated version.
- fix math mistake in how animated texture rotations are handled. This
could cause textures to not rotate when a positions were rotated, but
textures (st's) weren't.
- fix definition of the ring texture to handle
set-alpha-texture-anim-layer-func



![image](https://github.com/user-attachments/assets/979748b0-7abf-46a5-bf9d-693fb0ef34fb)


![image](https://github.com/user-attachments/assets/3011662c-bfec-4ce9-ad72-8853b3784f77)



https://github.com/user-attachments/assets/0242a59d-62bd-4799-8f6f-2a0aba63649f

Co-authored-by: water111 <[email protected]>
  • Loading branch information
water111 and water111 authored Oct 26, 2024
1 parent cb51bd3 commit 510b231
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 28 deletions.
1 change: 1 addition & 0 deletions game/graphics/opengl_renderer/Shader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ ShaderLibrary::ShaderLibrary(GameVersion version) {
at(ShaderId::GLOW_PROBE_ON_GRID) = {"glow_probe_on_grid", version};
at(ShaderId::HFRAG) = {"hfrag", version};
at(ShaderId::HFRAG_MONTAGE) = {"hfrag_montage", version};
at(ShaderId::PLAIN_TEXTURE) = {"plain_texture", version};

for (auto& shader : m_shaders) {
ASSERT_MSG(shader.okay(), "error compiling shader");
Expand Down
1 change: 1 addition & 0 deletions game/graphics/opengl_renderer/Shader.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ enum class ShaderId {
GLOW_PROBE_ON_GRID = 36,
HFRAG = 37,
HFRAG_MONTAGE = 38,
PLAIN_TEXTURE = 39,
MAX_SHADERS
};

Expand Down
148 changes: 126 additions & 22 deletions game/graphics/opengl_renderer/TextureAnimator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,16 @@
// then it's actually treated as a palette texture, but we don't really do this.
// This breaks the fade-out/thresholding, and likely the colors. But it still looks vaguely like
// clouds.
void debug_save_opengl_texture(const std::string& out, GLuint texture) {
glBindTexture(GL_TEXTURE_2D, texture);
int w, h;
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
lg::print("saving texture with size {} x {}\n", w, h);
std::vector<u8> data(w * h * 4);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, data.data());
file_util::write_rgba_png(out, data.data(), w, h);
}

/*!
* A simple list of preallocated textures by size. If a texture needs to be resized, it's faster
Expand Down Expand Up @@ -262,6 +272,71 @@ void opengl_upload_texture(GLint dest, const void* data, int w, int h) {
glBindTexture(GL_TEXTURE_2D, 0);
}

/*!
* Upload a texture and generate mipmaps. Assumes the usual RGBA format.
* The size of the destination and source texture don't need to match.
*/
void opengl_upload_resize_texture(FramebufferTexturePair& fbt,
const void* data,
const math::Vector2<int>& data_size,
ShaderLibrary& shaders) {
{
FramebufferTexturePairContext ctx(fbt);
GLuint temp_texture = 0;
GLuint vao = 0;
GLuint vertex_buffer = 0;
glGenTextures(1, &temp_texture);
glBindTexture(GL_TEXTURE_2D, temp_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, data_size.x(), data_size.y(), 0, GL_RGBA,
GL_UNSIGNED_INT_8_8_8_8_REV, data);

glGenVertexArrays(1, &vao);
glGenBuffers(1, &vertex_buffer);
glBindVertexArray(vao);

struct Vertex {
float x, y;
};

std::array<Vertex, 4> vertices = {
Vertex{-1, -1},
Vertex{-1, 1},
Vertex{1, -1},
Vertex{1, 1},
};

glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * 4, vertices.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, // location 0 in the shader
2, // 2 floats per vert
GL_FLOAT, // floats
GL_TRUE, // normalized, ignored,
sizeof(Vertex), //
nullptr //
);

auto& shader = shaders[ShaderId::PLAIN_TEXTURE];
shader.activate();
glUniform1i(glGetUniformLocation(shader.id(), "tex_T0"), 0);
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, temp_texture);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vertex_buffer);
glDeleteTextures(1, &temp_texture);
}
glBindTexture(GL_TEXTURE_2D, fbt.texture());
glGenerateMipmap(GL_TEXTURE_2D);
}

/*!
* Utility class to grab CLUTs from the source textures, blend them, and produce a destination RGBA
* texture using the index data in dest.
Expand Down Expand Up @@ -417,7 +492,8 @@ TextureAnimator::TextureAnimator(ShaderLibrary& shaders,
GL_UNSIGNED_INT_8_8_8_8_REV),
m_slime_final_scroll_texture(kFinalSlimeTextureSize,
kFinalSlimeTextureSize,
GL_UNSIGNED_INT_8_8_8_8_REV) {
GL_UNSIGNED_INT_8_8_8_8_REV),
m_shaders(&shaders) {
glGenVertexArrays(1, &m_vao);
glGenBuffers(1, &m_vertex_buffer);
glBindVertexArray(m_vao);
Expand Down Expand Up @@ -522,8 +598,28 @@ TextureAnimator::TextureAnimator(ShaderLibrary& shaders,
default:
ASSERT_NOT_REACHED();
}

setup_sky();

// Patch up references to animated textures
std::map<std::string, u64> name_to_slot;
for (const auto& anim_array : m_fixed_anim_arrays) {
for (const auto& anim : anim_array.anims) {
name_to_slot[anim.def.tex_name] = anim.dest_slot;
}
}

for (auto& anim_array : m_fixed_anim_arrays) {
for (auto& anim : anim_array.anims) {
for (size_t i = 0; i < anim.src_textures.size(); i++) {
const auto& it = name_to_slot.find(anim.def.layers.at(i).tex_name);
if (it != name_to_slot.end()) {
lg::error("Patching ref to {} in {}", it->first, anim.def.tex_name);
anim.src_textures[i].is_anim_slot = true;
anim.src_textures[i].idx = it->second;
}
}
}
}
}

/*!
Expand All @@ -544,6 +640,11 @@ int TextureAnimator::create_fixed_anim_array(const std::vector<FixedAnimDef>& de
if (anim.def.override_size) {
anim.fbt.emplace(anim.def.override_size->x(), anim.def.override_size->y(),
GL_UNSIGNED_INT_8_8_8_8_REV);
// I think there's kind of a bug here - if the game accesses a resized texture before
// the animation is run once, it can end up using the wrong size.
// For PC, we just resize the texture to the new size at startup, which avoids the texture
// changing sizes at runtime.
opengl_upload_resize_texture(*anim.fbt, dtex->data.data(), {dtex->w, dtex->h}, *m_shaders);
} else {
anim.fbt.emplace(dtex->w, dtex->h, GL_UNSIGNED_INT_8_8_8_8_REV);
opengl_upload_texture(anim.fbt->texture(), dtex->data.data(), dtex->w, dtex->h);
Expand All @@ -555,7 +656,10 @@ int TextureAnimator::create_fixed_anim_array(const std::vector<FixedAnimDef>& de
for (const auto& layer : def.layers) {
auto* stex = tex_by_name(m_common_level, layer.tex_name);
GLint gl_texture = m_opengl_texture_pool.allocate(stex->w, stex->h);
anim.src_textures.push_back(gl_texture);
FixedAnimSource src;
src.idx = gl_texture;
src.is_anim_slot = false;
anim.src_textures.push_back(src);
opengl_upload_texture(gl_texture, stex->data.data(), stex->w, stex->h);
}

Expand Down Expand Up @@ -1475,17 +1579,6 @@ PcTextureId TextureAnimator::get_id_for_tbp(TexturePool* pool, u64 tbp, u64 othe
}
}

void debug_save_opengl_texture(const std::string& out, GLuint texture) {
glBindTexture(GL_TEXTURE_2D, texture);
int w, h;
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
lg::print("saving texture with size {} x {}\n", w, h);
std::vector<u8> data(w * h * 4);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, data.data());
file_util::write_rgba_png(out, data.data(), w, h);
}

void TextureAnimator::run_clut_blender_group(DmaTransfer& tf, int idx, u64 frame_idx) {
float f;
ASSERT(tf.size_bytes == 16);
Expand Down Expand Up @@ -2434,23 +2527,26 @@ void TextureAnimator::set_draw_data_from_interpolated(DrawData* result,
math::Vector2f pos_offset(2048.f + (vals.offset.x() * w), 2048.f + (vals.offset.y() * h));
math::Vector2f st_scale = vals.st_scale;
math::Vector2f st_offset = vals.st_offset;
math::Vector2f corners[4] = {math::Vector2f{-0.5, -0.5}, math::Vector2f{0.5, -0.5},
math::Vector2f{-0.5, 0.5}, math::Vector2f{0.5, 0.5}};
const std::array<math::Vector2f, 4> fixed_corners = {
math::Vector2f{-0.5, -0.5}, math::Vector2f{0.5, -0.5}, math::Vector2f{-0.5, 0.5},
math::Vector2f{0.5, 0.5}};
auto pos_corners = fixed_corners;

if (vals.rot) {
const float rotation_radians = 2.f * M_PI * vals.rot / 65536.f;
const float sine = std::sin(rotation_radians);
const float cosine = std::cos(rotation_radians);
math::Vector2f vx(sine, cosine);
math::Vector2f vy(cosine, -sine);
for (auto& corner : corners) {
for (auto& corner : pos_corners) {
corner = vx * corner.x() + vy * corner.y();
}
}
math::Vector2f sts[4];
math::Vector2<u32> poss[4];

for (int i = 0; i < 4; i++) {
poss[i] = ((corners[i].elementwise_multiply(pos_scale) + pos_offset) * 16.f).cast<u32>();
poss[i] = ((pos_corners[i].elementwise_multiply(pos_scale) + pos_offset) * 16.f).cast<u32>();
}

if (vals.st_rot != 0) {
Expand All @@ -2460,12 +2556,12 @@ void TextureAnimator::set_draw_data_from_interpolated(DrawData* result,
math::Vector2f vx(sine, cosine);
math::Vector2f vy(cosine, -sine);
for (int i = 0; i < 4; i++) {
math::Vector2f corner = corners[i].elementwise_multiply(st_scale);
math::Vector2f corner = fixed_corners[i].elementwise_multiply(st_scale);
sts[i] = st_offset + vx * corner.x() + vy * corner.y();
}
} else {
for (int i = 0; i < 4; i++) {
sts[i] = corners[i].elementwise_multiply(st_scale) + st_offset;
sts[i] = fixed_corners[i].elementwise_multiply(st_scale) + st_offset;
}
}

Expand Down Expand Up @@ -2511,7 +2607,6 @@ void TextureAnimator::run_fixed_animation(FixedAnim& anim, float time) {

LayerVals interpolated_values;
DrawData draw_data;

// Loop over layers
for (size_t layer_idx = 0; layer_idx < anim.def.layers.size(); layer_idx++) {
auto& layer_def = anim.def.layers[layer_idx];
Expand All @@ -2521,13 +2616,22 @@ void TextureAnimator::run_fixed_animation(FixedAnim& anim, float time) {
continue;
}

if (layer_def.disable) {
continue;
}

// interpolate
interpolate_layer_values(
(time - layer_def.start_time) / (layer_def.end_time - layer_def.start_time),
&interpolated_values, layer_dyn.start_vals, layer_dyn.end_vals);

// shader setup
set_up_opengl_for_fixed(layer_def, anim.src_textures.at(layer_idx));
const auto& src = anim.src_textures.at(layer_idx);
if (src.is_anim_slot) {
set_up_opengl_for_fixed(layer_def, m_private_output_slots.at(src.idx));
} else {
set_up_opengl_for_fixed(layer_def, src.idx);
}

set_draw_data_from_interpolated(&draw_data, interpolated_values, anim.fbt->width(),
anim.fbt->height());
Expand Down
12 changes: 9 additions & 3 deletions game/graphics/opengl_renderer/TextureAnimator.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ struct FixedLayerDef {
bool clamp_v = false;
bool blend_enable = true;
bool channel_masks[4] = {true, true, true, true};
bool disable = false;
GsAlpha::BlendMode blend_modes[4]; // abcd
u8 blend_fix = 0;

Expand Down Expand Up @@ -208,13 +209,17 @@ struct DynamicLayerData {
LayerVals start_vals, end_vals;
};

struct FixedAnimSource {
u64 idx = 0;
bool is_anim_slot = false;
};

struct FixedAnim {
FixedAnimDef def;
std::vector<DynamicLayerData> dynamic_data;
// GLint dest_texture;
std::optional<FramebufferTexturePair> fbt;
int dest_slot;
std::vector<GLint> src_textures;
std::vector<FixedAnimSource> src_textures;

GpuTexture* pool_gpu_tex = nullptr;
};
Expand Down Expand Up @@ -528,11 +533,12 @@ class TextureAnimator {
GpuTexture* m_slime_scroll_pool_gpu_tex = nullptr;
int m_slime_output_slot = -1;
int m_slime_scroll_output_slot = -1;
ShaderLibrary* m_shaders = nullptr;
};

int output_slot_by_idx(GameVersion version, const std::string& name);
int update_opengl_noise_texture(GLuint texture,
u8* temp,
Vector16ub* random_table,
int dim,
int random_index_in);
int random_index_in);
11 changes: 8 additions & 3 deletions game/graphics/opengl_renderer/TextureAnimatorDefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,14 +199,19 @@ void TextureAnimator::setup_texture_anims_jak3() {
foam.tex_name = "splash-foam";
// :test (new 'static 'gs-test :ate #x1 :afail #x3 :zte #x1 :ztst (gs-ztest always))
foam.set_no_z_write_no_z_test();
foam.channel_masks[3] = false; // no alpha writes.
if (i == 16) {
// this layer is configured, but most of the settings do nothing because it uses
// set-alpha-texture-anim-layer-func
foam.disable = true;
}
// :alpha (new 'static 'gs-alpha :b #x2 :d #x1)
foam.set_clamp();
foam.set_blend_b2_d1();
}
dest2.set_alpha = true;
dest2.set_times({
{0.f, 25.f},
{25.f, 150.f},
{0.f, 25.f}, // 0
{25.f, 150.f}, // 1
{25.f, 50.f},
{50.f, 150.f},
{0.f, 25.f},
Expand Down
9 changes: 9 additions & 0 deletions game/graphics/opengl_renderer/shaders/plain_texture.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#version 410 core

uniform sampler2D tex_T0;
out vec4 color;
in vec2 tex_coord;

void main() {
color = texture(tex_T0, tex_coord);
}
10 changes: 10 additions & 0 deletions game/graphics/opengl_renderer/shaders/plain_texture.vert
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#version 410 core

layout (location = 0) in vec2 position_in;

out vec2 tex_coord;

void main() {
gl_Position = vec4(position_in, 0, 1.0);
tex_coord = (position_in + vec2(1.0, 1.0)) * 0.5;
}

0 comments on commit 510b231

Please sign in to comment.