mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2026-04-27 04:41:39 +00:00
Implement outlines.
This commit is contained in:
parent
bbe869c25f
commit
82aee0951a
10 changed files with 55 additions and 66 deletions
|
|
@ -17,6 +17,7 @@ enum class ImGuiCallback : int32_t
|
||||||
SetOrigin = -3,
|
SetOrigin = -3,
|
||||||
SetScale = -4,
|
SetScale = -4,
|
||||||
SetMarqueeFade = -5,
|
SetMarqueeFade = -5,
|
||||||
|
SetOutline = -6,
|
||||||
// -8 is ImDrawCallback_ResetRenderState, don't use!
|
// -8 is ImDrawCallback_ResetRenderState, don't use!
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -50,6 +51,11 @@ union ImGuiCallbackData
|
||||||
float boundsMin[2];
|
float boundsMin[2];
|
||||||
float boundsMax[2];
|
float boundsMax[2];
|
||||||
} setMarqueeFade;
|
} setMarqueeFade;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
float outline;
|
||||||
|
} setOutline;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern ImGuiCallbackData* AddImGuiCallback(ImGuiCallback callback);
|
extern ImGuiCallbackData* AddImGuiCallback(ImGuiCallback callback);
|
||||||
|
|
|
||||||
|
|
@ -205,7 +205,7 @@ static bool FontBuilder_Build(ImFontAtlas* atlas)
|
||||||
packer.dimensionsConstraint = msdf_atlas::DimensionsConstraint::POWER_OF_TWO_RECTANGLE;
|
packer.dimensionsConstraint = msdf_atlas::DimensionsConstraint::POWER_OF_TWO_RECTANGLE;
|
||||||
packer.minScale = 24.0;
|
packer.minScale = 24.0;
|
||||||
packer.miterLimit = 1.0;
|
packer.miterLimit = 1.0;
|
||||||
packer.pxRange = 4.0;
|
packer.pxRange = 8.0;
|
||||||
packer.pack(glyphs.data(), glyphs.size(), customRects.data(), customRects.size());
|
packer.pack(glyphs.data(), glyphs.size(), customRects.data(), customRects.size());
|
||||||
|
|
||||||
for (size_t i = 0; i < customRects.size(); i++)
|
for (size_t i = 0; i < customRects.size(); i++)
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ struct PushConstants
|
||||||
float2 InverseDisplaySize;
|
float2 InverseDisplaySize;
|
||||||
float2 Origin;
|
float2 Origin;
|
||||||
float2 Scale;
|
float2 Scale;
|
||||||
|
float Outline;
|
||||||
};
|
};
|
||||||
|
|
||||||
Texture2D<float4> g_Texture2DDescriptorHeap[] : register(t0, space0);
|
Texture2D<float4> g_Texture2DDescriptorHeap[] : register(t0, space0);
|
||||||
|
|
|
||||||
|
|
@ -73,21 +73,6 @@ float4 PixelAntialiasing(float2 uvTexspace)
|
||||||
return SampleLinear(uvTexspace);
|
return SampleLinear(uvTexspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint GetTexture2DDescriptorIndex()
|
|
||||||
{
|
|
||||||
return g_PushConstants.Texture2DDescriptorIndex & 0x7FFFFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
float ComputeScreenPixelRange(float2 texCoord)
|
|
||||||
{
|
|
||||||
uint width, height;
|
|
||||||
g_Texture2DDescriptorHeap[GetTexture2DDescriptorIndex()].GetDimensions(width, height);
|
|
||||||
|
|
||||||
float2 unitRange = 4.0 / float2(width, height);
|
|
||||||
float2 screenTextureSize = 1.0 / fwidth(texCoord);
|
|
||||||
return max(0.5 * dot(unitRange, screenTextureSize), 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float median(float r, float g, float b)
|
float median(float r, float g, float b)
|
||||||
{
|
{
|
||||||
return max(min(r, g), min(max(r, g), b));
|
return max(min(r, g), min(max(r, g), b));
|
||||||
|
|
@ -100,17 +85,28 @@ float4 main(in Interpolators interpolators) : SV_Target
|
||||||
|
|
||||||
if (g_PushConstants.Texture2DDescriptorIndex != 0)
|
if (g_PushConstants.Texture2DDescriptorIndex != 0)
|
||||||
{
|
{
|
||||||
float4 texture = g_Texture2DDescriptorHeap[GetTexture2DDescriptorIndex()].Sample(g_SamplerDescriptorHeap[0], interpolators.UV);
|
Texture2D<float4> texture = g_Texture2DDescriptorHeap[g_PushConstants.Texture2DDescriptorIndex & 0x7FFFFFFF];
|
||||||
|
float4 textureColor = texture.Sample(g_SamplerDescriptorHeap[0], interpolators.UV);
|
||||||
|
|
||||||
if ((g_PushConstants.Texture2DDescriptorIndex & 0x80000000) != 0)
|
if ((g_PushConstants.Texture2DDescriptorIndex & 0x80000000) != 0)
|
||||||
{
|
{
|
||||||
float sd = median(texture.r, texture.g, texture.b) - 0.5;
|
uint width, height;
|
||||||
float screenPixelDistance = ComputeScreenPixelRange(interpolators.UV) * sd;
|
texture.GetDimensions(width, height);
|
||||||
color.a *= saturate(screenPixelDistance + 0.5);
|
|
||||||
color.a *= texture.a;
|
float pxRange = 8.0;
|
||||||
|
float2 unitRange = pxRange / float2(width, height);
|
||||||
|
float2 screenTexSize = 1.0 / fwidth(interpolators.UV);
|
||||||
|
float screenPxRange = max(0.5 * dot(unitRange, screenTexSize), 1.0);
|
||||||
|
|
||||||
|
float sd = median(textureColor.r, textureColor.g, textureColor.b) - 0.5;
|
||||||
|
float screenPxDistance = screenPxRange * (sd + g_PushConstants.Outline / (pxRange * 2.0));
|
||||||
|
|
||||||
|
color.a *= saturate(screenPxDistance + 0.5);
|
||||||
|
color.a *= textureColor.a;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
color *= texture;
|
color *= textureColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1108,6 +1108,7 @@ struct ImGuiPushConstants
|
||||||
ImVec2 inverseDisplaySize{};
|
ImVec2 inverseDisplaySize{};
|
||||||
ImVec2 origin{ 0.0f, 0.0f };
|
ImVec2 origin{ 0.0f, 0.0f };
|
||||||
ImVec2 scale{ 1.0f, 1.0f };
|
ImVec2 scale{ 1.0f, 1.0f };
|
||||||
|
float outline{};
|
||||||
};
|
};
|
||||||
|
|
||||||
extern ImFontBuilderIO g_fontBuilderIO;
|
extern ImFontBuilderIO g_fontBuilderIO;
|
||||||
|
|
@ -1952,6 +1953,9 @@ static void ProcDrawImGui(const RenderCommand& cmd)
|
||||||
case ImGuiCallback::SetMarqueeFade:
|
case ImGuiCallback::SetMarqueeFade:
|
||||||
setPushConstants(&pushConstants.boundsMin, &callbackData->setMarqueeFade, sizeof(callbackData->setMarqueeFade));
|
setPushConstants(&pushConstants.boundsMin, &callbackData->setMarqueeFade, sizeof(callbackData->setMarqueeFade));
|
||||||
break;
|
break;
|
||||||
|
case ImGuiCallback::SetOutline:
|
||||||
|
setPushConstants(&pushConstants.outline, &callbackData->setOutline, sizeof(callbackData->setOutline));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert(false && "Unknown ImGui callback type.");
|
assert(false && "Unknown ImGui callback type.");
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -141,14 +141,14 @@ static void DrawHeaderContainer(const char* text)
|
||||||
SetTextSkew((min.y + max.y) / 2.0f, Scale(3.0f));
|
SetTextSkew((min.y + max.y) / 2.0f, Scale(3.0f));
|
||||||
|
|
||||||
// TODO: Apply bevel.
|
// TODO: Apply bevel.
|
||||||
DrawTextWithOutline<float>
|
DrawTextWithOutline
|
||||||
(
|
(
|
||||||
g_fntNewRodinUB,
|
g_fntNewRodinUB,
|
||||||
fontSize,
|
fontSize,
|
||||||
{ /* X */ min.x + textMarginX, /* Y */ CENTRE_TEXT_VERT(min, max, textSize) - Scale(5) },
|
{ /* X */ min.x + textMarginX, /* Y */ CENTRE_TEXT_VERT(min, max, textSize) - Scale(5) },
|
||||||
IM_COL32(255, 255, 255, 255 * alpha),
|
IM_COL32(255, 255, 255, 255 * alpha),
|
||||||
text,
|
text,
|
||||||
1.65f,
|
4,
|
||||||
IM_COL32(0, 0, 0, 255 * alpha)
|
IM_COL32(0, 0, 0, 255 * alpha)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -349,7 +349,7 @@ static void DrawAchievement(int rowIndex, float yOffset, Achievement& achievemen
|
||||||
);
|
);
|
||||||
|
|
||||||
// Draw timestamp text.
|
// Draw timestamp text.
|
||||||
DrawTextWithOutline<int>
|
DrawTextWithOutline
|
||||||
(
|
(
|
||||||
g_fntNewRodinDB,
|
g_fntNewRodinDB,
|
||||||
fontSize,
|
fontSize,
|
||||||
|
|
@ -523,7 +523,7 @@ static void DrawAchievementTotal(ImVec2 min, ImVec2 max)
|
||||||
auto fontSize = Scale(20);
|
auto fontSize = Scale(20);
|
||||||
auto textSize = g_fntNewRodinDB->CalcTextSizeA(fontSize, FLT_MAX, 0, str.c_str());
|
auto textSize = g_fntNewRodinDB->CalcTextSizeA(fontSize, FLT_MAX, 0, str.c_str());
|
||||||
|
|
||||||
DrawTextWithOutline<int>
|
DrawTextWithOutline
|
||||||
(
|
(
|
||||||
g_fntNewRodinDB,
|
g_fntNewRodinDB,
|
||||||
fontSize,
|
fontSize,
|
||||||
|
|
|
||||||
|
|
@ -188,7 +188,7 @@ static void DrawGuide(float* offset, ImVec2 regionMin, ImVec2 regionMax, EButton
|
||||||
|
|
||||||
ImVec2 textPosition = { textMarginX, textMarginY };
|
ImVec2 textPosition = { textMarginX, textMarginY };
|
||||||
|
|
||||||
DrawTextWithOutline<int>(font, fontSize, textPosition, IM_COL32_WHITE, text, 2, IM_COL32_BLACK);
|
DrawTextWithOutline(font, fontSize, textPosition, IM_COL32_WHITE, text, 2, IM_COL32_BLACK);
|
||||||
|
|
||||||
// Add extra luminance to low quality text.
|
// Add extra luminance to low quality text.
|
||||||
if (fontQuality == EFontQuality::Low)
|
if (fontQuality == EFontQuality::Low)
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,17 @@ static void ResetMarqueeFade()
|
||||||
SetScale({ 1.0f, 1.0f });
|
SetScale({ 1.0f, 1.0f });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void SetOutline(float outline)
|
||||||
|
{
|
||||||
|
auto callbackData = AddImGuiCallback(ImGuiCallback::SetOutline);
|
||||||
|
callbackData->setOutline.outline = outline;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ResetOutline()
|
||||||
|
{
|
||||||
|
SetOutline(0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
// Aspect ratio aware.
|
// Aspect ratio aware.
|
||||||
static float Scale(float size)
|
static float Scale(float size)
|
||||||
{
|
{
|
||||||
|
|
@ -179,41 +190,13 @@ static void DrawTextWithMarquee(const ImFont* font, float fontSize, const ImVec2
|
||||||
drawList->PopClipRect();
|
drawList->PopClipRect();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
static void DrawTextWithOutline(const ImFont* font, float fontSize, const ImVec2& pos, ImU32 color, const char* text, float outlineSize, ImU32 outlineColor)
|
||||||
static void DrawTextWithOutline(const ImFont* font, float fontSize, const ImVec2& pos, ImU32 color, const char* text, T outlineSize, ImU32 outlineColor)
|
|
||||||
{
|
{
|
||||||
auto drawList = ImGui::GetForegroundDrawList();
|
auto drawList = ImGui::GetForegroundDrawList();
|
||||||
|
|
||||||
outlineSize = Scale(outlineSize);
|
SetOutline(outlineSize);
|
||||||
|
drawList->AddText(font, fontSize, pos, outlineColor, text);
|
||||||
if constexpr (std::is_same_v<float, T> || std::is_same_v<double, T>)
|
ResetOutline();
|
||||||
{
|
|
||||||
auto step = outlineSize / 2.0f;
|
|
||||||
|
|
||||||
// TODO: This is still very inefficient!
|
|
||||||
for (float i = -outlineSize; i <= outlineSize; i += step)
|
|
||||||
{
|
|
||||||
for (float j = -outlineSize; j <= outlineSize; j += step)
|
|
||||||
{
|
|
||||||
if (i == 0.0f && j == 0.0f)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
drawList->AddText(font, fontSize, { pos.x + i, pos.y + j }, outlineColor, text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if constexpr (std::is_integral_v<T>)
|
|
||||||
{
|
|
||||||
// TODO: This is very inefficient!
|
|
||||||
for (int32_t i = -outlineSize + 1; i < outlineSize; i++)
|
|
||||||
{
|
|
||||||
for (int32_t j = -outlineSize + 1; j < outlineSize; j++)
|
|
||||||
{
|
|
||||||
if (i != 0 || j != 0)
|
|
||||||
drawList->AddText(font, fontSize, { pos.x + i, pos.y + j }, outlineColor, text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
drawList->AddText(font, fontSize, pos, color, text);
|
drawList->AddText(font, fontSize, pos, color, text);
|
||||||
}
|
}
|
||||||
|
|
@ -223,9 +206,8 @@ static void DrawTextWithShadow(const ImFont* font, float fontSize, const ImVec2&
|
||||||
auto drawList = ImGui::GetForegroundDrawList();
|
auto drawList = ImGui::GetForegroundDrawList();
|
||||||
|
|
||||||
offset = Scale(offset);
|
offset = Scale(offset);
|
||||||
radius = Scale(radius);
|
|
||||||
|
|
||||||
DrawTextWithOutline<float>(font, fontSize, { pos.x + offset, pos.y + offset }, shadowColour, text, radius, shadowColour);
|
DrawTextWithOutline(font, fontSize, { pos.x + offset, pos.y + offset }, shadowColour, text, radius, shadowColour);
|
||||||
|
|
||||||
drawList->AddText(font, fontSize, pos, colour, text, nullptr);
|
drawList->AddText(font, fontSize, pos, colour, text, nullptr);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -559,7 +559,7 @@ static void DrawScanlineBars()
|
||||||
// Installer text
|
// Installer text
|
||||||
const std::string &headerText = Localise(g_currentPage == WizardPage::Installing ? "Installer_Header_Installing" : "Installer_Header_Installer");
|
const std::string &headerText = Localise(g_currentPage == WizardPage::Installing ? "Installer_Header_Installing" : "Installer_Header_Installer");
|
||||||
int textAlpha = std::lround(255.0f * ComputeMotionInstaller(g_appearTime, g_disappearTime, TITLE_ANIMATION_TIME, TITLE_ANIMATION_DURATION));
|
int textAlpha = std::lround(255.0f * ComputeMotionInstaller(g_appearTime, g_disappearTime, TITLE_ANIMATION_TIME, TITLE_ANIMATION_DURATION));
|
||||||
DrawTextWithOutline<int>(g_dfsogeistdFont, Scale(42.0f), { Scale(285.0f), Scale(57.0f) }, IM_COL32(255, 195, 0, textAlpha), headerText.c_str(), 4, IM_COL32(0, 0, 0, textAlpha));
|
DrawTextWithOutline(g_dfsogeistdFont, Scale(42.0f), { Scale(285.0f), Scale(57.0f) }, IM_COL32(255, 195, 0, textAlpha), headerText.c_str(), 4, IM_COL32(0, 0, 0, textAlpha));
|
||||||
|
|
||||||
// Top bar line
|
// Top bar line
|
||||||
drawList->AddLine
|
drawList->AddLine
|
||||||
|
|
@ -761,7 +761,7 @@ static void DrawButton(ImVec2 min, ImVec2 max, const char *buttonText, bool sour
|
||||||
IM_COL32(baser + 128, baseg + 170, 0, 255)
|
IM_COL32(baser + 128, baseg + 170, 0, 255)
|
||||||
);
|
);
|
||||||
|
|
||||||
DrawTextWithOutline<int>
|
DrawTextWithOutline
|
||||||
(
|
(
|
||||||
font,
|
font,
|
||||||
size,
|
size,
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@ static void DrawScanlineBars()
|
||||||
|
|
||||||
// Options text
|
// Options text
|
||||||
// TODO: localise this.
|
// TODO: localise this.
|
||||||
DrawTextWithOutline<int>(g_dfsogeistdFont, Scale(48.0f), { Scale(122.0f), Scale(56.0f) }, IM_COL32(255, 195, 0, 255), "OPTIONS", 4, IM_COL32_BLACK);
|
DrawTextWithOutline(g_dfsogeistdFont, Scale(48.0f), { Scale(122.0f), Scale(56.0f) }, IM_COL32(255, 195, 0, 255), "OPTIONS", 4, IM_COL32_BLACK);
|
||||||
|
|
||||||
// Top bar line
|
// Top bar line
|
||||||
drawList->AddLine
|
drawList->AddLine
|
||||||
|
|
@ -389,7 +389,7 @@ static bool DrawCategories()
|
||||||
IM_COL32(255, 192, 0, alpha)
|
IM_COL32(255, 192, 0, alpha)
|
||||||
);
|
);
|
||||||
|
|
||||||
DrawTextWithOutline<int>
|
DrawTextWithOutline
|
||||||
(
|
(
|
||||||
g_dfsogeistdFont,
|
g_dfsogeistdFont,
|
||||||
size,
|
size,
|
||||||
|
|
@ -755,7 +755,7 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
|
||||||
IM_COL32(128, 170, 0, 255)
|
IM_COL32(128, 170, 0, 255)
|
||||||
);
|
);
|
||||||
|
|
||||||
DrawTextWithOutline<int>
|
DrawTextWithOutline
|
||||||
(
|
(
|
||||||
g_newRodinFont,
|
g_newRodinFont,
|
||||||
size,
|
size,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue