mirror of
https://github.com/kamb205/KB-RPCS3.git
synced 2026-10-18 11:00:52 +02:00
192 lines
6.0 KiB
C++
192 lines
6.0 KiB
C++
/*
|
|
* PS5 Vulkan Template - Themes: the title's look, picked from the UI kit's thirty.
|
|
*
|
|
* The start screen's Themes. The themes in a list, the screen drawn in the one
|
|
* the focus is on: its backdrop, its list, and a panel of the kit's widgets in
|
|
* it. CROSS makes it the title's theme (ps5ui::set_active_theme), which styles
|
|
* the start screen, the Samples menu and the samples' settings windows; CIRCLE
|
|
* goes back to the start screen.
|
|
*
|
|
* Copyright (C) 2026 Mihawk
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*/
|
|
|
|
#include "kit.hpp"
|
|
|
|
namespace {
|
|
|
|
using hui::gfx::Rect;
|
|
|
|
class ThemePicker : public ps5ui::KitExample
|
|
{
|
|
public:
|
|
bool done{ false };
|
|
hui::ui::ListView list;
|
|
hui::gfx::DrawList scene;
|
|
hui::ui::Feedback feedback;
|
|
float clock{ 0.0f };
|
|
float applied{ 0.0f }; // seconds left of the "now in use" note
|
|
|
|
ThemePicker()
|
|
{
|
|
title = PS5_TITLE_NAME;
|
|
name = "themes";
|
|
settings.overlay = false;
|
|
ps5.ownOverlay = true;
|
|
}
|
|
|
|
const hui::ui::Theme &focused() const
|
|
{
|
|
return hui::ui::themes()[list.focus()];
|
|
}
|
|
|
|
void syncRows()
|
|
{
|
|
const int active = ps5ui::active_theme_index();
|
|
for (int i = 0; i < (int)hui::ui::themes().size(); i++) {
|
|
list.item(i).badge = i == active ? "IN USE" : "";
|
|
}
|
|
}
|
|
|
|
void prepare() override
|
|
{
|
|
VulkanExampleBase::prepare();
|
|
prepareKit({ .music = false, .covers = false });
|
|
std::vector<hui::ui::ListItem> rows;
|
|
for (const hui::ui::Theme &theme : hui::ui::themes()) {
|
|
hui::ui::ListItem item;
|
|
item.title = theme.name;
|
|
item.subtitle = theme.family;
|
|
rows.push_back(item);
|
|
}
|
|
list.style.panel = true;
|
|
list.style.row_height = 76.0f;
|
|
list.style.title_size = 26.0f;
|
|
list.style.subtitle_size = 18.0f;
|
|
list.set_items(rows);
|
|
list.set_bounds({ 120.0f, 230.0f, 620.0f, 760.0f });
|
|
list.set_focus(std::max(0, ps5ui::active_theme_index()));
|
|
list.style.theme = focused();
|
|
syncRows();
|
|
list.enter();
|
|
prepared = true;
|
|
}
|
|
|
|
void update(float dt)
|
|
{
|
|
feedback.clear();
|
|
hui::InputFrame input = kit.input();
|
|
if (ps5.frameBudget) {
|
|
input = kit.scripted("themes", ps5.framesDrawn);
|
|
}
|
|
clock += dt;
|
|
applied = std::max(0.0f, applied - dt);
|
|
const hui::ui::Event event = list.handle(input, feedback);
|
|
if (event == hui::ui::Event::activated) {
|
|
ps5ui::set_active_theme(list.focus());
|
|
syncRows();
|
|
applied = 2.5f;
|
|
feedback.play(hui::audio::Cue::saved);
|
|
} else if (event == hui::ui::Event::cancelled || input.is_pressed(hui::Action::back)) {
|
|
done = true;
|
|
}
|
|
// The whole screen wears the theme the focus is on
|
|
list.style.theme = focused();
|
|
list.update(dt);
|
|
kit.play(feedback, focused().sounds);
|
|
kit.tick(dt);
|
|
}
|
|
|
|
void compose()
|
|
{
|
|
const hui::ui::Theme &theme = focused();
|
|
const uint32_t glass = kit.renderer.glass_texture();
|
|
scene.clear();
|
|
hui::ui::Canvas canvas{ scene, kit.fonts, glass, clock };
|
|
hui::ui::Painter paint(scene, kit.fonts, theme, glass);
|
|
paint.heading("Themes", 120.0f, 150.0f, 64.0f, paint.page_text());
|
|
paint.body("The title's look: the start screen, the Samples menu and the samples' settings",
|
|
122.0f, 196.0f, 22.0f, paint.page_text_muted());
|
|
char count[32];
|
|
snprintf(count, sizeof(count), "%02d / %02d", list.focus() + 1, (int)hui::ui::themes().size());
|
|
paint.label(count, 1800.0f, 150.0f, 24.0f, paint.page_text_muted(), hui::gfx::Align::right);
|
|
list.draw(canvas);
|
|
|
|
// The kit's widgets in the theme, as a sample's settings would wear them
|
|
const Rect panel{ 820.0f, 230.0f, 980.0f, 640.0f };
|
|
paint.panel(panel);
|
|
const float x = panel.x + 48.0f;
|
|
paint.heading(theme.name, x, panel.y + 84.0f, 48.0f, theme.text);
|
|
paint.body(theme.summary, x, panel.y + 128.0f, 22.0f, theme.text_muted);
|
|
const char *tabs[] = { "Scene", "Lights", "Camera" };
|
|
paint.tabs({ x, panel.y + 170.0f, 520.0f, 56.0f }, tabs, 0.0f, {});
|
|
paint.label("Shadows", x, panel.y + 290.0f, 24.0f, theme.text);
|
|
paint.toggle({ panel.x + panel.w - 48.0f - 92.0f, panel.y + 262.0f, 92.0f, 44.0f }, 1.0f, {});
|
|
paint.label("Exposure", x, panel.y + 370.0f, 24.0f, theme.text);
|
|
paint.slider({ x + 220.0f, panel.y + 346.0f, panel.w - 96.0f - 220.0f, 44.0f }, 0.62f, {});
|
|
paint.checkbox({ x, panel.y + 420.0f, 40.0f, 40.0f }, 1.0f, {});
|
|
paint.body("Bloom", x + 60.0f, panel.y + 450.0f, 24.0f, theme.text);
|
|
paint.radio({ x + 260.0f, panel.y + 420.0f, 40.0f, 40.0f }, 1.0f, {});
|
|
paint.body("MSAA 4x", x + 320.0f, panel.y + 450.0f, 24.0f, theme.text);
|
|
paint.chip({ x + 520.0f, panel.y + 418.0f, 150.0f, 44.0f }, "Ray query", 1.0f, {});
|
|
paint.button({ x, panel.y + panel.h - 112.0f, 260.0f, 64.0f }, "Apply", hui::ui::ButtonKind::primary, { 1.0f, 0.0f, false });
|
|
paint.button({ x + 290.0f, panel.y + panel.h - 112.0f, 220.0f, 64.0f }, "Reset", hui::ui::ButtonKind::secondary, {});
|
|
if (applied > 0.0f) {
|
|
paint.label("Now the title's theme", panel.x + panel.w - 48.0f, panel.y + panel.h - 70.0f, 24.0f,
|
|
theme.success, hui::gfx::Align::right);
|
|
}
|
|
ps5ui::draw_hints(scene, kit.fonts, theme,
|
|
{ { hui::ui::Button::dpad, "Move" }, { hui::ui::Button::cross, "Use this theme" }, { hui::ui::Button::circle, "Back" } }, 120.0f, 1040.0f);
|
|
|
|
hui::gfx::BackdropSpec backdrop = theme.backdrop;
|
|
backdrop.time = clock;
|
|
kit.renderer.begin();
|
|
kit.renderer.backdrop(backdrop);
|
|
kit.renderer.glass(); // glass themes frost their panels with the backdrop
|
|
kit.renderer.draw(scene);
|
|
}
|
|
|
|
void render() override
|
|
{
|
|
if (!prepared) {
|
|
return;
|
|
}
|
|
prepareFrame();
|
|
update(std::min(frameTimer, 0.05f));
|
|
compose();
|
|
buildKitCommandBuffer();
|
|
submitFrame();
|
|
if (done) {
|
|
quit = true;
|
|
}
|
|
}
|
|
|
|
~ThemePicker() override
|
|
{
|
|
if (device) {
|
|
vkDeviceWaitIdle(device);
|
|
}
|
|
}
|
|
};
|
|
|
|
} // namespace
|
|
|
|
void ps5_run_theme_picker(uint32_t frameBudget, const std::string &screenshotPath)
|
|
{
|
|
ThemePicker *picker = new ThemePicker();
|
|
picker->benchmark.active = frameBudget > 0;
|
|
picker->ps5.frameBudget = frameBudget;
|
|
picker->ps5.screenshotPath = screenshotPath;
|
|
try {
|
|
picker->initVulkan();
|
|
picker->prepare();
|
|
picker->renderLoop();
|
|
} catch (const std::exception &e) {
|
|
say("themes: %s", e.what());
|
|
}
|
|
if (picker->vulkanDevice) {
|
|
vkDeviceWaitIdle(picker->vulkanDevice->logicalDevice);
|
|
}
|
|
delete picker;
|
|
}
|