From bbe54df3a8941490b2413732eb46f1fd6c4cb307 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Mon, 17 Feb 2020 00:09:31 +0900 Subject: [PATCH] GPU/HW: Split rectangles on texture page boundaries Fixes the sky in Ape Escape's menu screen, FF7 menu borders, probably others. --- src/core/gpu_hw.cpp | 64 +++++++++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 20 deletions(-) diff --git a/src/core/gpu_hw.cpp b/src/core/gpu_hw.cpp index 9f1b60edc..bad04ff04 100644 --- a/src/core/gpu_hw.cpp +++ b/src/core/gpu_hw.cpp @@ -128,9 +128,7 @@ void GPU_HW::LoadVertices(RenderCommand rc, u32 num_vertices, const u32* command case Primitive::Rectangle: { // if we're drawing quads, we need to create a degenerate triangle to restart the triangle strip - const bool restart_strip = !IsFlushed(); - if (restart_strip) - AddDuplicateVertex(); + bool restart_strip = !IsFlushed(); u32 buffer_pos = 1; const u32 color = rc.color_for_first_vertex; @@ -140,10 +138,10 @@ void GPU_HW::LoadVertices(RenderCommand rc, u32 num_vertices, const u32* command const auto [texcoord_x, texcoord_y] = UnpackTexcoord(rc.texture_enable ? Truncate16(command_ptr[buffer_pos++]) : 0); - const u16 tex_left = ZeroExtend16(texcoord_x); - const u16 tex_top = ZeroExtend16(texcoord_y); - u32 rectangle_width; - u32 rectangle_height; + u16 orig_tex_left = ZeroExtend16(texcoord_x); + u16 orig_tex_top = ZeroExtend16(texcoord_y); + s32 rectangle_width; + s32 rectangle_height; switch (rc.rectangle_size) { case DrawRectangleSize::R1x1: @@ -159,28 +157,54 @@ void GPU_HW::LoadVertices(RenderCommand rc, u32 num_vertices, const u32* command rectangle_height = 16; break; default: - rectangle_width = command_ptr[buffer_pos] & 0xFFFF; - rectangle_height = command_ptr[buffer_pos] >> 16; + rectangle_width = static_cast(command_ptr[buffer_pos] & 0xFFFF); + rectangle_height = static_cast(command_ptr[buffer_pos] >> 16); break; } if (rectangle_width >= MAX_PRIMITIVE_WIDTH || rectangle_height >= MAX_PRIMITIVE_HEIGHT) return; - max_x = min_x + static_cast(rectangle_width); - max_y = min_y + static_cast(rectangle_height); + max_x = min_x + rectangle_width; + max_y = min_y + rectangle_height; - // TODO: This should repeat the texcoords instead of stretching - const u16 tex_right = tex_left + static_cast(rectangle_width); - const u16 tex_bottom = tex_top + static_cast(rectangle_height); + // Split the rectangle into multiple quads if it's greater than 256x256, as the texture page should repeat. + u16 tex_top = orig_tex_top; + for (s32 y_offset = 0; y_offset < rectangle_height;) + { + const s32 quad_height = std::min(rectangle_height - y_offset, TEXTURE_PAGE_WIDTH - tex_top); + const s32 quad_start_y = min_y + y_offset; + const s32 quad_end_y = quad_start_y + quad_height; + const u16 tex_bottom = tex_top + static_cast(quad_height); - AddVertex(min_x, min_y, color, texpage, tex_left, tex_top); - if (restart_strip) - AddDuplicateVertex(); + u16 tex_left = orig_tex_left; + for (s32 x_offset = 0; x_offset < rectangle_width;) + { + const s32 quad_width = std::min(rectangle_width - x_offset, TEXTURE_PAGE_HEIGHT - tex_left); + const s32 quad_start_x = min_x + x_offset; + const s32 quad_end_x = quad_start_x + quad_width; + const u16 tex_right = tex_left + static_cast(quad_width); - AddVertex(max_x, min_y, color, texpage, tex_right, tex_top); - AddVertex(min_x, max_y, color, texpage, tex_left, tex_bottom); - AddVertex(max_x, max_y, color, texpage, tex_right, tex_bottom); + if (restart_strip) + AddDuplicateVertex(); + + AddVertex(quad_start_x, quad_start_y, color, texpage, tex_left, tex_top); + + if (restart_strip) + AddDuplicateVertex(); + + AddVertex(quad_end_x, quad_start_y, color, texpage, tex_right, tex_top); + AddVertex(quad_start_x, quad_end_y, color, texpage, tex_left, tex_bottom); + AddVertex(quad_end_x, quad_end_y, color, texpage, tex_right, tex_bottom); + restart_strip = true; + + x_offset += quad_width; + tex_left = 0; + } + + y_offset += quad_height; + tex_top = 0; + } } break;