mirror of
https://github.com/stenzek/duckstation.git
synced 2026-02-04 05:04:33 +00:00
ImGuiManager: Support non-font icons in OSD
This commit is contained in:
@@ -36,6 +36,7 @@ add_library(util
|
||||
http_downloader.h
|
||||
image.cpp
|
||||
image.h
|
||||
imgui_gsvector.h
|
||||
imgui_manager.cpp
|
||||
imgui_manager.h
|
||||
ini_settings_interface.cpp
|
||||
|
||||
35
src/util/imgui_gsvector.h
Normal file
35
src/util/imgui_gsvector.h
Normal file
@@ -0,0 +1,35 @@
|
||||
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/gsvector.h"
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_internal.h"
|
||||
|
||||
inline ImVec2 GSVectorToImVec2(const GSVector2& vec)
|
||||
{
|
||||
alignas(VECTOR_ALIGNMENT) ImVec2 ret;
|
||||
GSVector2::store<true>(&ret.x, vec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline GSVector2 ImVec2ToGSVector(const ImVec2& vec)
|
||||
{
|
||||
return GSVector2::load<false>(&vec.x);
|
||||
}
|
||||
|
||||
inline ImRect GSVectorToImRect(const GSVector4& vec)
|
||||
{
|
||||
// GSVector4 maps directly to ImRect's memory layout.
|
||||
static_assert(sizeof(ImRect) == sizeof(GSVector4));
|
||||
alignas(VECTOR_ALIGNMENT) ImRect ret;
|
||||
GSVector4::store<true>(&ret.Min.x, vec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline GSVector4 ImRectToGSVector(const ImRect& rect)
|
||||
{
|
||||
return GSVector4::load<false>(&rect.Min.x);
|
||||
}
|
||||
@@ -76,6 +76,7 @@ struct OSDMessage
|
||||
float target_y;
|
||||
float last_y;
|
||||
OSDMessageType type;
|
||||
bool is_texture_icon;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -884,7 +885,14 @@ void ImGuiManager::AcquirePendingOSDMessages(Timer::Value current_time)
|
||||
break;
|
||||
|
||||
PostedOSDMessage& new_msg = s_state.osd_posted_messages.front();
|
||||
|
||||
// MaxCount is used to indicate removal of a message.
|
||||
const float duration = (new_msg.type < OSDMessageType::MaxCount) ? GetOSDMessageDuration(new_msg.type) : 0.0f;
|
||||
|
||||
// Any filenames are going to have an extension of at least 4 bytes (e.g. ".png"), so we can use that
|
||||
// to determine if it's a texture or not.
|
||||
const bool is_texture_icon = StringUtil::GetUTF8CharacterCount(new_msg.icon) >= 4;
|
||||
|
||||
std::deque<OSDMessage>::iterator iter;
|
||||
if (!new_msg.key.empty() &&
|
||||
(iter = std::find_if(s_state.osd_active_messages.begin(), s_state.osd_active_messages.end(),
|
||||
@@ -899,6 +907,7 @@ void ImGuiManager::AcquirePendingOSDMessages(Timer::Value current_time)
|
||||
iter->text = std::move(new_msg.text);
|
||||
iter->duration = duration;
|
||||
iter->type = new_msg.type;
|
||||
iter->is_texture_icon = is_texture_icon;
|
||||
|
||||
// Don't fade it in again
|
||||
const float time_passed = static_cast<float>(Timer::ConvertValueToSeconds(current_time - iter->start_time));
|
||||
@@ -926,6 +935,7 @@ void ImGuiManager::AcquirePendingOSDMessages(Timer::Value current_time)
|
||||
.target_y = -1.0f,
|
||||
.last_y = -1.0f,
|
||||
.type = new_msg.type,
|
||||
.is_texture_icon = is_texture_icon,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -985,9 +995,18 @@ void ImGuiManager::DrawOSDMessages(Timer::Value current_time)
|
||||
// Use larger icon when we have multiple lines.
|
||||
const bool use_large_icon = !msg.title.empty() && !msg.text.empty();
|
||||
const float icon_font_size = use_large_icon ? large_icon_size : font_size;
|
||||
const ImVec2 icon_size = msg.icon.empty() ? ImVec2() :
|
||||
font->CalcTextSizeA(icon_font_size, body_font_weight, FLT_MAX, 0.0f,
|
||||
IMSTR_START_END(msg.icon));
|
||||
GPUTexture* icon_texture =
|
||||
msg.is_texture_icon ?
|
||||
FullscreenUI::GetCachedTexture(msg.icon, static_cast<u32>(icon_font_size), static_cast<u32>(icon_font_size)) :
|
||||
nullptr;
|
||||
const ImVec2 icon_size =
|
||||
msg.icon.empty() ?
|
||||
ImVec2() :
|
||||
(msg.is_texture_icon ?
|
||||
ImVec2(icon_font_size *
|
||||
(static_cast<float>(icon_texture->GetWidth()) / static_cast<float>(icon_texture->GetHeight())),
|
||||
icon_font_size) :
|
||||
font->CalcTextSizeA(icon_font_size, body_font_weight, FLT_MAX, 0.0f, IMSTR_START_END(msg.icon)));
|
||||
const float icon_size_with_margin =
|
||||
msg.icon.empty() ? 0.0f : (icon_size.x + (use_large_icon ? large_icon_margin : normal_icon_margin));
|
||||
const float max_text_width = max_width - icon_size_with_margin;
|
||||
@@ -1079,7 +1098,12 @@ void ImGuiManager::DrawOSDMessages(Timer::Value current_time)
|
||||
|
||||
const ImVec2 base_pos = ImVec2(pos.x + padding, pos.y + padding);
|
||||
const ImU32 color = ImGui::GetColorU32(ModAlpha(text_color, opacity));
|
||||
if (!msg.icon.empty())
|
||||
if (icon_texture)
|
||||
{
|
||||
dl->AddImage(icon_texture, base_pos, base_pos + icon_size, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f),
|
||||
ImGui::GetColorU32(ModAlpha(0xFFFFFFFFu, opacity)));
|
||||
}
|
||||
else if (!msg.icon.empty())
|
||||
{
|
||||
const ImRect icon_rect = ImRect(base_pos, base_pos + icon_size);
|
||||
RenderShadowedTextClipped(dl, font, icon_font_size, body_font_weight, icon_rect.Min, icon_rect.Max, color,
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
<ClInclude Include="gpu_texture.h" />
|
||||
<ClInclude Include="host.h" />
|
||||
<ClInclude Include="http_downloader.h" />
|
||||
<ClInclude Include="imgui_gsvector.h" />
|
||||
<ClInclude Include="imgui_manager.h" />
|
||||
<ClInclude Include="ini_settings_interface.h" />
|
||||
<ClInclude Include="input_manager.h" />
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
<ClInclude Include="dyn_spirv_cross.h" />
|
||||
<ClInclude Include="spirv_module.h" />
|
||||
<ClInclude Include="postprocessing_shader_slang.h" />
|
||||
<ClInclude Include="imgui_gsvector.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="state_wrapper.cpp" />
|
||||
|
||||
Reference in New Issue
Block a user