From 7d791a3759ff6ad77b32869fae4f7dbbc6d34b89 Mon Sep 17 00:00:00 2001 From: ManDude <7569514+ManDude@users.noreply.github.com> Date: Mon, 10 Jan 2022 18:53:38 +0000 Subject: [PATCH] texture support except everything is broken for some reason --- .../opengl_renderer/SpriteRenderer.cpp | 404 ++++++++++++------ .../graphics/opengl_renderer/SpriteRenderer.h | 100 ++++- .../opengl_renderer/shaders/sprite_3d.frag | 16 +- .../opengl_renderer/shaders/sprite_3d.vert | 11 +- 4 files changed, 373 insertions(+), 158 deletions(-) diff --git a/game/graphics/opengl_renderer/SpriteRenderer.cpp b/game/graphics/opengl_renderer/SpriteRenderer.cpp index 84d9290a45..3a9ae7fb32 100644 --- a/game/graphics/opengl_renderer/SpriteRenderer.cpp +++ b/game/graphics/opengl_renderer/SpriteRenderer.cpp @@ -30,13 +30,15 @@ u32 process_sprite_chunk_header(DmaFollower& dma) { } } // namespace +constexpr int SPRITE_RENDERER_MAX_SPRITES = 48; + SpriteRenderer::SpriteRenderer(const std::string& name, BucketId my_id) : BucketRenderer(name, my_id) { glGenBuffers(1, &m_ogl.vertex_buffer); glGenVertexArrays(1, &m_ogl.vao); glBindVertexArray(m_ogl.vao); glBindBuffer(GL_ARRAY_BUFFER, m_ogl.vertex_buffer); - m_ogl.vertex_buffer_max_verts = 48 * 3 * 2; // 48 sprites + m_ogl.vertex_buffer_max_verts = SPRITE_RENDERER_MAX_SPRITES * 3 * 2; m_ogl.vertex_buffer_bytes = m_ogl.vertex_buffer_max_verts * sizeof(SpriteVertex3D); glBufferData(GL_ARRAY_BUFFER, m_ogl.vertex_buffer_bytes, nullptr, GL_STREAM_DRAW); glEnableVertexAttribArray(0); @@ -84,6 +86,15 @@ SpriteRenderer::SpriteRenderer(const std::string& name, BucketId my_id) sizeof(SpriteVertex3D), // (void*)offsetof(SpriteVertex3D, vert_id) // offset in array (why is this a pointer...) ); + + glEnableVertexAttribArray(5); + glVertexAttribIPointer( + 5, // location 0 in the shader + 2, // 3 floats per vert + GL_UNSIGNED_BYTE, // floats + sizeof(SpriteVertex3D), // + (void*)offsetof(SpriteVertex3D, tex_info) // offset in array (why is this a pointer...) + ); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); @@ -806,6 +817,32 @@ std::array sprite_quat_to_rot(float qi, float qj, float qk) { return result; } +void SpriteRenderer::render_verts(SharedRenderState* render_state, ScopedProfilerNode& prof) { + update_gl_blend(m_adgif_state); + + for (int i = 0; i <= m_adgif_index; ++i) { + update_gl_texture(render_state, i); + } + + glBindVertexArray(m_ogl.vao); + + // render! + glBindBuffer(GL_ARRAY_BUFFER, m_ogl.vertex_buffer); + glBufferSubData(GL_ARRAY_BUFFER, 0, m_sprite_offset * sizeof(SpriteVertex3D) * 6, + m_vertices_3d.data()); + glActiveTexture(GL_TEXTURE0); + + glDrawArrays(GL_TRIANGLES, 0, m_sprite_offset * 6); + + glBindVertexArray(0); + int n_tris = m_sprite_offset * 6 / 3; + prof.add_tri(n_tris); + prof.add_draw_call(1); + + m_sprite_offset = 0; + m_adgif_index = 0; +} + Vector4f sprite_transform2(const Vector4f& root, const Vector4f& off, const Matrix4f& cam, @@ -827,17 +864,180 @@ Vector4f sprite_transform2(const Vector4f& root, pos.x() += offset.x(); pos.y() += offset.y(); pos.z() += offset.z(); - // Vector4f transformed_pos = matrix_transform(cam, pos); - // float Q = pfog0 / transformed_pos.w(); - // transformed_pos.x() *= Q; - // transformed_pos.y() *= Q; - // transformed_pos.z() *= Q; - // Vector4f offset_pos = transformed_pos + hvdf_off; - // offset_pos.w() = std::max(offset_pos.w(), fog_max); - // offset_pos.w() = std::min(offset_pos.w(), fog_min); + Vector4f transformed_pos = matrix_transform(cam, pos); + float Q = pfog0 / transformed_pos.w(); + transformed_pos.x() *= Q; + transformed_pos.y() *= Q; + transformed_pos.z() *= Q; + Vector4f offset_pos = transformed_pos + hvdf_off; + offset_pos.w() = std::max(offset_pos.w(), fog_max); + offset_pos.w() = std::min(offset_pos.w(), fog_min); - // return offset_pos; - return pos; + return offset_pos; +} + +void SpriteRenderer::handle_tex0(u64 val, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { + GsTex0 reg(val); + + // update tbp + + m_adgif_state.reg_tex0 = reg; + m_adgif_state.texture_base_ptr = reg.tbp0(); + m_adgif_state.using_mt4hh = reg.psm() == GsTex0::PSM::PSMT4HH; + m_adgif_state.tcc = reg.tcc(); + + // tbw: assume they got it right + // psm: assume they got it right + // tw: assume they got it right + // th: assume they got it right + + assert(reg.tfx() == GsTex0::TextureFunction::MODULATE); + + // cbp: assume they got it right + // cpsm: assume they got it right + // csm: assume they got it right +} + +void SpriteRenderer::handle_tex1(u64 val, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { + GsTex1 reg(val); + // for now, we aren't going to handle mipmapping. I don't think it's used with direct. + // assert(reg.mxl() == 0); + // if that's true, we can ignore LCM, MTBA, L, K + + m_adgif_state.enable_tex_filt = reg.mmag(); + + // MMAG/MMIN specify texture filtering. For now, assume always linear + // assert(reg.mmag() == true); + // if (!(reg.mmin() == 1 || reg.mmin() == 4)) { // with mipmap off, both of these are linear + // // lg::error("unsupported mmin"); + // } +} + +void SpriteRenderer::handle_clamp(u64 val, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { + if (!(val == 0b101 || val == 0 || val == 1 || val == 0b100)) { + fmt::print("clamp: 0x{:x}\n", val); + assert(false); + } + + m_adgif_state.reg_clamp = val; + m_adgif_state.clamp_s = val & 0b001; + m_adgif_state.clamp_t = val & 0b100; +} + +void SpriteRenderer::update_gl_blend(AdGifState& state) { + if (!state.alpha_blend_enable) { + glDisable(GL_BLEND); + } else { + if (state.a == GsAlpha::BlendMode::SOURCE && state.b == GsAlpha::BlendMode::DEST && + state.c == GsAlpha::BlendMode::SOURCE && state.d == GsAlpha::BlendMode::DEST) { + // (Cs - Cd) * As + Cd + // Cs * As + (1 - As) * Cd + glEnable(GL_BLEND); + // s, d + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } else if (state.a == GsAlpha::BlendMode::SOURCE && + state.b == GsAlpha::BlendMode::ZERO_OR_FIXED && + state.c == GsAlpha::BlendMode::SOURCE && state.d == GsAlpha::BlendMode::DEST) { + // (Cs - 0) * As + Cd + // Cs * As + (1) * CD + glEnable(GL_BLEND); + // s, d + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + } else { + // unsupported blend: a 0 b 2 c 2 d 1 + lg::error("unsupported blend: a {} b {} c {} d {}\n", (int)state.a, (int)state.b, + (int)state.c, (int)state.d); + assert(false); + } + } +} + +void SpriteRenderer::handle_alpha(u64 val, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { + GsAlpha reg(val); + + m_adgif_state.from_register(reg); +} + +void SpriteRenderer::update_gl_prim(SharedRenderState* render_state) { + // currently gouraud is handled in setup. + const auto& state = m_prim_gl_state; + if (state.fogging_enable) { + // assert(false); + } + if (state.aa_enable) { + assert(false); + } + if (state.use_uv) { + assert(false); + } + if (state.ctxt) { + assert(false); + } + if (state.fix) { + assert(false); + } +} + +void SpriteRenderer::update_gl_texture(SharedRenderState* render_state, int unit) { + TextureRecord* tex = nullptr; + auto& state = m_adgif_state_stack[unit]; + if (!state.used) { + // nothing used this state, don't bother binding the texture. + return; + } + if (state.using_mt4hh) { + tex = render_state->texture_pool->lookup_mt4hh(state.texture_base_ptr); + } else { + tex = render_state->texture_pool->lookup(state.texture_base_ptr); + } + + if (!tex) { + // TODO Add back + fmt::print("Failed to find texture at {}, using random\n", state.texture_base_ptr); + tex = render_state->texture_pool->get_random_texture(); + if (tex) { + // fmt::print("Successful texture lookup! {} {}\n", tex->page_name, tex->name); + } + } + assert(tex); + + // first: do we need to load the texture? + if (!tex->on_gpu) { + render_state->texture_pool->upload_to_gpu(tex); + } + + glActiveTexture(GL_TEXTURE20 + unit); + glBindTexture(GL_TEXTURE_2D, tex->gpu_texture); + // Note: CLAMP and CLAMP_TO_EDGE are different... + if (state.clamp_s) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + } else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + } + + if (state.clamp_t) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + + if (state.enable_tex_filt) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + + state.used = false; } void SpriteRenderer::do_3d_block_cpu(u32 count, @@ -845,8 +1045,9 @@ void SpriteRenderer::do_3d_block_cpu(u32 count, ScopedProfilerNode& prof) { Matrix4f camera_matrix = m_3d_matrix_data.camera; // vf25, vf26, vf27, vf28 Vector4f hvdf_offset = m_3d_matrix_data.hvdf_offset; - glUniform4f(glGetUniformLocation(render_state->shaders[ShaderId::SPRITE_CPU].id(), "hvdf_offset"), - hvdf_offset[0], hvdf_offset[1], hvdf_offset[2], hvdf_offset[3]); + glUniform4fv( + glGetUniformLocation(render_state->shaders[ShaderId::SPRITE_CPU].id(), "hvdf_offset"), 1, + m_3d_matrix_data.hvdf_offset.data()); glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::SPRITE_CPU].id(), "pfog0"), m_frame_data.pfog0); glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::SPRITE_CPU].id(), "fog_min"), @@ -867,128 +1068,72 @@ void SpriteRenderer::do_3d_block_cpu(u32 count, m_frame_data.inv_area); glUniformMatrix4fv( glGetUniformLocation(render_state->shaders[ShaderId::SPRITE_CPU].id(), "camera"), 1, GL_FALSE, - camera_matrix.data()); + m_3d_matrix_data.camera.data()); glUniform4fv(glGetUniformLocation(render_state->shaders[ShaderId::SPRITE_CPU].id(), "xyz_array"), 4, m_frame_data.xyz_array[0].data()); glUniform4fv(glGetUniformLocation(render_state->shaders[ShaderId::SPRITE_CPU].id(), "st_array"), 4, m_frame_data.st_array[0].data()); - /* - auto vecdata_loc = - glGetUniformLocation(render_state->shaders[ShaderId::SPRITE_CPU].id(), "vec_data_2d"); - for (int i = 0; i < count; ++i) { - // upload vec-data - glUniform4fv(vecdata_loc + 0 + i * 5, 1, m_vec_data_2d[i].xyz_sx.data()); - glUniform1i(vecdata_loc + 1 + i * 5, m_vec_data_2d[i].flag()); - glUniform1i(vecdata_loc + 2 + i * 5, m_vec_data_2d[i].matrix()); - glUniform2fv(vecdata_loc + 3 + i * 5, 1, &m_vec_data_2d[i].flag_rot_sy.data()[2]); - glUniform4fv(vecdata_loc + 4 + i * 5, 1, m_vec_data_2d[i].rgba.data()); - } - */ + + // fmt::print("3d:\n{}", m_frame_data.sprite_3d_giftag.print()); + // fmt::print("adgif:\n{}", m_frame_data.adgif_giftag.print()); + // fmt::print("clipped:\n{}", m_frame_data.clipped_giftag.print()); + //if (m_prim_gl_state.current_register != m_frame_data.sprite_3d_giftag.prim()) { + // m_prim_gl_state.from_register(m_frame_data.sprite_3d_giftag.prim()); + //} for (u32 sprite_idx = 0; sprite_idx < count; sprite_idx++) { + if (m_sprite_offset == SPRITE_RENDERER_MAX_SPRITES) { + render_verts(render_state, prof); + } - auto& vert1 = m_vertices_3d.at(sprite_idx * 6 + 0); - auto& vert2 = m_vertices_3d.at(sprite_idx * 6 + 1); - auto& vert3 = m_vertices_3d.at(sprite_idx * 6 + 2); - auto& vert4 = m_vertices_3d.at(sprite_idx * 6 + 3); - auto& vert5 = m_vertices_3d.at(sprite_idx * 6 + 4); - auto& vert6 = m_vertices_3d.at(sprite_idx * 6 + 5); + auto& adgif = m_adgif[sprite_idx]; + // fmt::print("adgif: {:X} {:X} {:X} {:X}\n", adgif.tex0_data, adgif.tex1_data, adgif.clamp_data, adgif.alpha_data); + handle_tex0(adgif.tex0_data, render_state, prof); + handle_tex1(adgif.tex1_data, render_state, prof); + // handle_mip(adgif.mip_data, render_state, prof); + handle_clamp(adgif.clamp_data & 0b111, render_state, prof); + handle_alpha(adgif.alpha_data, render_state, prof); + + bool push_state = false; + if (!current_adgif_state()->used) { + *current_adgif_state() = m_adgif_state; + current_adgif_state()->used = true; + } else if (m_adgif_state != *current_adgif_state()) { + if (m_adgif_index + 1 == ADGIF_STATE_COUNT || + !m_adgif_state.nontexture_equal(*current_adgif_state())) { + render_verts(render_state, prof); + } else { + m_adgif_index++; + } + *current_adgif_state() = m_adgif_state; + current_adgif_state()->used = true; + } + + size_t vert_idx = 6 * m_sprite_offset++; + + auto& vert1 = m_vertices_3d.at(vert_idx + 0); vert1.xyz_sx = m_vec_data_2d[sprite_idx].xyz_sx; vert1.quat_sy = m_vec_data_2d[sprite_idx].flag_rot_sy; vert1.rgba = m_vec_data_2d[sprite_idx].rgba / 255; - vert1.vert_id = 0; + vert1.tex_info[0] = m_adgif_index; + vert1.tex_info[1] = current_adgif_state()->tcc; - m_vertices_3d.at(sprite_idx * 6 + 1) = vert1; - m_vertices_3d.at(sprite_idx * 6 + 2) = vert1; - m_vertices_3d.at(sprite_idx * 6 + 3) = vert1; - m_vertices_3d.at(sprite_idx * 6 + 4) = vert1; - m_vertices_3d.at(sprite_idx * 6 + 5) = vert1; + m_vertices_3d.at(vert_idx + 1) = vert1; + m_vertices_3d.at(vert_idx + 2) = vert1; + m_vertices_3d.at(vert_idx + 3) = vert1; + m_vertices_3d.at(vert_idx + 4) = vert1; + m_vertices_3d.at(vert_idx + 5) = vert1; - m_vertices_3d.at(sprite_idx * 6 + 0).vert_id = 0; - m_vertices_3d.at(sprite_idx * 6 + 1).vert_id = 1; - m_vertices_3d.at(sprite_idx * 6 + 2).vert_id = 2; - m_vertices_3d.at(sprite_idx * 6 + 3).vert_id = 2; - m_vertices_3d.at(sprite_idx * 6 + 4).vert_id = 3; - m_vertices_3d.at(sprite_idx * 6 + 5).vert_id = 0; + m_vertices_3d.at(vert_idx + 0).vert_id = 0; + m_vertices_3d.at(vert_idx + 1).vert_id = 1; + m_vertices_3d.at(vert_idx + 2).vert_id = 2; + m_vertices_3d.at(vert_idx + 3).vert_id = 2; + m_vertices_3d.at(vert_idx + 4).vert_id = 3; + m_vertices_3d.at(vert_idx + 5).vert_id = 0; /* -// STEP 1: UNPACK DATA AND CREATE READABLE VARIABLES - - Vector4f position = Vector4f(vert1.xyz_sx.x(), vert1.xyz_sx.y(), vert1.xyz_sx.z(), 1.0f); - float sx = vert1.xyz_sx.w(); - float sy = vert1.quat_sy.w(); - Vector4f quat = Vector4f(vert1.quat_sy.x(), vert1.quat_sy.y(), vert1.quat_sy.z(), 1.0f); - Vector4f fragment_color = vert1.rgba; - - // STEP 2: TRANSFORM TRANS - - Vector4f transformed_pos_vf02 = - matrix_transform(camera_matrix, m_vec_data_2d[sprite_idx] .xyz_sx); - - Vector4f scales_vf01 = m_vec_data_2d[sprite_idx] .xyz_sx; // now used for something else. - Vector4f fog_consts_vf12 = Vector4f(m_frame_data.fog_min, m_frame_data.fog_max, - m_frame_data.max_scale, m_frame_data.bonus); - - scales_vf01.z() = sy; // start building the scale vector - - float Q = m_frame_data.pfog0 / transformed_pos_vf02.w(); - // quat.z() *= m_frame_data.deg_to_rad; - scales_vf01.z() *= Q; // sy - scales_vf01.w() *= Q; // sx - - transformed_pos_vf02.x() *= Q; - transformed_pos_vf02.y() *= Q; - transformed_pos_vf02.z() *= Q; - - scales_vf01.x() = scales_vf01.z(); // = sy - - Vector4f offset_pos_vf10 = transformed_pos_vf02 + hvdf_offset; - - scales_vf01.x() *= scales_vf01.w(); // x = sx * sy - - offset_pos_vf10.w() = std::max(offset_pos_vf10.w(), m_frame_data.fog_max); - - scales_vf01.z() = std::max(scales_vf01.z(), m_frame_data.min_scale); - scales_vf01.w() = std::max(scales_vf01.w(), m_frame_data.min_scale); - - scales_vf01.x() *= m_frame_data.inv_area; // x = sx * sy * inv_area (area ratio) - - offset_pos_vf10.w() = std::min(offset_pos_vf10.w(), m_frame_data.fog_min); - - scales_vf01.z() = std::min(scales_vf01.z(), fog_consts_vf12.z()); - scales_vf01.w() = std::min(scales_vf01.w(), fog_consts_vf12.z()); - - scales_vf01.x() = std::min(scales_vf01.x(), 1.0f); - - transformed_pos_vf02.w() = offset_pos_vf10.w() - fog_consts_vf12.y(); - - fragment_color.w() *= scales_vf01.x(); // is this right? doesn't this stall?? - - std::array rot = sprite_quat_to_rot(quat.x(), quat.y(), quat.z()); - Vector4f transf = sprite_transform2(position, m_frame_data.xyz_array[0], camera_matrix, rot, - sx, sy, hvdf_offset, - m_frame_data.pfog0, m_frame_data.fog_min, m_frame_data.fog_max); - - // packet.sprite_giftag = use_first_giftag ? m_frame_data.sprite_2d_giftag : - // m_frame_data.sprite_2d_giftag2; - - auto tex_coord = m_frame_data.st_array[0].xyz(); - - // correct xy offset - transf.x() -= (2048.); - transf.y() -= (2048.); - - // correct z scale - transf.z() /= (8388608); - transf.z() -= 1; - - // correct xy scale - transf.x() /= (256); - transf.y() /= -(128); - - SpriteHud2DPacket packet; memset(&packet, 0, sizeof(packet)); // ilw.y vi08, 1(vi02) | nop vi08 = matrix @@ -1180,24 +1325,9 @@ void SpriteRenderer::do_3d_block_cpu(u32 count, */ } - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_GEQUAL); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glBindVertexArray(m_ogl.vao); - - // render! - glBindBuffer(GL_ARRAY_BUFFER, m_ogl.vertex_buffer); - glBufferSubData(GL_ARRAY_BUFFER, 0, count * sizeof(SpriteVertex3D) * 6, m_vertices_3d.data()); - glActiveTexture(GL_TEXTURE0); - - glDrawArrays(GL_TRIANGLES, 0, count * 6); - - glBindVertexArray(0); - int n_tris = (count * 6 / 3); - prof.add_tri(n_tris); - prof.add_draw_call(1); + if (m_sprite_offset > 0) { + render_verts(render_state, prof); + } } void SpriteRenderer::do_2d_group0_block_cpu(u32 count, diff --git a/game/graphics/opengl_renderer/SpriteRenderer.h b/game/graphics/opengl_renderer/SpriteRenderer.h index a4711d4636..7a8e3431cb 100644 --- a/game/graphics/opengl_renderer/SpriteRenderer.h +++ b/game/graphics/opengl_renderer/SpriteRenderer.h @@ -168,6 +168,16 @@ class SpriteRenderer : public BucketRenderer { void do_2d_group0_block_cpu(u32 count, SharedRenderState* render_state, ScopedProfilerNode& prof); void do_3d_block_cpu(u32 count, SharedRenderState* render_state, ScopedProfilerNode& prof); + void handle_tex0(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof); + void handle_tex1(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof); + // void handle_mip(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof); + void handle_clamp(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof); + void handle_alpha(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof); + + void update_gl_prim(SharedRenderState* render_state); + void update_gl_texture(SharedRenderState* render_state, int unit); + void render_verts(SharedRenderState* render_state, ScopedProfilerNode& prof); + u8 m_sprite_distorter_setup[7 * 16]; // direct data u8 m_sprite_direct_setup[3 * 16]; SpriteFrameData m_frame_data; // qwa: 980 @@ -191,12 +201,13 @@ class SpriteRenderer : public BucketRenderer { bool m_3d_enable = true; struct SpriteVertex3D { - math::Vector4f xyz_sx; // position + x scale - math::Vector4f quat_sy; // quaternion + y scale - math::Vector4f rgba; // color + math::Vector4f xyz_sx; // position + x scale + math::Vector4f quat_sy; // quaternion + y scale + math::Vector4f rgba; // color math::Vector flags_matrix; // flags + matrix... split - u8 vert_id; - math::Vector pad; + u16 vert_id; + math::Vector pad; + math::Vector tex_info; }; static_assert(sizeof(SpriteVertex3D) == 64); @@ -208,4 +219,83 @@ class SpriteRenderer : public BucketRenderer { u32 vertex_buffer_bytes = 0; u32 vertex_buffer_max_verts = 0; } m_ogl; + + int m_sprite_offset = 0; + + // state set through the prim register that requires changing GL stuff. + struct PrimGlState { + void from_register(GsPrim reg) { + current_register = reg; + gouraud_enable = reg.gouraud(); + texture_enable = reg.tme(); + fogging_enable = reg.fge(); + aa_enable = reg.aa1(); + use_uv = reg.fst(); + ctxt = reg.ctxt(); + fix = reg.fix(); + } + + GsPrim current_register; + bool gouraud_enable = false; + bool texture_enable = false; + bool fogging_enable = false; + + bool aa_enable = false; + bool use_uv = false; // todo: might not require a gl state change + bool ctxt = false; // do they ever use ctxt2? + bool fix = false; // what does this even do? + } m_prim_gl_state; + + static constexpr int ADGIF_STATE_COUNT = 1; + + struct AdGifState { + GsTex0 reg_tex0; + u32 texture_base_ptr = 0; + bool using_mt4hh = false; + bool tcc = false; + + bool enable_tex_filt = false; + + u64 reg_clamp = 0b101; + bool clamp_s = true; + bool clamp_t = true; + + GsAlpha reg_alpha; + GsAlpha::BlendMode a = GsAlpha::BlendMode::SOURCE; + GsAlpha::BlendMode b = GsAlpha::BlendMode::DEST; + GsAlpha::BlendMode c = GsAlpha::BlendMode::SOURCE; + GsAlpha::BlendMode d = GsAlpha::BlendMode::DEST; + bool alpha_blend_enable = false; + u8 fix = 0; + void from_register(GsAlpha reg) { + reg_alpha = reg; + a = reg.a_mode(); + b = reg.b_mode(); + c = reg.c_mode(); + d = reg.d_mode(); + fix = reg.fix(); + + assert(fix == 0); + } + + bool used = false; + + bool nontexture_equal(const AdGifState& other) const { + return reg_alpha == other.reg_alpha && alpha_blend_enable == other.alpha_blend_enable; + } + + bool operator==(const AdGifState& other) const { + return reg_tex0 == other.reg_tex0 && enable_tex_filt == other.enable_tex_filt && + reg_clamp == other.reg_clamp && nontexture_equal(other); + } + bool operator!=(const AdGifState& other) const { return !operator==(other); } + } m_adgif_state_stack[ADGIF_STATE_COUNT]; + + AdGifState m_adgif_state; // temp state + + AdGifState* current_adgif_state() { return &m_adgif_state_stack[m_adgif_index]; } + + int m_adgif_index = 0; + + void update_gl_blend(AdGifState& state); }; diff --git a/game/graphics/opengl_renderer/shaders/sprite_3d.frag b/game/graphics/opengl_renderer/shaders/sprite_3d.frag index 9ea213bc89..7df881094e 100644 --- a/game/graphics/opengl_renderer/shaders/sprite_3d.frag +++ b/game/graphics/opengl_renderer/shaders/sprite_3d.frag @@ -3,9 +3,8 @@ out vec4 color; in vec4 fragment_color; -in vec2 tex_coord; - -// in flat uvec2 tex_info; +in vec3 tex_coord; +in flat uvec2 tex_info; layout (binding = 20) uniform sampler2D tex_T0; layout (binding = 21) uniform sampler2D tex_T1; @@ -35,12 +34,11 @@ vec4 sample_tex(vec2 coord, uint unit) { } void main() { - // vec4 T0 = sample_tex(tex_coord, tex_info.x); - // if (tex_info.y == 0) { - // T0.w = 1.0; - // } - // vec4 tex_color = fragment_color * T0 * 2.0; - vec4 tex_color = fragment_color * 2.0; + vec4 T0 = sample_tex(tex_coord.xy / tex_coord.z, tex_info.x); + if (tex_info.y == 0) { + T0.w = 1.0; + } + vec4 tex_color = fragment_color * T0 * 2.0; if (tex_color.a < 0.016) { // discard; } diff --git a/game/graphics/opengl_renderer/shaders/sprite_3d.vert b/game/graphics/opengl_renderer/shaders/sprite_3d.vert index 1992b5a246..132fb6a016 100644 --- a/game/graphics/opengl_renderer/shaders/sprite_3d.vert +++ b/game/graphics/opengl_renderer/shaders/sprite_3d.vert @@ -5,6 +5,7 @@ layout (location = 1) in vec4 quat_sy; layout (location = 2) in vec4 rgba; layout (location = 3) in uvec2 flags_matrix; layout (location = 4) in uint vert_id; +layout (location = 5) in uvec2 tex_info_in; uniform vec4 hvdf_offset; uniform mat4 camera; @@ -23,10 +24,7 @@ uniform vec4 st_array[4]; out vec4 fragment_color; out vec3 tex_coord; - -// putting all texture info stuff here so it's easier to copy-paste -// layout (location = 3) in uvec2 tex_info_in; -// out flat uvec2 tex_info; +out flat uvec2 tex_info; vec4 matrix_transform(mat4 mtx, vec4 pt) { return mtx[3] @@ -119,7 +117,6 @@ void main() { gl_Position = transformed; // scissoring area adjust gl_Position.y *= 512.0/448.0; - // fragment_color = vec4(rgba_in.x, rgba_in.y, rgba_in.z, rgba_in.w * 2.); - // tex_coord = tex_coord_in; - // tex_info = tex_info_in; + + tex_info = tex_info_in; }