From 34c1e1a9ad3eafbfe20691a62c4c44271b75d0c5 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Thu, 2 Feb 2023 01:48:45 +0300 Subject: [PATCH] rsx: Add support for rounded rectangles --- rpcs3/Emu/RSX/GL/GLOverlays.cpp | 3 + rpcs3/Emu/RSX/Overlays/overlay_controls.cpp | 112 ++++++++++++++++++++ rpcs3/Emu/RSX/Overlays/overlay_controls.h | 12 ++- rpcs3/Emu/RSX/Overlays/overlay_message.cpp | 38 +++++-- rpcs3/Emu/RSX/Overlays/overlay_message.h | 6 +- rpcs3/Emu/RSX/VK/VKOverlays.cpp | 3 + 6 files changed, 162 insertions(+), 12 deletions(-) diff --git a/rpcs3/Emu/RSX/GL/GLOverlays.cpp b/rpcs3/Emu/RSX/GL/GLOverlays.cpp index 137b4138d9..d140b88b68 100644 --- a/rpcs3/Emu/RSX/GL/GLOverlays.cpp +++ b/rpcs3/Emu/RSX/GL/GLOverlays.cpp @@ -454,6 +454,9 @@ namespace gl case rsx::overlays::primitive_type::line_strip: primitives = GL_LINE_STRIP; break; + case rsx::overlays::primitive_type::triangle_fan: + primitives = GL_TRIANGLE_FAN; + break; default: fmt::throw_exception("Unexpected primitive type %d", static_cast(type)); } diff --git a/rpcs3/Emu/RSX/Overlays/overlay_controls.cpp b/rpcs3/Emu/RSX/Overlays/overlay_controls.cpp index 02fc1d9b54..23ea6b4dec 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_controls.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_controls.cpp @@ -25,6 +25,34 @@ namespace rsx { namespace overlays { + static std::vector generate_unit_quadrant(int num_patch_points, const float offset[2], const float scale[2]) + { + std::vector result; + result.resize(num_patch_points + 1); + + // Set root vertex + result[0].vec2(offset[0], offset[1]); + + // Set the 0th and Nth outer vertices which lie flush with the axes + result[1].vec2(offset[0] + scale[0], offset[1]); + result[num_patch_points].vec2(offset[0], offset[1] + scale[1]); + + constexpr float degrees_to_radians = 0.0174533f; + for (int i = 1; i < num_patch_points - 1; i++) + { + // If we keep a unit circle, 2 of the 4 components of the rotation matrix become 0 + // We end up with a simple vec2(cos_theta, sin_theta) as the output + // The final scaling and translation can then be done with fmad + const auto angle = degrees_to_radians * ((i * 90) / (num_patch_points - 1)); + result[i + 1].vec2( + std::fmaf(std::cosf(angle), scale[0], offset[0]), + std::fmaf(std::sinf(angle), scale[1], offset[1]) + ); + } + + return result; + } + image_info::image_info(const char* filename) { fs::file f(filename, fs::read + fs::isfile); @@ -905,5 +933,89 @@ namespace rsx bool size_changed = old_width != new_width || old_height != new_height; return size_changed; } + + compiled_resource& rounded_rect::get_compiled() + { + if (!is_compiled) + { + compiled_resources.clear(); + + if (radius == 0 || radius > (w / 2)) + { + // Invalid radius + compiled_resources = overlay_element::get_compiled(); + } + else + { + compiled_resource compiled_resources_temp = {}; + compiled_resources_temp.append({}); // Bg horizontal mid + compiled_resources_temp.append({}); // Bg horizontal top + compiled_resources_temp.append({}); // Bg horizontal bottom + compiled_resources_temp.append({}); // Bg upper-left + compiled_resources_temp.append({}); // Bg lower-left + compiled_resources_temp.append({}); // Bg upper-right + compiled_resources_temp.append({}); // Bg lower-right + + for (auto& draw_cmd : compiled_resources_temp.draw_commands) + { + auto& config = draw_cmd.config; + config.color = back_color; + config.pulse_glow = pulse_effect_enabled; + config.pulse_sinus_offset = pulse_sinus_offset; + config.pulse_speed_modifier = pulse_speed_modifier; + } + + auto& bg0 = compiled_resources_temp.draw_commands[0]; + auto& bg1 = compiled_resources_temp.draw_commands[1]; + auto& bg2 = compiled_resources_temp.draw_commands[2]; + + bg0.verts.emplace_back(f32(x), f32(y + radius), 0.f, 0.f); + bg0.verts.emplace_back(f32(x + w), f32(y + radius), 0.f, 0.f); + bg0.verts.emplace_back(f32(x), f32(y + h) - radius, 0.f, 0.f); + bg0.verts.emplace_back(f32(x + w), f32(y + h) - radius, 0.f, 0.f); + + bg1.verts.emplace_back(f32(x + radius), f32(y), 0.f, 0.f); + bg1.verts.emplace_back(f32(x + w) - radius, f32(y), 0.f, 0.f); + bg1.verts.emplace_back(f32(x + radius), f32(y + radius), 0.f, 0.f); + bg1.verts.emplace_back(f32(x + w) - radius, f32(y + radius), 0.f, 0.f); + + bg2.verts.emplace_back(f32(x + radius), f32(y + h) - radius, 0.f, 0.f); + bg2.verts.emplace_back(f32(x + w) - radius, f32(y + h) - radius, 0.f, 0.f); + bg2.verts.emplace_back(f32(x + radius), f32(y + h) + 1.f, 0.f, 0.f); // Note the +1 subpixel correction + bg2.verts.emplace_back(f32(x + w) - radius, f32(y + h) + 1.f, 0.f, 0.f); + + // Generate the quadrants + const f32 corners[4][2] = + { + { f32(x + radius), f32(y + radius) }, + { f32(x + radius), f32(y + h) - radius }, + { f32(x + w) - radius, f32(y + radius) }, + { f32(x + w) - radius, f32(y + h) - radius } + }; + + const f32 radius_f = static_cast(radius); + const f32 scale[4][2] = + { + { -radius_f, -radius_f }, + { -radius_f, +radius_f }, + { +radius_f, -radius_f }, + { +radius_f, +radius_f } + }; + + for (int i = 0; i < 4; ++i) + { + auto& command = compiled_resources_temp.draw_commands[i + 3]; + command.config.primitives = rsx::overlays::primitive_type::triangle_fan; + command.verts = generate_unit_quadrant(num_control_points, corners[i], scale[i]); + } + + compiled_resources.add(std::move(compiled_resources_temp), margin_left, margin_top); + } + + is_compiled = true; + } + + return compiled_resources; + } } } diff --git a/rpcs3/Emu/RSX/Overlays/overlay_controls.h b/rpcs3/Emu/RSX/Overlays/overlay_controls.h index 9c2e42a9e2..4072ba2d95 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_controls.h +++ b/rpcs3/Emu/RSX/Overlays/overlay_controls.h @@ -27,7 +27,8 @@ namespace rsx quad_list = 0, triangle_strip = 1, line_list = 2, - line_strip = 3 + line_strip = 3, + triangle_fan = 4 }; struct image_info @@ -241,6 +242,15 @@ namespace rsx } }; + struct rounded_rect : public overlay_element + { + u8 radius = 5; + u8 num_control_points = 8; // Smoothness control + + using overlay_element::overlay_element; + compiled_resource& get_compiled() override; + }; + struct image_view : public overlay_element { private: diff --git a/rpcs3/Emu/RSX/Overlays/overlay_message.cpp b/rpcs3/Emu/RSX/Overlays/overlay_message.cpp index 0738366dc0..26d6efa924 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_message.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_message.cpp @@ -24,6 +24,7 @@ namespace rsx m_text.set_font("Arial", 14); m_text.set_text(msg_id); + m_text.set_padding(4, 8, 4, 8); m_text.auto_resize(); m_text.back_color.a = 0.f; @@ -32,10 +33,18 @@ namespace rsx m_fade_animation.duration = 2.f; m_fade_animation.active = true; + back_color.a = 0.15; + if (icon) { m_icon = std::move(icon); m_icon->set_pos(m_text.x + m_text.w + 8, m_text.y); + + set_size(m_margin + m_text.w + m_icon->w + m_margin, m_margin + std::max(m_text.h, m_icon->h) + m_margin); + } + else + { + set_size(m_text.w + m_margin + m_margin, m_text.h + m_margin + m_margin); } } template message_item::message_item(std::string msg_id, u64, std::shared_ptr>, std::unique_ptr); @@ -47,15 +56,30 @@ namespace rsx return m_refs && *m_refs == 0 ? 0 : m_expiration_time; } + void message_item::set_pos(u16 _x, u16 _y) + { + rounded_rect::set_pos(_x, _y); + m_text.set_pos(_x + m_margin, y + m_margin); + + if (m_icon) + { + m_icon->set_pos(m_icon->x, m_text.y); + } + } + compiled_resource& message_item::get_compiled() { - if (!m_processed) + if (!m_processed || !m_fade_animation.active) { compiled_resources = {}; return compiled_resources; } - compiled_resources = m_text.get_compiled(); + // Disable caching + is_compiled = false; + + compiled_resources = rounded_rect::get_compiled(); + compiled_resources.add(m_text.get_compiled()); if (m_icon) { compiled_resources.add(m_icon->get_compiled()); @@ -70,18 +94,14 @@ namespace rsx if (m_cur_pos != index) { m_cur_pos = index; - m_text.set_pos(10, static_cast(origin + (index * 18 * grow_direction))); - if (m_icon) - { - m_icon->set_pos(m_icon->x, m_text.y); - } + set_pos(10, static_cast(origin + (index * 18 * grow_direction))); } if (!m_processed) { m_expiration_time = get_expiration_time(m_visible_duration); } - else if ((m_expiration_time - time) < 2'000'000) + else if (time + 2'000'000 > m_expiration_time) { m_fade_animation.update(rsx::get_current_renderer()->vblank_count); } @@ -126,7 +146,7 @@ namespace rsx std::lock_guard lock(m_mutex_queue); - update_queue(m_vis_items_top, m_ready_queue_top, 0, 1); + update_queue(m_vis_items_top, m_ready_queue_top, 10, 1); update_queue(m_vis_items_bottom, m_ready_queue_bottom, virtual_height - 18, -1); visible = !m_vis_items_top.empty() || !m_vis_items_bottom.empty(); diff --git a/rpcs3/Emu/RSX/Overlays/overlay_message.h b/rpcs3/Emu/RSX/Overlays/overlay_message.h index 09348e8111..62d0b7cb8c 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_message.h +++ b/rpcs3/Emu/RSX/Overlays/overlay_message.h @@ -13,15 +13,16 @@ namespace rsx bottom }; - class message_item : public overlay_element + class message_item : public rounded_rect { public: template message_item(T msg_id, u64 expiration, std::shared_ptr> refs, std::unique_ptr icon = {}); void update(usz index, u64 time, u16 origin, int grow_direction); + void set_pos(u16 _x, u16 _y) override; u64 get_expiration() const; - compiled_resource& get_compiled(); + compiled_resource& get_compiled() override; private: label m_text{}; @@ -33,6 +34,7 @@ namespace rsx std::shared_ptr> m_refs; bool m_processed = false; usz m_cur_pos = umax; + const u16 m_margin = 6; }; class message final : public overlay diff --git a/rpcs3/Emu/RSX/VK/VKOverlays.cpp b/rpcs3/Emu/RSX/VK/VKOverlays.cpp index 17481ad646..62aa4d9460 100644 --- a/rpcs3/Emu/RSX/VK/VKOverlays.cpp +++ b/rpcs3/Emu/RSX/VK/VKOverlays.cpp @@ -703,6 +703,9 @@ namespace vk case rsx::overlays::primitive_type::line_strip: renderpass_config.set_primitive_type(VK_PRIMITIVE_TOPOLOGY_LINE_STRIP); break; + case rsx::overlays::primitive_type::triangle_fan: + renderpass_config.set_primitive_type(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN); + break; default: fmt::throw_exception("Unexpected primitive type %d", static_cast(type)); }