Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions src/viewer/appState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ void AppState::CallStateCallbacks()
cmfLoadRequest.CallCallbacks( *this );
exitRequested.CallCallbacks( *this );
showUi.CallCallbacks( *this );
uiScale.CallCallbacks( *this );

modelState.CallCallbacks( *this );
}
Expand Down
3 changes: 3 additions & 0 deletions src/viewer/appState.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,9 @@ struct AppState

State<bool> exitRequested{ false };
State<bool> showUi{ true };
/// ui scale factor (see UiConsts::MIN_UI_SCALE / MAX_UI_SCALE)
State<float> uiScale{ 1.0f };
float defaultUiScale{ 1.0f };

// model
ModelState modelState{};
Expand Down
10 changes: 10 additions & 0 deletions src/viewer/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include "application.h"

#include <algorithm>
#include "rendering/ui/uiConsts.h"
#include "rendering/ui/uiSettings.h"
#include "rendering/vulkan/shadercache.h"
#include "rendering/vulkan/vulkanerrors.h"
#include "viewerIcon.h"
Expand Down Expand Up @@ -41,6 +43,13 @@ void Application::Initialize()
}
SetCarbonMeshViewerWindowIcon( m_window );

float contentScaleX = 1.0f;
float contentScaleY = 1.0f;
glfwGetWindowContentScale( m_window, &contentScaleX, &contentScaleY );
m_appState.defaultUiScale = std::clamp( contentScaleX, UiConsts::MIN_UI_SCALE, UiConsts::MAX_UI_SCALE );
Comment thread
JohnGreenFC marked this conversation as resolved.
m_appState.uiScale.SetValueNoCallback( m_appState.defaultUiScale );
Log::Info( "Monitor content scale is %.2f, initial ui scale %.2fx", contentScaleX, m_appState.defaultUiScale );

// we may ask for a given size (see above) but it is not guaranteed to be the actual framebuffer size
int actualHeight, actualWidth;
glfwGetFramebufferSize( m_window, &actualWidth, &actualHeight );
Expand Down Expand Up @@ -222,6 +231,7 @@ void Application::Run()
}
auto logicalDevice = m_renderer->GetDevice()->GetLogicalDevice();
vkDeviceWaitIdle( logicalDevice );
UiSettings::Save();
m_orientationGizmoRenderer.release();

m_sceneRenderer.release();
Expand Down
9 changes: 5 additions & 4 deletions src/viewer/rendering/ui/uiAnimationPlayback.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@

#include "uiCustomWidgets.h"

const float ANIMATION_SELECTION_WIDTH = 120.0f;
const float BASE_ANIMATION_SELECTION_WIDTH = 120.0f;

void UIAnimationPlayback::Render( AppState& appState )
{
UpdateState( appState );

const auto [width, height] = appState.windowSize.GetValue();

ImGui::SetNextWindowPos( ImVec2( 0, static_cast<float>( height ) - UiConsts::ANIMATION_PLAYER_HEIGHT ), ImGuiCond_Always );
ImGui::SetNextWindowSize( ImVec2( static_cast<float>( width ), UiConsts::ANIMATION_PLAYER_HEIGHT ), ImGuiCond_Always );
const float playerHeight = UiConsts::AnimationPlayerHeight();
ImGui::SetNextWindowPos( ImVec2( 0, static_cast<float>( height ) - playerHeight ), ImGuiCond_Always );
ImGui::SetNextWindowSize( ImVec2( static_cast<float>( width ), playerHeight ), ImGuiCond_Always );
if( ImGui::Begin( "##animationTitle", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize ) )
{
// animation selection
Expand Down Expand Up @@ -62,7 +63,7 @@ void UIAnimationPlayback::Render( AppState& appState )

ImGui::BeginDisabled( animationNames.empty() );

ImGui::PushItemWidth( ANIMATION_SELECTION_WIDTH );
ImGui::PushItemWidth( UiConsts::Scaled( BASE_ANIMATION_SELECTION_WIDTH ) );
ImGui::ComboBox( "##animation", animationNames, selectedAnimationIndex, [&]( int32_t selectedIndex ) {
m_playing = false;
m_currentTime = 0.0f;
Expand Down
49 changes: 42 additions & 7 deletions src/viewer/rendering/ui/uiConsts.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,45 @@

namespace UiConsts
{
const float MENU_BAR_HEIGHT = 18.0f;
const float ANIMATION_PLAYER_HEIGHT = 36.0f;
const float BUTTON_WIDTH = 19.0f;
const float BUTTON_HEIGHT = 19.0f;
const ImVec2 BUTTON_SIZE = ImVec2( BUTTON_WIDTH, BUTTON_HEIGHT );
const float FONT_AWESOME_SIZE = 13.0f;
}
const float MIN_UI_SCALE = 1.0f;
const float MAX_UI_SCALE = 3.0f;

// sizes at 1x, use the scaled accessors below
const float BASE_FONT_SIZE = 13.0f;
const float BASE_FONT_AWESOME_SIZE = 13.0f;
const float BASE_MENU_BAR_HEIGHT = 18.0f;
const float BASE_ANIMATION_PLAYER_HEIGHT = 36.0f;
const float BASE_BUTTON_WIDTH = 19.0f;
const float BASE_BUTTON_HEIGHT = 19.0f;

// the applied scale is whatever the font atlas was built with, so it is derived from the current font rather than stored
inline float Scaled( float baseSize )
{
return baseSize * ImGui::GetFontSize() / BASE_FONT_SIZE;
}

inline float FontAwesomeSize()
{
return Scaled( BASE_FONT_AWESOME_SIZE );
}
inline float MenuBarHeight()
{
return Scaled( BASE_MENU_BAR_HEIGHT );
}
inline float AnimationPlayerHeight()
{
return Scaled( BASE_ANIMATION_PLAYER_HEIGHT );
}
inline float ButtonWidth()
{
return Scaled( BASE_BUTTON_WIDTH );
}
inline float ButtonHeight()
{
return Scaled( BASE_BUTTON_HEIGHT );
}
inline ImVec2 ButtonSize()
{
return ImVec2( ButtonWidth(), ButtonHeight() );
}
}
12 changes: 6 additions & 6 deletions src/viewer/rendering/ui/uiCustomWidgets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ CheckBoxTriStateValue GetCheckedStatus( int64_t checked, int64_t count )

bool FontAwesomeButton( const FaIcon& icon, int id, float width, float height )
{
const float faButtonPadding = 4.0f;
const float glyphWidth = UiConsts::FONT_AWESOME_SIZE * icon.xyRatio;
const float faButtonPadding = UiConsts::Scaled( 4.0f );
const float glyphWidth = UiConsts::FontAwesomeSize() * icon.xyRatio;
const float paddingX = std::max( 0.0f, ( width - glyphWidth ) * 0.5f );
ImGui::PushStyleVar( ImGuiStyleVar_FramePadding, ImVec2( paddingX, faButtonPadding ) );
ImGui::PushID( id );
Expand All @@ -73,8 +73,8 @@ bool FontAwesomeButton( const FaIcon& icon, int id, float width, float height )

void FontAwesomeText( const FaIcon& icon, float width )
{
const float faButtonPadding = -4.0f;
const float glyphWidth = UiConsts::FONT_AWESOME_SIZE * icon.xyRatio;
const float faButtonPadding = UiConsts::Scaled( -4.0f );
const float glyphWidth = UiConsts::FontAwesomeSize() * icon.xyRatio;
const float paddingX = std::max( 0.0f, ( width - glyphWidth ) * 0.5f );
ImGui::PushStyleVar( ImGuiStyleVar_FramePadding, ImVec2( paddingX, faButtonPadding ) );
ImGui::TextUnformatted( icon.text );
Expand All @@ -86,12 +86,12 @@ bool FontAwesomeSlashedButton( const FaIcon& icon, int id, float width, float he
bool ret = ImGui::FontAwesomeButton( icon, id, width, height );
ImVec2 min = ImGui::GetItemRectMin();
ImVec2 max = ImGui::GetItemRectMax();
float slashPadding = 1.5f;
const float slashPadding = UiConsts::Scaled( 1.5f );
ImGui::GetWindowDrawList()->AddLine(
ImVec2( min.x + slashPadding, max.y - slashPadding ),
ImVec2( max.x - slashPadding, min.y + slashPadding ),
ImGui::GetColorU32( ImGuiCol_Text ),
2.0f );
UiConsts::Scaled( 2.0f ) );

return ret;
}
Expand Down
4 changes: 2 additions & 2 deletions src/viewer/rendering/ui/uiCustomWidgets.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ enum class CheckBoxTriStateValue
CheckBoxTriStateValue GetCheckedStatus( int64_t checked, int64_t count );

bool CheckBoxTristate( const char* label, CheckBoxTriStateValue* v_tristate );
bool FontAwesomeButton( const FaIcon& icon, int id = 0, float width = UiConsts::BUTTON_WIDTH, float height = UiConsts::BUTTON_HEIGHT );
bool FontAwesomeSlashedButton( const FaIcon& icon, int id = 0, float width = UiConsts::BUTTON_WIDTH, float height = UiConsts::BUTTON_HEIGHT );
bool FontAwesomeButton( const FaIcon& icon, int id = 0, float width = UiConsts::ButtonWidth(), float height = UiConsts::ButtonHeight() );
bool FontAwesomeSlashedButton( const FaIcon& icon, int id = 0, float width = UiConsts::ButtonWidth(), float height = UiConsts::ButtonHeight() );
void FontAwesomeText( const FaIcon& icon, float width );
const char* OpenCmfFileDialog();

Expand Down
23 changes: 12 additions & 11 deletions src/viewer/rendering/ui/uiDetailWindow.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright © 2026 CCP ehf.

#include "uiDetailWindow.h"
#include "uiConsts.h"
#include "cmf/bufferstreams.h"
#include "cmf/declutils.h"
#include <imgui.h>
Expand Down Expand Up @@ -598,7 +599,7 @@ void UIDetailWindow::RenderAttributeTable( const uint8_t* vbData, uint32_t verte
}

ImGui::TableSetupScrollFreeze( 1, 1 );
ImGui::TableSetupColumn( "Index", ImGuiTableColumnFlags_WidthFixed, 48.0f );
ImGui::TableSetupColumn( "Index", ImGuiTableColumnFlags_WidthFixed, UiConsts::Scaled( 48.0f ) );
for( const auto& attr : attributes )
{
ImGui::TableSetupColumn( GetUsageFlagLabel( attr.usage, attr.usageIndex ).c_str(), ImGuiTableColumnFlags_WidthStretch );
Expand Down Expand Up @@ -642,7 +643,7 @@ void UIDetailWindow::RenderAttributeTable( const uint8_t* vbData, uint32_t verte
p,
ImVec2( p.x + sz, p.y + sz ),
ImColor( color.x, color.y, color.z ) );
ImGui::Dummy( ImVec2( sz + 4.0f, sz ) );
ImGui::Dummy( ImVec2( sz + UiConsts::Scaled( 4.0f ), sz ) );
ImGui::SameLine();
}

Expand Down Expand Up @@ -713,7 +714,7 @@ void UIDetailWindow::RenderIndexData( const CmfContent& cmfContent, const cmf::M
if( ImGui::BeginTable( "##indexdata", areas.empty() ? 4 : 5, tableFlags, outerSize ) )
{
ImGui::TableSetupScrollFreeze( 0, 1 );
ImGui::TableSetupColumn( "Triangle", ImGuiTableColumnFlags_WidthFixed, 72.0f );
ImGui::TableSetupColumn( "Triangle", ImGuiTableColumnFlags_WidthFixed, UiConsts::Scaled( 72.0f ) );
ImGui::TableSetupColumn( "V0", ImGuiTableColumnFlags_WidthStretch );
ImGui::TableSetupColumn( "V1", ImGuiTableColumnFlags_WidthStretch );
ImGui::TableSetupColumn( "V2", ImGuiTableColumnFlags_WidthStretch );
Expand Down Expand Up @@ -808,7 +809,7 @@ void UIDetailWindow::RenderSkeleton( const cmf::Skeleton& skeleton )
}

ImGui::TableSetupScrollFreeze( 1, 1 );
ImGui::TableSetupColumn( "Index", ImGuiTableColumnFlags_WidthFixed, 48.0f );
ImGui::TableSetupColumn( "Index", ImGuiTableColumnFlags_WidthFixed, UiConsts::Scaled( 48.0f ) );
for( const int ci : activeColIndices )
{
ImGui::TableSetupColumn( m_boneColumnFilter[ci].first.c_str(), ImGuiTableColumnFlags_WidthStretch );
Expand Down Expand Up @@ -927,7 +928,7 @@ void UIDetailWindow::RenderBoneBindings( const CmfContent& cmfContent, const cmf
if( ImGui::BeginTable( "##bonebindingstable", 2, tableFlags ) )
{
ImGui::TableSetupScrollFreeze( 0, 1 );
ImGui::TableSetupColumn( "Index", ImGuiTableColumnFlags_WidthFixed, 48.0f );
ImGui::TableSetupColumn( "Index", ImGuiTableColumnFlags_WidthFixed, UiConsts::Scaled( 48.0f ) );
ImGui::TableSetupColumn( "Name", ImGuiTableColumnFlags_WidthStretch );
ImGui::TableHeadersRow();

Expand Down Expand Up @@ -1134,8 +1135,8 @@ void UIDetailWindow::RenderAnimationCurves( const cmf::AnimationCurve& curve, co
if( ImGui::BeginTable( "##curvestable", 3, tableFlags, ImVec2( 0.0f, ImGui::GetContentRegionAvail().y ) ) )
{
ImGui::TableSetupScrollFreeze( 1, 1 );
ImGui::TableSetupColumn( "Knot", ImGuiTableColumnFlags_WidthFixed, 48.0f );
ImGui::TableSetupColumn( "Time", ImGuiTableColumnFlags_WidthFixed, 80.0f );
ImGui::TableSetupColumn( "Knot", ImGuiTableColumnFlags_WidthFixed, UiConsts::Scaled( 48.0f ) );
ImGui::TableSetupColumn( "Time", ImGuiTableColumnFlags_WidthFixed, UiConsts::Scaled( 80.0f ) );
ImGui::TableSetupColumn( "Value", ImGuiTableColumnFlags_WidthFixed );
ImGui::TableHeadersRow();

Expand Down Expand Up @@ -1205,8 +1206,8 @@ void UIDetailWindow::RenderAudioOccluder( const cmf::AudioOcclusionMesh& audioOc

ImGui::Spacing();

const float indexColumnWidth = 60.0f;
const float columnWidth = 80.0f;
const float indexColumnWidth = UiConsts::Scaled( 60.0f );
const float columnWidth = UiConsts::Scaled( 80.0f );

if( ImGui::CollapsingHeader( "Vertices", ImGuiTreeNodeFlags_DefaultOpen ) )
{
Expand All @@ -1217,7 +1218,7 @@ void UIDetailWindow::RenderAudioOccluder( const cmf::AudioOcclusionMesh& audioOc
ImGuiTableFlags_ScrollY |
ImGuiTableFlags_SizingFixedFit;

const float tableHeight = std::min( (float)vertexCount * ImGui::GetTextLineHeightWithSpacing() + ImGui::GetTextLineHeightWithSpacing(), 200.0f );
const float tableHeight = std::min( (float)vertexCount * ImGui::GetTextLineHeightWithSpacing() + ImGui::GetTextLineHeightWithSpacing(), UiConsts::Scaled( 200.0f ) );
if( ImGui::BeginTable( "##aomverts", 4, tableFlags, ImVec2( 0.0f, tableHeight ) ) )
{
ImGui::TableSetupScrollFreeze( 1, 1 );
Expand Down Expand Up @@ -1261,7 +1262,7 @@ void UIDetailWindow::RenderAudioOccluder( const cmf::AudioOcclusionMesh& audioOc
ImGuiTableFlags_ScrollY |
ImGuiTableFlags_SizingFixedFit;

const float tableHeight = std::min( (float)triCount * ImGui::GetTextLineHeightWithSpacing() + ImGui::GetTextLineHeightWithSpacing(), 200.0f );
const float tableHeight = std::min( (float)triCount * ImGui::GetTextLineHeightWithSpacing() + ImGui::GetTextLineHeightWithSpacing(), UiConsts::Scaled( 200.0f ) );
if( ImGui::BeginTable( "##aomtris", 4, tableFlags, ImVec2( 0.0f, tableHeight ) ) )
{
ImGui::TableSetupScrollFreeze( 1, 1 );
Expand Down
6 changes: 3 additions & 3 deletions src/viewer/rendering/ui/uiGeneralWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,7 @@ void UIGeneralWindow::RenderMorphList( const cmf::Mesh& mesh, MeshState& meshSta
{
ImGui::TableSetupColumn( "", ImGuiTableColumnFlags_WidthFixed );
ImGui::TableSetupColumn( "", ImGuiTableColumnFlags_WidthStretch );
ImGui::TableSetupColumn( "", ImGuiTableColumnFlags_WidthFixed, UiConsts::BUTTON_WIDTH );
ImGui::TableSetupColumn( "", ImGuiTableColumnFlags_WidthFixed, UiConsts::ButtonWidth() );
ImGui::TableNextRow();

ImGui::TableNextColumn();
Expand Down Expand Up @@ -626,7 +626,7 @@ void UIGeneralWindow::RenderAnimationOverrideList( AppState& appState )
ImGui::BeginDisabled( disabled );

// button to add an animation owner from a cmf file
if( ImGui::Button( "+", ImVec2( ImGui::GetContentRegionAvail().x, UiConsts::BUTTON_HEIGHT ) ) )
if( ImGui::Button( "+", ImVec2( ImGui::GetContentRegionAvail().x, UiConsts::ButtonHeight() ) ) )
{
auto* path = ImGui::OpenCmfFileDialog();
if( path != nullptr )
Expand Down Expand Up @@ -696,7 +696,7 @@ void UIGeneralWindow::RenderAnimationOverrideList( AppState& appState )

if( index != 0 )
{
ImGui::SameLine( ImGui::GetContentRegionAvail().x - UiConsts::BUTTON_WIDTH );
ImGui::SameLine( ImGui::GetContentRegionAvail().x - UiConsts::ButtonWidth() );
std::string label = "-##" + std::to_string( index );
if( ImGui::Button( label.c_str() ) )
{
Expand Down
32 changes: 32 additions & 0 deletions src/viewer/rendering/ui/uiMenubar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "uiMenubar.h"
#include <imgui.h>

#include "uiConsts.h"
#include "uiCustomWidgets.h"

void UiMenubar::Render( AppState& appState )
Expand Down Expand Up @@ -112,6 +113,8 @@ void UiMenubar::Render( AppState& appState )
}
ImGui::Separator();

RenderUiScaleMenu( appState );

bool uiShown = appState.showUi.GetValue();
const char* toggleUiLabel = uiShown ? "Hide UI" : "Show UI";
if( ImGui::MenuItem( toggleUiLabel, "Ctrl+F12" ) )
Expand All @@ -124,3 +127,32 @@ void UiMenubar::Render( AppState& appState )
ImGui::EndMainMenuBar();
}
}

void UiMenubar::RenderUiScaleMenu( AppState& appState )
{
if( ImGui::BeginMenu( "UI Scale" ) )
{
if( !m_uiScaleSliderActive )
{
m_uiScaleSliderValue = appState.uiScale.GetValue();
}
ImGui::SetNextItemWidth( UiConsts::Scaled( 160.0f ) );
ImGui::SliderFloat( "##uiScale", &m_uiScaleSliderValue, UiConsts::MIN_UI_SCALE, UiConsts::MAX_UI_SCALE, "%.2fx", ImGuiSliderFlags_AlwaysClamp );
m_uiScaleSliderActive = ImGui::IsItemActive();
// rebuilding the fonts is expensive, only apply once the slider is released
if( ImGui::IsItemDeactivatedAfterEdit() )
{
appState.uiScale.SetValue( m_uiScaleSliderValue );
}
ImGui::SameLine();
if( ImGui::SmallButton( "Reset" ) )
{
appState.uiScale.SetValue( appState.defaultUiScale );
}
ImGui::EndMenu();
}
else
{
m_uiScaleSliderActive = false;
}
}
6 changes: 6 additions & 0 deletions src/viewer/rendering/ui/uiMenubar.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,10 @@ class UiMenubar
{
public:
void Render( AppState& appState );

private:
void RenderUiScaleMenu( AppState& appState );

float m_uiScaleSliderValue{ 1.0f };
bool m_uiScaleSliderActive{ false };
};
Loading
Loading