1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-25 20:22:30 +01:00

rsx: Add support for rounded rectangles

This commit is contained in:
kd-11 2023-02-02 01:48:45 +03:00 committed by kd-11
parent 0885884839
commit 34c1e1a9ad
6 changed files with 162 additions and 12 deletions

View File

@ -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<s32>(type));
}

View File

@ -25,6 +25,34 @@ namespace rsx
{
namespace overlays
{
static std::vector<vertex> generate_unit_quadrant(int num_patch_points, const float offset[2], const float scale[2])
{
std::vector<vertex> 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<f32>(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;
}
}
}

View File

@ -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:

View File

@ -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<atomic_t<u32>>, std::unique_ptr<overlay_element>);
@ -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<u16>(origin + (index * 18 * grow_direction)));
if (m_icon)
{
m_icon->set_pos(m_icon->x, m_text.y);
}
set_pos(10, static_cast<u16>(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();

View File

@ -13,15 +13,16 @@ namespace rsx
bottom
};
class message_item : public overlay_element
class message_item : public rounded_rect
{
public:
template <typename T>
message_item(T msg_id, u64 expiration, std::shared_ptr<atomic_t<u32>> refs, std::unique_ptr<overlay_element> 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<atomic_t<u32>> m_refs;
bool m_processed = false;
usz m_cur_pos = umax;
const u16 m_margin = 6;
};
class message final : public overlay

View File

@ -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<s32>(type));
}