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
e83752d
Modifying the appState
CCPNobody Jun 3, 2026
affdb21
Update model.cpp
CCPNobody Jun 4, 2026
f098f5e
Adding vertex color visualization
CCPNobody Jun 4, 2026
0ca212e
Add vertex normal/tangent/binormal visualization
CCPNobody Jun 8, 2026
73746dd
Fixing normal, tangent and binormal visualization for legacy packed t…
CCPNobody Jun 8, 2026
1355dfa
Adding a display flag for the model which turns off display flag for …
CCPNobody Jun 8, 2026
67f8ffc
Refactor orientation gizmo & shader fixes
CCPNobody Jun 8, 2026
9c800ed
Disable normal/tangent/bitangent UI
CCPNobody Jun 9, 2026
c3995b9
Compute camera near/far from bounding sphere
CCPNobody Jun 9, 2026
2ff55ab
Merge remote-tracking branch 'origin/main' into PLAT-10869-CMF-Viewer…
Jun 9, 2026
c40d618
Support per-usage vertex attributes
CCPNobody Jun 12, 2026
7cc7060
Add tri-state checkboxes for mesh attribute controls
CCPNobody Jun 15, 2026
2284890
Formatting fixes
CCPNobody Jun 15, 2026
267fe3f
more formatting fixes
CCPNobody Jun 15, 2026
1918c11
Fixing mac build errors
CCPNobody Jun 15, 2026
d68c031
Merge remote-tracking branch 'origin/main' into PLAT-10869-CMF-Viewer…
Jun 16, 2026
87772b8
Merge remote-tracking branch 'origin/main' into PLAT-10869-CMF-Viewer…
Jun 18, 2026
d1c9210
Merge remote-tracking branch 'origin/main' into PLAT-10869-CMF-Viewer…
Jun 18, 2026
1510154
Merge from main
filipppavlov Jun 24, 2026
5f64a3d
Add copyright comments
filipppavlov Jun 24, 2026
1ee7569
Fix compile errors on clang
filipppavlov Jun 24, 2026
b45da28
Fix global normal/tangent/bitangent checkboxes not working
filipppavlov Jun 24, 2026
a5cc677
Format the file
filipppavlov Jun 24, 2026
3afc9d7
Fix compile error on clang
filipppavlov Jun 24, 2026
d8c7726
Address PR comments
filipppavlov Jun 24, 2026
f40d154
Update shadercache.cpp
ccp-intern Jun 24, 2026
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
18 changes: 10 additions & 8 deletions src/viewer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,18 +84,20 @@ foreach( SHADER_PATH ${SHADERS} )
file( RELATIVE_PATH SHADER_RELATIVE_PATH ${SOURCE_SHADER_DIR} ${SHADER_PATH} )

get_filename_component( SHADER_NAME ${SHADER_RELATIVE_PATH} NAME )
get_filename_component( SHADER_EXTENSION ${SHADER_RELATIVE_PATH} EXT )

if( NOT EXISTS ${GENERATED_SHADER_DIR} )
file( MAKE_DIRECTORY ${GENERATED_SHADER_DIR} )
endif()

add_custom_command(
OUTPUT "${GENERATED_SHADER_DIR}/${SHADER_NAME}.spv.h"
DEPENDS ${SHADER_PATH}
COMMAND ${GLSLC_EXECUTABLE} "${SHADER_PATH}" -mfmt=num -o "${GENERATED_SHADER_DIR}/${SHADER_NAME}.spv.h"
COMMENT "Compiling shader: ${SHADER_PATH} to ${GENERATED_SHADER_DIR}/${SHADER_NAME}.spv.h"
)
list( APPEND COMPILED_SHADERS "${GENERATED_SHADER_DIR}/${SHADER_NAME}.spv.h" )
if( "${SHADER_EXTENSION}" STREQUAL ".comp" OR "${SHADER_EXTENSION}" STREQUAL ".vert" OR "${SHADER_EXTENSION}" STREQUAL ".frag" )
add_custom_command(
OUTPUT "${GENERATED_SHADER_DIR}/${SHADER_NAME}.spv.h"
DEPENDS ${SHADER_PATH}
COMMAND ${GLSLC_EXECUTABLE} "${SHADER_PATH}" -mfmt=num -o "${GENERATED_SHADER_DIR}/${SHADER_NAME}.spv.h"
COMMENT "Compiling shader: ${SHADER_PATH} to ${GENERATED_SHADER_DIR}/${SHADER_NAME}.spv.h"
)
list( APPEND COMPILED_SHADERS "${GENERATED_SHADER_DIR}/${SHADER_NAME}.spv.h" )
endif()
endforeach()

add_custom_command(
Expand Down
22 changes: 1 addition & 21 deletions src/viewer/appState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,7 @@ void AppState::CallStateCallbacks()
cmfPath.CallCallbacks( *this );
exitRequested.CallCallbacks( *this );

modelState.selectedLod.CallCallbacks( *this );
modelState.activeLod.CallCallbacks( *this );
modelState.meshScreenSize.CallCallbacks( *this );
modelState.visualizationShader.CallCallbacks( *this );
modelState.availableShaders.CallCallbacks( *this );
modelState.polygonMode.CallCallbacks( *this );
modelState.meshVisibilityStates.CallCallbacks( *this );
modelState.morphTargetWeight.CallCallbacks( *this );
modelState.morphTargetEnabled.CallCallbacks( *this );
modelState.meshWireframeOverlay.CallCallbacks( *this );
modelState.audioOcclusionMesh.CallCallbacks( *this );
modelState.meshBoundingBox.CallCallbacks( *this );
modelState.modelBoundingBox.CallCallbacks( *this );
modelState.currentAnimation.CallCallbacks( *this );
modelState.currentAnimationTime.CallCallbacks( *this );
modelState.availableShaders.CallCallbacks( *this );
modelState.boneDebug.CallCallbacks( *this );
modelState.jointDebug.CallCallbacks( *this );
modelState.jointAxisDebug.CallCallbacks( *this );
modelState.activeAnimationOwner.CallCallbacks( *this );
modelState.selectedBones.CallCallbacks( *this );
modelState.CallCallbacks( *this );
}

void AppState::ResetModelState()
Expand Down
70 changes: 59 additions & 11 deletions src/viewer/appState.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <functional>

#include "data/cmfcontent.h"
#include "rendering/vulkan/graphicseffecttypes.h"

//forwards declaration
struct AppState;
Expand All @@ -31,6 +32,7 @@ class State
public:
State( T initialValue );
const T GetValue() const;
T& GetValue();
void SetValue( T newValue );
void ForceSetValue( T newValue );
void SetValueNoCallback( T newValue );
Expand Down Expand Up @@ -58,6 +60,12 @@ class StateCollection
size_t AddState();
size_t AddState( T initialValue );

template <typename Callable>
size_t AddState( Callable configurator );

template <typename Callable>
size_t AddState( T initialValue, Callable configurator );

void Clear();
void CallCallbacks( AppState& appState );

Expand All @@ -66,6 +74,7 @@ class StateCollection
void RemoveAt( size_t index );

size_t size() const;
bool empty() const;

// Non-const iterators
iterator begin();
Expand Down Expand Up @@ -100,35 +109,74 @@ enum class CameraTrigger
CAMERA_TRIGGER_LOOK_BACK,
};

struct MeshState
{
State<bool> display{ true };
/// the pair is <weight, enabled>
StateCollection<std::pair<float, bool>> morphs{ { 0.0f, true } };
State<bool> wireframeOverlay{ false };
State<bool> audioOcclusionMesh{ false };
State<bool> renderBoundingBox{ false };
StateCollection<std::pair<uint32_t, bool>> showVertexNormals{ { 0, false } };
StateCollection<std::pair<uint32_t, bool>> showVertexTangents{ { 0, false } };
StateCollection<std::pair<uint32_t, bool>> showVertexBinormals{ { 0, false } };
State<uint32_t> activeLod{ 0 };
State<float> meshScreenSize{ 0.0f };

void CallCallbacks( AppState& appState )
{
display.CallCallbacks( appState );
morphs.CallCallbacks( appState );
wireframeOverlay.CallCallbacks( appState );
audioOcclusionMesh.CallCallbacks( appState );
renderBoundingBox.CallCallbacks( appState );
activeLod.CallCallbacks( appState );
meshScreenSize.CallCallbacks( appState );
showVertexNormals.CallCallbacks( appState );
showVertexTangents.CallCallbacks( appState );
showVertexBinormals.CallCallbacks( appState );
}
};

struct ModelState
{
/// The lod selected by the user (-1 for auto)
State<int32_t> selectedLod{ -1 };

/// The lod of the mesh that is currently active
StateCollection<uint32_t> activeLod{ 0 };
StateCollection<float> meshScreenSize{ 0.0f };
StateCollection<MeshState> meshes{ {} };

State<std::string> visualizationShader{ "" };
State<std::vector<std::string>> availableShaders{ {} };
State<std::pair<std::string, GraphicsEffectTypes::ShaderInputDeclaration>> activeShader{ {} };
State<std::vector<std::pair<std::string, GraphicsEffectTypes::ShaderInputDeclaration>>> availableShaders{ {} };

State<VkPolygonMode> polygonMode{ VK_POLYGON_MODE_FILL };
State<std::string> currentAnimation{ "" };
State<float> currentAnimationTime{ 0.0f };

StateCollection<bool> meshVisibilityStates{ true };
StateCollection<float> morphTargetWeight{ 0.0 };
StateCollection<bool> morphTargetEnabled{ true };
StateCollection<bool> meshWireframeOverlay{ false };
StateCollection<bool> audioOcclusionMesh{ false };
StateCollection<bool> meshBoundingBox{ false };
State<bool> boneDebug{ false };
State<bool> jointDebug{ false };
State<bool> jointAxisDebug{ false };
State<bool> modelBoundingBox{ false };
State<std::shared_ptr<CmfContent>> activeAnimationOwner{ nullptr };
StateCollection<std::shared_ptr<CmfContent>> animationOverrides{ nullptr };
StateCollection<uint32_t> selectedBones{ 0xFF };

void CallCallbacks( AppState& appState )
{
selectedLod.CallCallbacks( appState );
meshes.CallCallbacks( appState );
activeShader.CallCallbacks( appState );
availableShaders.CallCallbacks( appState );
polygonMode.CallCallbacks( appState );
currentAnimation.CallCallbacks( appState );
currentAnimationTime.CallCallbacks( appState );
boneDebug.CallCallbacks( appState );
jointDebug.CallCallbacks( appState );
jointAxisDebug.CallCallbacks( appState );
modelBoundingBox.CallCallbacks( appState );
activeAnimationOwner.CallCallbacks( appState );
animationOverrides.CallCallbacks( appState );
selectedBones.CallCallbacks( appState );
}
};

struct AppState
Expand Down
58 changes: 57 additions & 1 deletion src/viewer/appState_template_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,33 @@ void State<T>::SetValueNoCallback( T newValue )
m_value = newValue;
}

template <typename T>
T& State<T>::GetValue()
{
return m_value;
}

namespace detail
{
template <typename T, typename = void>
struct has_call_callbacks : std::false_type
{
};

template <typename T>
struct has_call_callbacks<T, std::void_t<decltype( std::declval<T&>().CallCallbacks( std::declval<AppState&>() ) )>> : std::true_type
{
};
}

template <typename T>
void State<T>::CallCallbacks( AppState& appState )
{
if constexpr( detail::has_call_callbacks<T>::value )
{
m_value.CallCallbacks( appState );
}

if( m_fireCallbacks )
{
for( auto& callback : m_callbacks )
Expand Down Expand Up @@ -91,6 +115,28 @@ size_t StateCollection<T>::AddState( T initialValue )
return m_states.size() - 1;
}

template <typename T>
template <typename Callable>
size_t StateCollection<T>::AddState( Callable configurator )
{
State<T> state( m_initialValue );
m_states.push_back( state );
configurator( m_states.back().GetValue() );
m_fireCallbacks = true;
return m_states.size() - 1;
}

template <typename T>
template <typename Callable>
size_t StateCollection<T>::AddState( T initialValue, Callable configurator )
{
State<T> state( initialValue );
m_states.push_back( state );
configurator( m_states.back().GetValue() );
m_fireCallbacks = true;
return m_states.size() - 1;
}

template <typename T>
void StateCollection<T>::RemoveAt( size_t index )
{
Expand All @@ -111,12 +157,16 @@ void StateCollection<T>::RegisterCallback( std::function<void( std::vector<T>, A
template <typename T>
void StateCollection<T>::CallCallbacks( AppState& appState )
{
for( auto& state : m_states )
{
state.CallCallbacks( appState );
}

std::vector<T> values;
values.reserve( m_states.size() );
for( auto& state : m_states )
{
values.push_back( state.GetValue() );
state.CallCallbacks( appState );
}

if( m_fireCallbacks )
Expand Down Expand Up @@ -146,6 +196,12 @@ size_t StateCollection<T>::size() const
return m_states.size();
}

template <typename T>
bool StateCollection<T>::empty() const
{
return m_states.empty();
}

// Non-const iterators
template <typename T>
typename StateCollection<T>::iterator StateCollection<T>::begin()
Expand Down
14 changes: 14 additions & 0 deletions src/viewer/assets/shaders/binormalaxis.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (c) 2026 CCP ehf.

#version 450

// inputs
layout( location = 0 ) in vec3 inFragColor;

// Outputs
layout( location = 0 ) out vec4 outFragColor;

void main()
{
outFragColor = vec4( inFragColor, 1.0 );
}
40 changes: 40 additions & 0 deletions src/viewer/assets/shaders/binormalaxis.vert
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) 2026 CCP ehf.

#version 450
#pragma multi_usage inBinormal

// Constants
layout( binding = 0 ) uniform PerFrame
{
mat4 projectionMatrix;
mat4 viewMatrix;
} perframe;


layout( binding = 1 ) uniform AxisConfig
{
vec3 color;
float scale;
int axisSelector;
} axisConfig;

// Inputs
// inputs are per instance, not per vertex
layout( location = 0 ) in vec3 inPosition;
layout( location = 1 ) in vec3 inBinormal;

// Output
layout ( location = 0 ) out vec3 outColor;

void main()
{
vec4 position = vec4( inPosition, 1.0 );

if( gl_VertexIndex == 1 )
{
position.xyz += axisConfig.scale * inBinormal;
}

gl_Position = perframe.projectionMatrix * perframe.viewMatrix * position;
outColor = axisConfig.color;
}
14 changes: 14 additions & 0 deletions src/viewer/assets/shaders/model_color.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (c) 2026 CCP ehf.

#version 450

// Inputs
layout( location = 0 ) in vec3 color;

// Outputs
layout( location = 0 ) out vec4 outFragColor;

void main()
{
outFragColor = vec4( color, 1.0 );
}
26 changes: 26 additions & 0 deletions src/viewer/assets/shaders/model_color.vert
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) 2026 CCP ehf.

#version 450
#pragma multi_usage inColor

// Constants
layout( binding = 0 ) uniform PerFrame
{
mat4 projectionMatrix;
mat4 viewMatrix;
} perframe;


// Inputs
layout( location = 0 ) in vec3 inPosition;
layout( location = 1 ) in vec3 inColor;

// Outputs;
layout( location = 0 ) out vec3 color;


void main()
{
color = inColor;
gl_Position = perframe.projectionMatrix * perframe.viewMatrix * vec4( inPosition, 1.0 );
}
3 changes: 2 additions & 1 deletion src/viewer/assets/shaders/model_normal.vert
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ layout( binding = 0 ) uniform PerFrame


// Inputs
// inputs are per instance, not per vertex
layout( location = 0 ) in vec3 inPosition;
layout( location = 1 ) in vec3 inNormal;
layout( location = 1 ) in vec3 inNormal; // shadercachecreator_multi_usage_index

// Outputs
layout( location = 0 ) out vec3 viewPosition;
Expand Down
Loading