rpcsx/rpcs3/Emu/RSX/Overlays/overlay_message.cpp

297 lines
7.4 KiB
C++
Raw Normal View History

2022-05-17 16:35:41 +02:00
#include "stdafx.h"
#include "overlay_message.h"
#include "Emu/RSX/RSXThread.h"
namespace rsx
{
namespace overlays
{
2023-02-01 21:04:08 +01:00
static u64 get_expiration_time(u64 duration)
{
if (duration == umax)
{
return duration;
}
return rsx::uclock() + duration;
}
template <typename T>
message_item::message_item(T msg_id, u64 expiration, std::shared_ptr<atomic_t<u32>> refs, std::shared_ptr<overlay_element> icon)
2022-05-17 16:35:41 +02:00
{
2023-02-01 21:04:08 +01:00
m_visible_duration = expiration;
m_refs = std::move(refs);
2022-05-17 16:35:41 +02:00
2023-02-01 21:04:08 +01:00
m_text.set_font("Arial", 14);
2022-05-17 16:35:41 +02:00
m_text.set_text(msg_id);
m_text.set_padding(4, 8, 4, 8);
2022-05-17 16:35:41 +02:00
m_text.auto_resize();
m_text.back_color.a = 0.f;
m_fade_in_animation.current = color4f(1.f, 1.f, 1.f, 0.f);
m_fade_in_animation.end = color4f(1.0f);
m_fade_in_animation.duration = 1.f;
m_fade_in_animation.active = true;
m_fade_out_animation.current = color4f(1.f);
m_fade_out_animation.end = color4f(1.f, 1.f, 1.f, 0.f);
m_fade_out_animation.duration = 1.f;
m_fade_out_animation.active = false;
2023-02-01 21:04:08 +01:00
2023-02-02 19:49:32 +01:00
back_color = color4f(0.25f, 0.25f, 0.25f, 0.85f);
2023-02-01 21:04:08 +01:00
if (icon)
{
m_icon = icon;
2023-02-01 21:04:08 +01:00
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);
2023-02-01 21:04:08 +01:00
}
2022-05-17 16:35:41 +02:00
}
template message_item::message_item(std::string msg_id, u64, std::shared_ptr<atomic_t<u32>>, std::shared_ptr<overlay_element>);
template message_item::message_item(localized_string_id msg_id, u64, std::shared_ptr<atomic_t<u32>>, std::shared_ptr<overlay_element>);
2022-05-17 16:35:41 +02:00
void message_item::reset_expiration()
{
m_expiration_time = get_expiration_time(m_visible_duration);
}
2022-05-17 16:35:41 +02:00
u64 message_item::get_expiration() const
{
2023-02-13 11:33:06 +01:00
// If reference counting is enabled and reached 0 consider it expired
return m_refs && *m_refs == 0 ? 0 : m_expiration_time;
2022-05-17 16:35:41 +02:00
}
bool message_item::text_matches(const std::u32string& text) const
{
return m_text.text == text;
}
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);
}
}
2023-02-01 21:04:08 +01:00
compiled_resource& message_item::get_compiled()
2022-05-17 16:35:41 +02:00
{
if (!m_processed)
2022-05-17 16:35:41 +02:00
{
2023-02-01 21:04:08 +01:00
compiled_resources = {};
return compiled_resources;
2022-05-17 16:35:41 +02:00
}
// Disable caching
is_compiled = false;
compiled_resources = rounded_rect::get_compiled();
compiled_resources.add(m_text.get_compiled());
2023-02-01 21:04:08 +01:00
if (m_icon)
{
compiled_resources.add(m_icon->get_compiled());
}
2022-05-17 16:35:41 +02:00
auto& current_animation = m_fade_in_animation.active
? m_fade_in_animation
: m_fade_out_animation;
current_animation.apply(compiled_resources);
2023-02-01 21:04:08 +01:00
return compiled_resources;
2022-05-17 16:35:41 +02:00
}
void message_item::update(usz index, u64 time, u16 y_offset)
2022-05-17 16:35:41 +02:00
{
if (m_cur_pos != index)
{
m_cur_pos = index;
set_pos(10, y_offset);
2022-05-17 16:35:41 +02:00
}
2023-02-01 21:04:08 +01:00
if (!m_processed)
{
m_expiration_time = get_expiration_time(m_visible_duration);
}
if (m_fade_in_animation.active)
{
// We are fading in.
m_fade_in_animation.update(rsx::get_current_renderer()->vblank_count);
}
else if (time + u64(m_fade_out_animation.duration * 1'000'000) > get_expiration())
2022-05-17 16:35:41 +02:00
{
// We are fading out.
// Only activate the animation if the message hasn't expired yet (prevents glitches afterwards).
if (time <= get_expiration())
{
m_fade_out_animation.active = true;
}
m_fade_out_animation.update(rsx::get_current_renderer()->vblank_count);
2022-05-17 16:35:41 +02:00
}
else if (m_fade_out_animation.active)
{
// We are fading out, but the expiration was extended.
// Reset the fade in animation to the state of the fade out animation to prevent opacity pop.
const usz current_frame = rsx::get_current_renderer()->vblank_count;
const f32 fade_out_progress = static_cast<f32>(m_fade_out_animation.get_remaining_frames(current_frame)) / static_cast<f32>(m_fade_out_animation.get_duration_in_frames());
const u64 fade_in_frames_done = u64(fade_out_progress * m_fade_in_animation.get_duration_in_frames());
m_fade_in_animation.reset(current_frame - fade_in_frames_done);
m_fade_in_animation.active = true;
m_fade_in_animation.update(current_frame);
// Reset the fade out animation.
m_fade_out_animation.reset();
}
2022-05-17 16:35:41 +02:00
m_processed = true;
}
void message::update_queue(std::deque<message_item>& vis_set, std::deque<message_item>& ready_set, message_pin_location origin)
2022-05-17 16:35:41 +02:00
{
2023-02-01 21:04:08 +01:00
const u64 cur_time = rsx::uclock();
for (auto it = vis_set.begin(); it != vis_set.end();)
2022-05-17 16:35:41 +02:00
{
if (it->get_expiration() < cur_time)
{
it = vis_set.erase(it);
}
else
{
it++;
}
2022-05-17 16:35:41 +02:00
}
2023-02-01 21:04:08 +01:00
while (vis_set.size() < max_visible_items && !ready_set.empty())
2022-05-17 16:35:41 +02:00
{
2023-02-01 21:04:08 +01:00
vis_set.emplace_back(std::move(ready_set.front()));
ready_set.pop_front();
2022-05-17 16:35:41 +02:00
}
2023-02-03 01:43:14 +01:00
if (vis_set.empty())
2022-05-17 16:35:41 +02:00
{
return;
}
// Render reversed list. Oldest entries are furthest from the border
2023-02-03 01:43:14 +01:00
constexpr u16 spacing = 4;
u16 y_offset = 8, index = 0;
for (auto it = vis_set.rbegin(); it != vis_set.rend(); ++it, ++index)
2022-05-17 16:35:41 +02:00
{
if (origin == message_pin_location::top) [[ likely ]]
{
it->update(index, cur_time, y_offset);
2023-02-03 01:43:14 +01:00
y_offset += (spacing + it->h);
}
else
{
2023-02-03 01:43:14 +01:00
y_offset += (spacing + it->h);
it->update(index, cur_time, virtual_height - y_offset);
}
2022-05-17 16:35:41 +02:00
}
}
2023-02-01 21:04:08 +01:00
void message::update()
{
if (!visible)
{
return;
}
std::lock_guard lock(m_mutex_queue);
2023-02-03 01:31:09 +01:00
update_queue(m_visible_items_top, m_ready_queue_top, message_pin_location::top);
update_queue(m_visible_items_bottom, m_ready_queue_bottom, message_pin_location::bottom);
2023-02-01 21:04:08 +01:00
2023-02-03 01:31:09 +01:00
visible = !m_visible_items_top.empty() || !m_visible_items_bottom.empty();
2023-02-01 21:04:08 +01:00
}
2022-05-17 16:35:41 +02:00
compiled_resource message::get_compiled()
{
if (!visible)
{
return {};
}
std::lock_guard lock(m_mutex_queue);
compiled_resource cr{};
2023-02-03 01:31:09 +01:00
for (auto& item : m_visible_items_top)
2023-02-01 21:04:08 +01:00
{
cr.add(item.get_compiled());
}
2023-02-03 01:31:09 +01:00
for (auto& item : m_visible_items_bottom)
2022-05-17 16:35:41 +02:00
{
cr.add(item.get_compiled());
}
return cr;
}
bool message::message_exists(message_pin_location location, localized_string_id id, bool allow_refresh)
{
return message_exists(location, get_localized_u32string(id), allow_refresh);
}
bool message::message_exists(message_pin_location location, const std::string& msg, bool allow_refresh)
{
return message_exists(location, utf8_to_u32string(msg), allow_refresh);
}
bool message::message_exists(message_pin_location location, const std::u32string& msg, bool allow_refresh)
{
auto check_list = [&](std::deque<message_item>& list)
{
return std::any_of(list.begin(), list.end(), [&](message_item& item)
{
if (item.text_matches(msg))
{
if (allow_refresh)
{
item.reset_expiration();
}
return true;
}
return false;
});
};
switch (location)
{
case message_pin_location::top:
2023-02-03 01:31:09 +01:00
return check_list(m_ready_queue_top) || check_list(m_visible_items_top);
case message_pin_location::bottom:
2023-02-03 01:31:09 +01:00
return check_list(m_ready_queue_bottom) || check_list(m_visible_items_bottom);
}
2023-02-03 01:43:14 +01:00
return false;
}
void refresh_message_queue()
{
if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
{
if (auto msg_overlay = manager->get<rsx::overlays::message>())
{
msg_overlay->refresh();
}
}
}
2022-05-17 16:35:41 +02:00
} // namespace overlays
} // namespace rsx