rsx/overlays: Implement tabbed containers

This commit is contained in:
kd-11 2026-03-01 17:17:42 +03:00 committed by kd-11
parent 7859a5f9d2
commit 5cb688f309
9 changed files with 442 additions and 161 deletions

View file

@ -517,6 +517,7 @@ target_sources(rpcs3_emu PRIVATE
RSX/Overlays/overlay_perf_metrics.cpp
RSX/Overlays/overlay_progress_bar.cpp
RSX/Overlays/overlay_save_dialog.cpp
RSX/Overlays/overlay_tabs.cpp
RSX/Overlays/overlay_trophy_notification.cpp
RSX/Overlays/overlay_user_list_dialog.cpp
RSX/Overlays/overlay_utils.cpp

View file

@ -579,43 +579,49 @@ namespace rsx
compiled_resource& overlay_element::get_compiled()
{
if (!is_compiled())
if (is_compiled())
{
compiled_resources.clear();
return compiled_resources;
}
compiled_resource compiled_resources_temp = {};
auto& cmd_bg = compiled_resources_temp.append({});
auto& config = cmd_bg.config;
m_is_compiled = true;
compiled_resources.clear();
config.color = back_color;
config.pulse_glow = pulse_effect_enabled;
config.pulse_sinus_offset = pulse_sinus_offset;
config.pulse_speed_modifier = pulse_speed_modifier;
if (!is_visible())
{
return compiled_resources;
}
auto& verts = compiled_resources_temp.draw_commands.front().verts;
verts.resize(4);
compiled_resource compiled_resources_temp = {};
auto& cmd_bg = compiled_resources_temp.append({});
auto& config = cmd_bg.config;
verts[0].vec4(x, y, 0.f, 0.f);
verts[1].vec4(f32(x + w), y, 1.f, 0.f);
verts[2].vec4(x, f32(y + h), 0.f, 1.f);
verts[3].vec4(f32(x + w), f32(y + h), 1.f, 1.f);
config.color = back_color;
config.pulse_glow = pulse_effect_enabled;
config.pulse_sinus_offset = pulse_sinus_offset;
config.pulse_speed_modifier = pulse_speed_modifier;
compiled_resources.add(std::move(compiled_resources_temp), margin_left, margin_top);
auto& verts = compiled_resources_temp.draw_commands.front().verts;
verts.resize(4);
if (!text.empty())
{
compiled_resources_temp.clear();
auto& cmd_text = compiled_resources_temp.append({});
verts[0].vec4(x, y, 0.f, 0.f);
verts[1].vec4(f32(x + w), y, 1.f, 0.f);
verts[2].vec4(x, f32(y + h), 0.f, 1.f);
verts[3].vec4(f32(x + w), f32(y + h), 1.f, 1.f);
cmd_text.config.set_font(get_font());
cmd_text.config.color = fore_color;
cmd_text.verts = render_text(text.c_str(), static_cast<f32>(x), static_cast<f32>(y));
compiled_resources.add(std::move(compiled_resources_temp), margin_left, margin_top);
if (!cmd_text.verts.empty())
compiled_resources.add(std::move(compiled_resources_temp), margin_left - horizontal_scroll_offset, margin_top - vertical_scroll_offset);
}
if (!text.empty())
{
compiled_resources_temp.clear();
auto& cmd_text = compiled_resources_temp.append({});
m_is_compiled = true;
cmd_text.config.set_font(get_font());
cmd_text.config.color = fore_color;
cmd_text.verts = render_text(text.c_str(), static_cast<f32>(x), static_cast<f32>(y));
if (!cmd_text.verts.empty())
compiled_resources.add(std::move(compiled_resources_temp), margin_left - horizontal_scroll_offset, margin_top - vertical_scroll_offset);
}
return compiled_resources;
@ -722,6 +728,13 @@ namespace rsx
add_element(spacer_element);
}
void layout_container::clear_items()
{
m_items.clear();
advance_pos = 0;
scroll_offset_value = 0;
}
overlay_element* vertical_layout::add_element(std::unique_ptr<overlay_element>& item, int offset)
{
if (auto_resize)
@ -888,27 +901,36 @@ namespace rsx
compiled_resource& image_view::get_compiled()
{
if (!is_compiled())
if (is_compiled())
{
auto& result = overlay_element::get_compiled();
auto& cmd_img = result.draw_commands.front();
cmd_img.config.set_image_resource(image_resource_ref);
cmd_img.config.color = fore_color;
cmd_img.config.external_data_ref = external_ref;
cmd_img.config.blur_strength = blur_strength;
// Make padding work for images (treat them as the content instead of the 'background')
auto& verts = cmd_img.verts;
verts[0] += vertex(padding_left, padding_bottom, 0, 0);
verts[1] += vertex(-padding_right, padding_bottom, 0, 0);
verts[2] += vertex(padding_left, -padding_top, 0, 0);
verts[3] += vertex(-padding_right, -padding_top, 0, 0);
m_is_compiled = true;
return compiled_resources;
}
compiled_resources.clear();
if (!is_visible())
{
m_is_compiled = true;
return compiled_resources;
}
auto& result = overlay_element::get_compiled();
auto& cmd_img = result.draw_commands.front();
cmd_img.config.set_image_resource(image_resource_ref);
cmd_img.config.color = fore_color;
cmd_img.config.external_data_ref = external_ref;
cmd_img.config.blur_strength = blur_strength;
// Make padding work for images (treat them as the content instead of the 'background')
auto& verts = cmd_img.verts;
verts[0] += vertex(padding_left, padding_bottom, 0, 0);
verts[1] += vertex(-padding_right, padding_bottom, 0, 0);
verts[2] += vertex(padding_left, -padding_top, 0, 0);
verts[3] += vertex(-padding_right, -padding_top, 0, 0);
m_is_compiled = true;
return compiled_resources;
}
@ -961,29 +983,40 @@ namespace rsx
compiled_resource& image_button::get_compiled()
{
if (!is_compiled())
if (is_compiled())
{
auto& compiled = image_view::get_compiled();
for (auto& cmd : compiled.draw_commands)
return compiled_resources;
}
compiled_resources.clear();
if (!is_visible())
{
m_is_compiled = true;
return compiled_resources;
}
auto& compiled = image_view::get_compiled();
for (auto& cmd : compiled.draw_commands)
{
if (cmd.config.texture_ref == image_resource_id::font_file)
{
if (cmd.config.texture_ref == image_resource_id::font_file)
// Text, translate geometry to the right
for (auto &v : cmd.verts)
{
// Text, translate geometry to the right
for (auto &v : cmd.verts)
{
v.values[0] += m_text_offset_x;
v.values[1] += m_text_offset_y;
}
v.values[0] += m_text_offset_x;
v.values[1] += m_text_offset_y;
}
}
}
m_is_compiled = true;
return compiled_resources;
}
label::label(const std::string& text)
label::label(std::string_view text)
{
set_text(text);
set_text(text.data());
}
bool label::auto_resize(bool grow_only, u16 limit_w, u16 limit_h)
@ -1013,90 +1046,97 @@ namespace rsx
compiled_resource& rounded_rect::get_compiled()
{
if (!is_compiled())
if (is_compiled())
{
compiled_resources.clear();
#ifdef __APPLE__
if (true)
#else
if (radius == 0 || radius > (w / 2))
#endif
{
// 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.disable_vertex_snap = true;
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), 0.f, 0.f);
bg2.verts.emplace_back(f32(x + w) - radius, f32(y + h), 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);
}
m_is_compiled = true;
return compiled_resources;
}
compiled_resources.clear();
if (!is_visible())
{
m_is_compiled = true;
return compiled_resources;
}
#ifdef __APPLE__
if (true)
#else
if (radius == 0 || radius > (w / 2))
#endif
{
// Invalid radius
compiled_resources = overlay_element::get_compiled();
m_is_compiled = true;
return compiled_resources;
}
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.disable_vertex_snap = true;
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), 0.f, 0.f);
bg2.verts.emplace_back(f32(x + w) - radius, f32(y + h), 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);
m_is_compiled = true;
return compiled_resources;
}
}

View file

@ -219,6 +219,8 @@ namespace rsx
virtual compiled_resource& get_compiled();
void measure_text(u16& width, u16& height, bool ignore_word_wrap = false) const;
virtual void set_selected(bool selected) { static_cast<void>(selected); }
virtual void set_visible(bool visible) { this->visible = visible; m_is_compiled = false; }
virtual bool is_visible() const { return visible; }
protected:
bool m_is_compiled = false; // Only use m_is_compiled as a getter in is_compiled() if possible
@ -233,6 +235,7 @@ namespace rsx
bool auto_resize = true;
virtual overlay_element* add_element(std::unique_ptr<overlay_element>&, int = -1) = 0;
void clear_items();
layout_container();
@ -320,7 +323,7 @@ namespace rsx
struct label : public overlay_element
{
label() = default;
label(const std::string& text);
label(std::string_view text);
bool auto_resize(bool grow_only = false, u16 limit_w = -1, u16 limit_h = -1);
};

View file

@ -18,8 +18,8 @@ namespace rsx
m_cancel_btn = std::make_unique<image_button>(120, 20);
m_highlight_box = std::make_unique<overlay_element>(width, 0);
m_scroll_indicator_top->set_size(width, 40);
m_scroll_indicator_bottom->set_size(width, 40);
m_scroll_indicator_top->set_size(width, 10);
m_scroll_indicator_bottom->set_size(width, 10);
m_accept_btn->set_size(120, 30);
m_cancel_btn->set_size(120, 30);
@ -37,7 +37,7 @@ namespace rsx
m_cancel_btn->set_image_resource(resource_config::standard_image_resource::circle);
}
m_scroll_indicator_bottom->set_pos(0, height - 40);
m_scroll_indicator_bottom->set_pos(0, height - 10);
m_accept_btn->set_pos(30, height + 20);
if (can_deny)
@ -199,6 +199,37 @@ namespace rsx
return m_selected_entry;
}
void list_view::hide_prompt_buttons(bool hidden)
{
m_accept_btn->set_visible(!hidden);
m_cancel_btn->set_visible(!hidden);
if (m_deny_btn)
{
m_deny_btn->set_visible(!hidden);
}
refresh();
}
void list_view::hide_scroll_indicators(bool hidden)
{
m_scroll_indicator_top->set_visible(!hidden);
m_scroll_indicator_bottom->set_visible(!hidden);
m_highlight_box->set_visible(!hidden);
refresh();
}
void list_view::disable_selection_pulse(bool disabled)
{
m_highlight_box->pulse_effect_enabled = !disabled;
m_highlight_box->set_sinus_offset(1.5f);
m_highlight_box->refresh();
refresh();
}
void list_view::set_cancel_only(bool cancel_only)
{
if (cancel_only)
@ -209,7 +240,7 @@ namespace rsx
m_cancel_btn->set_pos(x + 180, y + h + 20);
m_cancel_only = cancel_only;
m_is_compiled = false;
refresh();
}
bool list_view::get_cancel_only() const
@ -233,27 +264,39 @@ namespace rsx
compiled_resource& list_view::get_compiled()
{
if (!is_compiled())
if (is_compiled())
{
auto& compiled = vertical_layout::get_compiled();
compiled.add(m_highlight_box->get_compiled());
compiled.add(m_scroll_indicator_top->get_compiled());
compiled.add(m_scroll_indicator_bottom->get_compiled());
compiled.add(m_cancel_btn->get_compiled());
if (!m_cancel_only)
{
compiled.add(m_accept_btn->get_compiled());
if (m_deny_btn)
{
compiled.add(m_deny_btn->get_compiled());
}
}
compiled_resources = compiled;
return compiled_resources;
}
compiled_resources.clear();
if (!is_visible())
{
m_is_compiled = true;
return compiled_resources;
}
auto& compiled = vertical_layout::get_compiled();
compiled.add(m_highlight_box->get_compiled());
compiled.add(m_scroll_indicator_top->get_compiled());
compiled.add(m_scroll_indicator_bottom->get_compiled());
compiled.add(m_cancel_btn->get_compiled());
if (m_cancel_only)
{
m_is_compiled = true;
return compiled_resources;
}
compiled.add(m_accept_btn->get_compiled());
if (m_deny_btn)
{
compiled.add(m_deny_btn->get_compiled());
}
m_is_compiled = true;
return compiled_resources;
}
} // namespace overlays

View file

@ -39,6 +39,10 @@ namespace rsx
bool get_cancel_only() const;
const overlay_element* get_selected_entry() const;
void hide_prompt_buttons(bool hidden = true);
void hide_scroll_indicators(bool hidden = true);
void disable_selection_pulse(bool disabled = true);
void set_cancel_only(bool cancel_only);
void translate(s16 _x, s16 _y) override;

View file

@ -0,0 +1,142 @@
#include "stdafx.h"
#include "overlay_tabs.h"
namespace rsx::overlays
{
tabbed_container::tabbed_container(u16 header_width)
: m_headers_width(header_width)
{
auto_resize = false;
}
overlay_element* tabbed_container::add_element(std::unique_ptr<overlay_element>& item, int offset)
{
return horizontal_layout::add_element(item, offset);
}
void tabbed_container::add_tab(std::string_view title, std::shared_ptr<overlay_element>& panel)
{
std::unique_ptr<overlay_element> label_widget = std::make_unique<label>(title);
label_widget->set_size(m_headers_width, 60);
label_widget->set_font("Arial", 18);
label_widget->back_color.a = 0.f;
label_widget->set_padding(16, 4, 16, 4);
add_tab(label_widget, panel);
}
void tabbed_container::add_tab(std::unique_ptr<overlay_element>& header, std::shared_ptr<overlay_element>& panel)
{
if (!m_tab_headers)
{
reflow_layout();
}
m_tab_headers->add_entry(header);
auto current = panel.get();
m_tab_contents.push_back(std::move(panel));
set_current_tab(current);
}
void tabbed_container::set_size(u16 width, u16 height)
{
horizontal_layout::set_size(width, height);
reflow_layout();
}
void tabbed_container::set_headers_width(u16 size)
{
m_headers_width = size;
m_tab_headers = nullptr;
horizontal_layout::clear_items();
reflow_layout();
}
void tabbed_container::set_headers_pulse_effect(bool pulse)
{
if (!m_tab_headers)
{
return;
}
m_tab_headers->disable_selection_pulse(!pulse);
}
void tabbed_container::set_current_tab(overlay_element* view)
{
compiled_resources.clear();
m_is_compiled = false;
m_current_view = view;
reflow_layout();
}
void tabbed_container::reflow_layout()
{
if (m_headers_width > w)
{
// Invalid config
return;
}
if (!m_tab_headers)
{
std::unique_ptr<overlay_element> tab_headers = std::make_unique<list_view>(m_headers_width, h, false);
auto ptr = horizontal_layout::add_element(tab_headers);
m_tab_headers = ensure(dynamic_cast<list_view*>(ptr));
m_tab_headers->set_pos(x, y);
m_tab_headers->hide_prompt_buttons();
m_tab_headers->back_color.a = 0.95f;
}
if (m_current_view)
{
m_current_view->set_pos(x + m_headers_width, y);
m_current_view->set_size(w - m_headers_width, h);
}
}
overlay_element* tabbed_container::set_selected_tab(u32 index)
{
if (index >= ::size32(m_tab_contents))
{
return nullptr;
}
auto view = m_tab_contents[index].get();
set_current_tab(view);
m_selected_idx = index;
m_tab_headers->select_entry(static_cast<s32>(index));
return view;
}
overlay_element* tabbed_container::get_selected() const
{
return m_current_view;
}
u32 tabbed_container::get_selected_idx() const
{
return m_selected_idx;
}
compiled_resource& tabbed_container::get_compiled()
{
// TODO: Caching
compiled_resources.clear();
if (m_tab_headers)
{
compiled_resources.add(m_tab_headers->get_compiled());
}
if (m_current_view)
{
compiled_resources.add(m_current_view->get_compiled());
}
m_is_compiled = true;
return compiled_resources;
}
}

View file

@ -0,0 +1,40 @@
#pragma once
#include "overlays.h"
#include "overlay_list_view.hpp"
namespace rsx::overlays
{
struct tabbed_container : public horizontal_layout
{
tabbed_container(u16 header_width = 0);
void add_tab(std::string_view title, std::shared_ptr<overlay_element>& panel);
void add_tab(std::unique_ptr<overlay_element>& header, std::shared_ptr<overlay_element>& panel);
virtual void set_size(u16 _w, u16 _h) override;
virtual void set_headers_width(u16 size);
virtual void set_headers_pulse_effect(bool pulse);
overlay_element* set_selected_tab(u32 index);
overlay_element* get_selected() const;
u32 get_selected_idx() const;
compiled_resource& get_compiled() override;
protected:
void reflow_layout();
void set_current_tab(overlay_element* view);
overlay_element* add_element(std::unique_ptr<overlay_element>& item, int offset = -1) override;
private:
list_view* m_tab_headers = nullptr;
std::vector<std::shared_ptr<overlay_element>> m_tab_contents;
overlay_element* m_current_view = nullptr;
u16 m_headers_width = 0;
u32 m_selected_idx = umax;
};
}

View file

@ -153,6 +153,7 @@
<ClCompile Include="Emu\RSX\Overlays\overlay_media_list_dialog.cpp" />
<ClCompile Include="Emu\RSX\Overlays\overlay_osk_panel.cpp" />
<ClCompile Include="Emu\RSX\Overlays\overlay_compile_notification.cpp" />
<ClCompile Include="Emu\RSX\Overlays\overlay_tabs.cpp" />
<ClCompile Include="Emu\RSX\Overlays\overlay_user_list_dialog.cpp" />
<ClCompile Include="Emu\RSX\Overlays\overlay_utils.cpp" />
<ClCompile Include="Emu\RSX\Overlays\overlay_video.cpp" />
@ -714,6 +715,7 @@
<ClInclude Include="Emu\RSX\Overlays\overlay_manager.h" />
<ClInclude Include="Emu\RSX\Overlays\overlay_media_list_dialog.h" />
<ClInclude Include="Emu\RSX\Overlays\overlay_progress_bar.hpp" />
<ClInclude Include="Emu\RSX\Overlays\overlay_tabs.h" />
<ClInclude Include="Emu\RSX\Overlays\overlay_video.h" />
<ClInclude Include="Emu\RSX\Overlays\Trophies\overlay_trophy_list_dialog.h" />
<ClInclude Include="Emu\RSX\Program\Assembler\CFG.h" />

View file

@ -1414,6 +1414,9 @@
<ClCompile Include="Emu\RSX\Overlays\overlay_audio.cpp">
<Filter>Emu\GPU\RSX\Overlays</Filter>
</ClCompile>
<ClCompile Include="Emu\RSX\Overlays\overlay_tabs.cpp">
<Filter>Emu\GPU\RSX\Overlays</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Crypto\aes.h">
@ -2839,6 +2842,9 @@
<ClInclude Include="Emu\RSX\Overlays\overlay_audio.h">
<Filter>Emu\GPU\RSX\Overlays</Filter>
</ClInclude>
<ClInclude Include="Emu\RSX\Overlays\overlay_tabs.h">
<Filter>Emu\GPU\RSX\Overlays</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="Emu\RSX\Program\GLSLSnippets\GPUDeswizzle.glsl">