Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
1b99c30
Full Icon framework & support.
davo0411 May 31, 2025
3507e94
UI Text helper function for better looking large text
davo0411 May 31, 2025
35fcac9
Update Menu.cpp
davo0411 May 31, 2025
5ee980c
Update src/UIIconLoader.cpp
davo0411 May 31, 2025
ab879df
Update src/UIIconLoader.cpp
davo0411 May 31, 2025
ab7d837
Icon folder changes, fix for compile issue.
davo0411 Jun 1, 2025
c2747f4
Reorganise
davo0411 Jun 15, 2025
3b67b36
Update README.md
davo0411 Jun 15, 2025
0954e5a
fixes
davo0411 Jun 15, 2025
681dc30
Merge branch 'Icons' of https://github.com/davo0411/skyrim-community-…
davo0411 Jun 15, 2025
3ce7198
rabbit suggested fixes
davo0411 Jun 15, 2025
a5e9cab
fix
davo0411 Jun 15, 2025
2369e17
Merge branch 'dev' into Icons
davo0411 Jun 15, 2025
fed8c36
style: 🎨 apply pre-commit.ci formatting
pre-commit-ci[bot] Jun 15, 2025
f01c2a1
build fix
davo0411 Jun 16, 2025
4896741
Fixes
davo0411 Jun 16, 2025
9333086
Update Menu.cpp
davo0411 Jun 16, 2025
899d691
style: 🎨 apply pre-commit.ci formatting
pre-commit-ci[bot] Jun 16, 2025
248e4a5
Licence tweaks
davo0411 Jun 16, 2025
9e9a69e
Merge branch 'Icons' of https://github.com/davo0411/skyrim-community-…
davo0411 Jun 16, 2025
7a0ca4b
Comment clean & Mipmap fixes
davo0411 Jun 16, 2025
f239dc4
Texture memory leak cleanup
davo0411 Jun 16, 2025
3400e53
fixes
davo0411 Jun 16, 2025
7504d4f
style: 🎨 apply pre-commit.ci formatting
pre-commit-ci[bot] Jun 16, 2025
2687359
Merge branch 'dev' into Icons
davo0411 Jun 18, 2025
c452cbe
style: 🎨 apply pre-commit.ci formatting
pre-commit-ci[bot] Jun 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,8 @@ See LICENSE within each directory; if none, it's [Default](#default)

- [Features Shaders](features)
- [Package Shaders](package/Shaders/)

### Icons

- [Microsoft Icons](package/Interface/CommunityShaders/Icons/Microsoft%20Icons/) are subject to the [MIT License](package/Interface/CommunityShaders/Icons/Microsoft%20Icons/LICENSE) https://github.com/microsoft/fluentui-system-icons
- [Community Shaders Logo](package/Interface/CommunityShaders/Icons/Community%20Shaders%20Logo/) is not covered by the GPL-3.0 license. It is provided solely for personal use (e.g., building from source) and may only be used in unmodified form. There is no license for any other purpose or to distribute the logo. No trademark license is granted for the logo. Any use not expressly permitted is prohibited without the express written consent of the Community Shaders team.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions package/Interface/CommunityShaders/Icons/Microsoft Icons/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2020 Microsoft Corporation

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
302 changes: 245 additions & 57 deletions src/Menu.cpp

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions src/Menu.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,35 @@ class Menu
void ProcessInputEvents(RE::InputEvent* const* a_events);
bool ShouldSwallowInput();
void OnFocusLost();
// UI icon textures
struct UIIcon
{
ID3D11ShaderResourceView* texture = nullptr;
ImVec2 size = ImVec2(32.0f, 32.0f);

void Release()
{
if (texture) {
texture->Release();
texture = nullptr;
}
}
};
struct UIIcons
{
UIIcon saveSettings;
UIIcon loadSettings;
UIIcon clearCache;
UIIcon clearDiskCache;
UIIcon logo; // New logo icon
} uiIcons;

struct ThemeSettings
{
float GlobalScale = REL::Module::IsVR() ? -0.5f : 0.f; // exponential

bool UseSimplePalette = true; // simple palette or full customization
bool ShowActionIcons = true; // whether to show action buttons as icons
struct PaletteColors
{
ImVec4 Background{ 0.f, 0.f, 0.f, 0.5882353186607361f };
Expand Down
248 changes: 245 additions & 3 deletions src/Utils/UI.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
#include "UI.h"
#include "Menu.h"

#include <d3d11.h>
#include <imgui.h>
#include <imgui_internal.h>

#include "../Globals.h"
#include "../Menu.h"

#define STB_IMAGE_IMPLEMENTATION
#include <cmath>
#include <stb_image.h>

namespace Util
{
PerformanceOverlay performanceOverlay;
Expand Down Expand Up @@ -47,7 +58,241 @@ namespace Util
const auto Size = ImGui::GetMainViewport()->Size;
return { Size.x * scale, Size.y * scale };
}
// Icon loading functions (moved from UIIconLoader)
bool LoadTextureFromFile(ID3D11Device* device,
const char* filename,
ID3D11ShaderResourceView** out_srv,
ImVec2& out_size)
{
// Validate input parameters
if (!device || !out_srv) {
logger::warn("LoadTextureFromFile: Invalid parameters - device: {}, out_srv: {}",
device ? "valid" : "null", out_srv ? "valid" : "null");
return false;
}

// Initialize output to nullptr
*out_srv = nullptr;

logger::debug("LoadTextureFromFile: Attempting to load {}", filename);

// Load from disk into a raw RGBA buffer
int image_width = 0;
int image_height = 0;
int channels_in_file;
unsigned char* image_data = stbi_load(filename, &image_width, &image_height, &channels_in_file, 4);
if (image_data == NULL) {
logger::warn("LoadTextureFromFile: Failed to load image data from {}", filename);
return false;
}
// Creates Textures for Icons with Mipmapping to support high DPI displays.
logger::debug("LoadTextureFromFile: Loaded image {}x{} with {} channels from {}",
image_width, image_height, channels_in_file, filename);
D3D11_TEXTURE2D_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Width = image_width;
desc.Height = image_height;
desc.MipLevels = 1; // Start with just one mip level
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
desc.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS;
desc.CPUAccessFlags = 0;

ID3D11Texture2D* pTexture = nullptr;
D3D11_SUBRESOURCE_DATA subResource;
subResource.pSysMem = image_data;
subResource.SysMemPitch = desc.Width * 4;
subResource.SysMemSlicePitch = 0;

HRESULT hr = device->CreateTexture2D(&desc, &subResource, &pTexture);
if (FAILED(hr) || !pTexture) {
logger::warn("LoadTextureFromFile: Failed to create D3D11 texture, HRESULT: 0x{:08X}", static_cast<uint32_t>(hr));
stbi_image_free(image_data);
return false;
}
// Create simple shader resource view
hr = device->CreateShaderResourceView(pTexture, nullptr, out_srv);
if (FAILED(hr) || !*out_srv) {
logger::warn("LoadTextureFromFile: Failed to create shader resource view, HRESULT: 0x{:08X}", static_cast<uint32_t>(hr));
pTexture->Release();
stbi_image_free(image_data);
*out_srv = nullptr;
return false;
}

// Generate mipmaps for better icon quality at different scales
ID3D11DeviceContext* context = nullptr;
device->GetImmediateContext(&context);
if (context) {
context->GenerateMips(*out_srv);
context->Release();
}
// Success - clean up intermediate resources
pTexture->Release();
stbi_image_free(image_data);

out_size = ImVec2((float)image_width, (float)image_height);
logger::debug("LoadTextureFromFile: Successfully loaded {} ({}x{})", filename, image_width, image_height);
return true;
}
bool InitializeMenuIcons(Menu* menu)
{
if (!menu) {
logger::warn("InitializeMenuIcons: Menu pointer is null");
return false;
}

// Get the D3D device from globals
ID3D11Device* device = globals::d3d::device;
if (!device) {
logger::warn("InitializeMenuIcons: D3D device is null");
return false;
}
// Define path to icons
std::string basePath = "Data\\Interface\\CommunityShaders\\Icons\\";
logger::info("InitializeMenuIcons: Loading icons from base path: {}", basePath);

// Initialize all texture pointers to nullptr for safe cleanup
std::array<ID3D11ShaderResourceView**, 5> texturePointers = {
&menu->uiIcons.saveSettings.texture,
&menu->uiIcons.loadSettings.texture,
&menu->uiIcons.clearCache.texture,
&menu->uiIcons.clearDiskCache.texture,
&menu->uiIcons.logo.texture
};

// Safely release existing textures
for (auto* texturePtr : texturePointers) {
if (*texturePtr) {
(*texturePtr)->Release();
*texturePtr = nullptr;
}
}

// Instead of failing completely if one icon fails, try to load each one individually
bool anyIconLoaded = false;
int iconsLoaded = 0;

// Load save settings icon
if (LoadTextureFromFile(device, (basePath + "Microsoft Icons\\save-settings.png").c_str(), &menu->uiIcons.saveSettings.texture, menu->uiIcons.saveSettings.size)) {
logger::info("InitializeMenuIcons: Successfully loaded save-settings icon");
iconsLoaded++;
anyIconLoaded = true;
} else {
logger::warn("InitializeMenuIcons: Failed to load save-settings icon from: {}", basePath + "Microsoft Icons\\save-settings.png");
}

// Load load settings icon
if (LoadTextureFromFile(device, (basePath + "Microsoft Icons\\load-settings.png").c_str(), &menu->uiIcons.loadSettings.texture, menu->uiIcons.loadSettings.size)) {
logger::info("InitializeMenuIcons: Successfully loaded load-settings icon");
iconsLoaded++;
anyIconLoaded = true;
} else {
logger::warn("InitializeMenuIcons: Failed to load load-settings icon from: {}", basePath + "Microsoft Icons\\load-settings.png");
}

// Load clear cache icon
if (LoadTextureFromFile(device, (basePath + "Microsoft Icons\\clear-cache.png").c_str(), &menu->uiIcons.clearCache.texture, menu->uiIcons.clearCache.size)) {
logger::info("InitializeMenuIcons: Successfully loaded clear-cache icon");
iconsLoaded++;
anyIconLoaded = true;
} else {
logger::warn("InitializeMenuIcons: Failed to load clear-cache icon from: {}", basePath + "Microsoft Icons\\clear-cache.png");
}

// Load clear disk cache icon
if (LoadTextureFromFile(device, (basePath + "Microsoft Icons\\clear-disk.png").c_str(), &menu->uiIcons.clearDiskCache.texture, menu->uiIcons.clearDiskCache.size)) {
logger::info("InitializeMenuIcons: Successfully loaded clear-disk icon");
iconsLoaded++;
anyIconLoaded = true;
} else {
logger::warn("InitializeMenuIcons: Failed to load clear-disk icon from: {}", basePath + "Microsoft Icons\\clear-disk.png");
}

// Load logo icon
if (LoadTextureFromFile(device, (basePath + "Community Shaders Logo\\cs-logo.png").c_str(), &menu->uiIcons.logo.texture, menu->uiIcons.logo.size)) {
logger::info("InitializeMenuIcons: Successfully loaded logo icon");
iconsLoaded++;
anyIconLoaded = true;
} else {
logger::warn("InitializeMenuIcons: Failed to load logo icon from: {}", basePath + "Community Shaders Logo\\cs-logo.png");
}

logger::info("InitializeMenuIcons: Loaded {}/5 icons successfully", iconsLoaded);
return anyIconLoaded;
}

// Text rendering helpers (moved from UITextHelper)
ImVec2 DrawSharpText(const char* text, bool alignToPixelGrid, float scale)
{
ImVec2 startPos = ImGui::GetCursorPos();

if (alignToPixelGrid) {
// Get current position
ImVec2 pos = ImGui::GetCursorPos();

// Align to pixel grid for sharper rendering
pos.x = std::round(pos.x);
pos.y = std::round(pos.y);

// Set aligned position
ImGui::SetCursorPos(pos);
}
// Apply scale if needed
if (scale != 1.0f) {
ImGui::SetWindowFontScale(scale);
}

// Use Text instead of TextUnformatted for better rendering
ImGui::Text("%s", text);
// Restore original scale if needed
if (scale != 1.0f)
ImGui::SetWindowFontScale(1.0f);

// Calculate and return the rendered size
ImVec2 endPos = ImGui::GetCursorPos();
return ImVec2(endPos.x - startPos.x, endPos.y - startPos.y);
}

ImVec2 DrawAlignedTextWithLogo(ID3D11ShaderResourceView* logoTexture, const ImVec2& logoSize, const char* text, float textScale)
{
// Save current cursor position
ImVec2 startPos = ImGui::GetCursorPos();

// Calculate scaled text height
float fontHeight = ImGui::GetFontSize() * textScale;
float logoHeight = logoSize.y;

// Calculate vertical offset to center align logo with text
float verticalOffset = (fontHeight - logoHeight) * 0.5f;

// Position cursor for logo with vertical alignment
ImGui::SetCursorPos(ImVec2(startPos.x, startPos.y + verticalOffset));

// Render logo
ImGui::Image(logoTexture, logoSize);
ImGui::SameLine();

// Reset cursor for text with proper vertical alignment
ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPosX(), startPos.y));
// Use windowed font scale for sharper text
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
ImGui::SetWindowFontScale(textScale);

// Render text aligned to pixel grid for sharpness
ImGui::Text("%s", text);
// Restore style
ImGui::SetWindowFontScale(1.0f);
ImGui::PopStyleVar();

// Calculate and return the total rendered size
ImVec2 endPos = ImGui::GetCursorPos();
return ImVec2(endPos.x - startPos.x, endPos.y - startPos.y);
}
// StyledButtonWrapper implementation
StyledButtonWrapper::StyledButtonWrapper(const ImVec4& normalColor, const ImVec4& hoveredColor, const ImVec4& activeColor) :
m_pushedStyles(0)
Expand Down Expand Up @@ -81,9 +326,6 @@ namespace Util
ImGui::TextWrapped("%s", description);
ImGui::Spacing();
}

// Note: For this simplified version, we don't use TreeNode
// The sections are always expanded in FeatureIssues UI
}

SectionWrapper::~SectionWrapper()
Expand Down
22 changes: 21 additions & 1 deletion src/Utils/UI.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
#pragma once

#include <imgui.h>

// Forward declarations
struct ID3D11Device;
struct ID3D11ShaderResourceView;
struct ImVec2;
class Menu;

namespace Util
{
// Text rendering constants
constexpr float DefaultHeaderTextScale = 1.5f; // Larger scale for header text to improve readability

/**
* Usage:
Expand Down Expand Up @@ -110,6 +117,19 @@ namespace Util
bool PercentageSlider(const char* label, float* data, float lb = 0.f, float ub = 100.f, const char* format = "%.1f %%");
ImVec2 GetNativeViewportSizeScaled(float scale);

// Icon loading functions
// `device` must remain alive for the SRV lifetime. Caller owns *out_srv and must `Release()` it.
bool LoadTextureFromFile(ID3D11Device* device,
const char* filename,
ID3D11ShaderResourceView** out_srv,
ImVec2& out_size);
bool InitializeMenuIcons(Menu* menu);

// Text rendering helpers for clearer title text
// These functions modify ImGui rendering state and should be called within ImGui context
ImVec2 DrawSharpText(const char* text, bool alignToPixelGrid = true, float scale = 1.0f);
ImVec2 DrawAlignedTextWithLogo(ID3D11ShaderResourceView* logoTexture, const ImVec2& logoSize, const char* text, float textScale = DefaultHeaderTextScale);

/**
* Draws a custom styled collapsible category header with lines extending from both sides
* @param categoryName The name of the category to display
Expand Down
1 change: 1 addition & 0 deletions vcpkg.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"magic-enum",
"nlohmann-json",
"pystring",
"stb",
"tracy",
"unordered-dense",
"xbyak"
Expand Down