From f2fd6bdccf0d7ce9218d1c741a6f17836553e945 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 13 Mar 2023 11:06:32 +0100 Subject: [PATCH] Shaders: use zero per-vertex count to disable skinning, not total count. This prepares for SSBO support where the total count is unbounded (and thus the value is ignored, thus it can be 0). Also regroup the doc paragraphs so it's clear what's related to UBO usage and what applies to classic uniforms as well. --- src/Magnum/Shaders/FlatGL.cpp | 6 +- src/Magnum/Shaders/FlatGL.h | 33 +++++----- src/Magnum/Shaders/MeshVisualizerGL.cpp | 10 +-- src/Magnum/Shaders/MeshVisualizerGL.h | 66 +++++++++---------- src/Magnum/Shaders/PhongGL.cpp | 6 +- src/Magnum/Shaders/PhongGL.h | 33 +++++----- src/Magnum/Shaders/Test/FlatGL_Test.cpp | 6 +- .../Shaders/Test/MeshVisualizerGL_Test.cpp | 6 +- src/Magnum/Shaders/Test/PhongGL_Test.cpp | 6 +- 9 files changed, 84 insertions(+), 88 deletions(-) diff --git a/src/Magnum/Shaders/FlatGL.cpp b/src/Magnum/Shaders/FlatGL.cpp index cc954d502..ea12471cc 100644 --- a/src/Magnum/Shaders/FlatGL.cpp +++ b/src/Magnum/Shaders/FlatGL.cpp @@ -104,7 +104,7 @@ template typename FlatGL::CompileState FlatG #endif #ifndef MAGNUM_TARGET_GLES2 - CORRADE_ASSERT(!(configuration.flags() & Flag::DynamicPerVertexJointCount) || configuration.jointCount(), + CORRADE_ASSERT(!(configuration.flags() & Flag::DynamicPerVertexJointCount) || (configuration.perVertexJointCount() || configuration.secondaryPerVertexJointCount()), "Shaders::FlatGL: dynamic per-vertex joint count enabled for zero joints", CompileState{NoCreate}); CORRADE_ASSERT(!(configuration.flags() & Flag::InstancedTransformation) || !configuration.secondaryPerVertexJointCount(), "Shaders::FlatGL: TransformationMatrix attribute binding conflicts with the SecondaryJointIds / SecondaryWeights attributes, use a non-instanced rendering with secondary weights instead", CompileState{NoCreate}); @@ -178,7 +178,7 @@ template typename FlatGL::CompileState FlatG .addSource(configuration.flags() & Flag::InstancedTransformation ? "#define INSTANCED_TRANSFORMATION\n"_s : ""_s) .addSource(configuration.flags() >= Flag::InstancedTextureOffset ? "#define INSTANCED_TEXTURE_OFFSET\n"_s : ""_s); #ifndef MAGNUM_TARGET_GLES2 - if(configuration.jointCount()) { + if(configuration.perVertexJointCount() || configuration.secondaryPerVertexJointCount()) { vert.addSource(Utility::format( "#define JOINT_COUNT {}\n" "#define PER_VERTEX_JOINT_COUNT {}u\n" @@ -661,7 +661,7 @@ template typename FlatGL::Configuration& Fla CORRADE_ASSERT(secondaryPerVertexCount <= 4, "Shaders::FlatGL::Configuration::setJointCount(): expected at most 4 secondary per-vertex joints, got" << secondaryPerVertexCount, *this); CORRADE_ASSERT(!count == (!perVertexCount && !secondaryPerVertexCount), - "Shaders::FlatGL::Configuration::setJointCount(): either both joint count and (secondary) per-vertex joint count has to be non-zero, or all zero", *this); + "Shaders::FlatGL::Configuration::setJointCount(): count has to be non-zero iff (secondary) per-vertex joint count is non-zero", *this); _jointCount = count; _perVertexJointCount = perVertexCount; _secondaryPerVertexJointCount = secondaryPerVertexCount; diff --git a/src/Magnum/Shaders/FlatGL.h b/src/Magnum/Shaders/FlatGL.h index 106465c03..1315ec1eb 100644 --- a/src/Magnum/Shaders/FlatGL.h +++ b/src/Magnum/Shaders/FlatGL.h @@ -1406,27 +1406,26 @@ template class MAGNUM_SHADERS_EXPORT FlatGL: * * If @ref Flag::UniformBuffers isn't set, @p count describes an upper * bound on how many joint matrices get supplied to each draw by - * @ref setJointMatrices() / @ref setJointMatrix(). If - * @ref Flag::UniformBuffers is set, @p count describes size of a + * @ref setJointMatrices() / @ref setJointMatrix(). + * + * If @ref Flag::UniformBuffers is set, @p count describes size of a * @ref TransformationUniform2D / @ref TransformationUniform3D buffer * bound with @ref bindJointBuffer(). Uniform buffers have a statically * defined size and @cpp count*sizeof(TransformationUniform2D) @ce / * @cpp count*sizeof(TransformationUniform3D) @ce has to be within - * @ref GL::AbstractShaderProgram::maxUniformBlockSize(). - * - * The per-vertex joints then index into the array offset by - * @ref FlatDrawUniform::jointOffset. If @p count is @cpp 0 @ce, - * skinning is not performed. - * - * The @p perVertexCount and @p secondaryPerVertexCount then describe - * how many components are taken from @ref JointIds / @ref Weights and - * @ref SecondaryJointIds / @ref SecondaryWeights attributes. Both - * values are expected to not be larger than @cpp 4 @ce, setting either - * of these to @cpp 0 @ce means given attribute is not used at all. If - * @p count is @cpp 0 @ce, both @p perVertexCount and - * @p secondaryPerVertexCount is expected to be @cpp 0 @ce as well; if - * @p count is non-zero at least one of @p perVertexCount and - * @p secondaryPerVertexCount is expected to be non-zero as well. + * @ref GL::AbstractShaderProgram::maxUniformBlockSize(). The + * per-vertex joints then index into the array offset by + * @ref FlatDrawUniform::jointOffset. + * + * The @p perVertexCount and @p secondaryPerVertexCount parameters + * describe how many components are taken from @ref JointIds / + * @ref Weights and @ref SecondaryJointIds / @ref SecondaryWeights + * attributes. Both values are expected to not be larger than + * @cpp 4 @ce, setting either of these to @cpp 0 @ce means given + * attribute is not used at all. If both @p perVertexCount and + * @p secondaryPerVertexCount are set to @cpp 0 @ce, skinning is not + * performed; if either of them is non-zero, @p count is expected to be + * non-zero as well. * * Default value for all three is @cpp 0 @ce. * @see @ref FlatGL::jointCount(), @ref FlatGL::perVertexJointCount(), diff --git a/src/Magnum/Shaders/MeshVisualizerGL.cpp b/src/Magnum/Shaders/MeshVisualizerGL.cpp index 45818cd45..d7de27905 100644 --- a/src/Magnum/Shaders/MeshVisualizerGL.cpp +++ b/src/Magnum/Shaders/MeshVisualizerGL.cpp @@ -197,7 +197,7 @@ GL::Version MeshVisualizerGLBase::setupShaders(GL::Shader& vert, GL::Shader& fra #endif ; #ifndef MAGNUM_TARGET_GLES2 - if(jointCount) { + if(perVertexJointCount || secondaryPerVertexJointCount) { vert.addSource(Utility::format( "#define JOINT_COUNT {}\n" "#define PER_VERTEX_JOINT_COUNT {}u\n" @@ -476,7 +476,7 @@ MeshVisualizerGL2D::CompileState MeshVisualizerGL2D::compile(const Configuration constructor when testing for asserts -- GLSL compilation would fail otherwise */ #ifndef MAGNUM_TARGET_GLES2 - CORRADE_ASSERT(!(configuration.flags() & Flag::DynamicPerVertexJointCount) || configuration.jointCount(), + CORRADE_ASSERT(!(configuration.flags() & Flag::DynamicPerVertexJointCount) || (configuration.perVertexJointCount() || configuration.secondaryPerVertexJointCount()), "Shaders::MeshVisualizerGL2D: dynamic per-vertex joint count enabled for zero joints", CompileState{NoCreate}); CORRADE_ASSERT(!(configuration.flags() & Flag::InstancedTransformation) || !configuration.secondaryPerVertexJointCount(), "Shaders::MeshVisualizerGL2D: TransformationMatrix attribute binding conflicts with the SecondaryJointIds / SecondaryWeights attributes, use a non-instanced rendering with secondary weights instead", CompileState{NoCreate}); @@ -875,7 +875,7 @@ MeshVisualizerGL2D::Configuration& MeshVisualizerGL2D::Configuration::setJointCo CORRADE_ASSERT(secondaryPerVertexCount <= 4, "Shaders::MeshVisualizerGL2D::Configuration::setJointCount(): expected at most 4 secondary per-vertex joints, got" << secondaryPerVertexCount, *this); CORRADE_ASSERT(!count == (!perVertexCount && !secondaryPerVertexCount), - "Shaders::MeshVisualizerGL2D::Configuration::setJointCount(): either both joint count and (secondary) per-vertex joint count has to be non-zero, or all zero", *this); + "Shaders::MeshVisualizerGL2D::Configuration::setJointCount(): count has to be non-zero iff (secondary) per-vertex joint count is non-zero", *this); _jointCount = count; _perVertexJointCount = perVertexCount; _secondaryPerVertexJointCount = secondaryPerVertexCount; @@ -921,7 +921,7 @@ MeshVisualizerGL3D::CompileState MeshVisualizerGL3D::compile(const Configuration constructor when testing for asserts -- GLSL compilation would fail otherwise */ #ifndef MAGNUM_TARGET_GLES2 - CORRADE_ASSERT(!(configuration.flags() & Flag::DynamicPerVertexJointCount) || configuration.jointCount(), + CORRADE_ASSERT(!(configuration.flags() & Flag::DynamicPerVertexJointCount) || (configuration.perVertexJointCount() || configuration.secondaryPerVertexJointCount()), "Shaders::MeshVisualizerGL3D: dynamic per-vertex joint count enabled for zero joints", CompileState{NoCreate}); CORRADE_ASSERT(!(configuration.flags() & Flag::InstancedTransformation) || !configuration.secondaryPerVertexJointCount(), "Shaders::MeshVisualizerGL3D: TransformationMatrix attribute binding conflicts with the SecondaryJointIds / SecondaryWeights attributes, use a non-instanced rendering with secondary weights instead", CompileState{NoCreate}); @@ -1469,7 +1469,7 @@ MeshVisualizerGL3D::Configuration& MeshVisualizerGL3D::Configuration::setJointCo CORRADE_ASSERT(secondaryPerVertexCount <= 4, "Shaders::MeshVisualizerGL3D::Configuration::setJointCount(): expected at most 4 secondary per-vertex joints, got" << secondaryPerVertexCount, *this); CORRADE_ASSERT(!count == (!perVertexCount && !secondaryPerVertexCount), - "Shaders::MeshVisualizerGL3D::Configuration::setJointCount(): either both joint count and (secondary) per-vertex joint count has to be non-zero, or all zero", *this); + "Shaders::MeshVisualizerGL3D::Configuration::setJointCount(): count has to be non-zero iff (secondary) per-vertex joint count is non-zero", *this); _jointCount = count; _perVertexJointCount = perVertexCount; _secondaryPerVertexJointCount = secondaryPerVertexCount; diff --git a/src/Magnum/Shaders/MeshVisualizerGL.h b/src/Magnum/Shaders/MeshVisualizerGL.h index af75115b1..f8fada44f 100644 --- a/src/Magnum/Shaders/MeshVisualizerGL.h +++ b/src/Magnum/Shaders/MeshVisualizerGL.h @@ -1207,26 +1207,25 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D::Configuration { * * If @ref Flag::UniformBuffers isn't set, @p count describes an upper * bound on how many joint matrices get supplied to each draw with - * @ref setJointMatrices() / @ref setJointMatrix(). If - * @ref Flag::UniformBuffers is set, @p count describes size of a + * @ref setJointMatrices() / @ref setJointMatrix(). + * + * If @ref Flag::UniformBuffers is set, @p count describes size of a * @ref TransformationUniform2D buffer bound with * @ref bindJointBuffer(). Uniform buffers have a statically defined * size and @cpp count*sizeof(TransformationUniform2D) @ce has to be - * within @ref GL::AbstractShaderProgram::maxUniformBlockSize(). - * - * The per-vertex joints then index into the array offset by - * @ref MeshVisualizerDrawUniform2D::jointOffset. If @p count is - * @cpp 0 @ce, skinning is not performed. - * - * The @p perVertexCount and @p secondaryPerVertexCount then describe - * how many components are taken from @ref JointIds / @ref Weights and - * @ref SecondaryJointIds / @ref SecondaryWeights attributes. Both - * values are expected to not be larger than @cpp 4 @ce, setting either - * of these to @cpp 0 @ce means given attribute is not used at all. If - * @p count is @cpp 0 @ce, both @p perVertexCount and - * @p secondaryPerVertexCount is expected to be @cpp 0 @ce as well; if - * @p count is non-zero at least one of @p perVertexCount and - * @p secondaryPerVertexCount is expected to be non-zero as well. + * within @ref GL::AbstractShaderProgram::maxUniformBlockSize(). The + * per-vertex joints then index into the array offset by + * @ref MeshVisualizerDrawUniform2D::jointOffset. + * + * The @p perVertexCount and @p secondaryPerVertexCount parameters + * describe how many components are taken from @ref JointIds / + * @ref Weights and @ref SecondaryJointIds / @ref SecondaryWeights + * attributes. Both values are expected to not be larger than + * @cpp 4 @ce, setting either of these to @cpp 0 @ce means given + * attribute is not used at all. If both @p perVertexCount and + * @p secondaryPerVertexCount are set to @cpp 0 @ce, skinning is not + * performed; if either of them is non-zero, @p count is expected to be + * non-zero as well. * * Default value for all three is @cpp 0 @ce. * @see @ref MeshVisualizerGL2D::jointCount(), @@ -3200,26 +3199,25 @@ class MeshVisualizerGL3D::Configuration { * * If @ref Flag::UniformBuffers isn't set, @p count describes an upper * bound on how many joint matrices get supplied to each draw with - * @ref setJointMatrices() / @ref setJointMatrix(). If - * @ref Flag::UniformBuffers is set, @p count describes size of a + * @ref setJointMatrices() / @ref setJointMatrix(). + * + * If @ref Flag::UniformBuffers is set, @p count describes size of a * @ref TransformationUniform3D buffer bound with * @ref bindJointBuffer(). Uniform buffers have a statically defined * size and @cpp count*sizeof(TransformationUniform3D) @ce has to be - * within @ref GL::AbstractShaderProgram::maxUniformBlockSize(). - * - * The per-vertex joints then index into the array offset by - * @ref MeshVisualizerDrawUniform3D::jointOffset. If @p count is - * @cpp 0 @ce, skinning is not performed. - * - * The @p perVertexCount and @p secondaryPerVertexCount then describe - * how many components are taken from @ref JointIds / @ref Weights and - * @ref SecondaryJointIds / @ref SecondaryWeights attributes. Both - * values are expected to not be larger than @cpp 4 @ce, setting either - * of these to @cpp 0 @ce means given attribute is not used at all. If - * @p count is @cpp 0 @ce, both @p perVertexCount and - * @p secondaryPerVertexCount is expected to be @cpp 0 @ce as well; if - * @p count is non-zero at least one of @p perVertexCount and - * @p secondaryPerVertexCount is expected to be non-zero as well. + * within @ref GL::AbstractShaderProgram::maxUniformBlockSize(). The + * per-vertex joints then index into the array offset by + * @ref MeshVisualizerDrawUniform3D::jointOffset. + * + * The @p perVertexCount and @p secondaryPerVertexCount parameters + * describe how many components are taken from @ref JointIds / + * @ref Weights and @ref SecondaryJointIds / @ref SecondaryWeights + * attributes. Both values are expected to not be larger than + * @cpp 4 @ce, setting either of these to @cpp 0 @ce means given + * attribute is not used at all. If both @p perVertexCount and + * @p secondaryPerVertexCount are set to @cpp 0 @ce, skinning is not + * performed; if either of them is non-zero, @p count is expected to be + * non-zero as well. * * Default value for all three is @cpp 0 @ce. * @see @ref MeshVisualizerGL2D::jointCount(), diff --git a/src/Magnum/Shaders/PhongGL.cpp b/src/Magnum/Shaders/PhongGL.cpp index f3c495855..098713789 100644 --- a/src/Magnum/Shaders/PhongGL.cpp +++ b/src/Magnum/Shaders/PhongGL.cpp @@ -119,7 +119,7 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) { "Shaders::PhongGL: specular texture requires the shader to not have specular disabled", CompileState{NoCreate}); #ifndef MAGNUM_TARGET_GLES2 - CORRADE_ASSERT(!(configuration.flags() & Flag::DynamicPerVertexJointCount) || configuration.jointCount(), + CORRADE_ASSERT(!(configuration.flags() & Flag::DynamicPerVertexJointCount) || (configuration.perVertexJointCount() || configuration.secondaryPerVertexJointCount()), "Shaders::PhongGL: dynamic per-vertex joint count enabled for zero joints", CompileState{NoCreate}); CORRADE_ASSERT(!(configuration.flags() & Flag::InstancedTransformation) || !configuration.secondaryPerVertexJointCount(), "Shaders::PhongGL: TransformationMatrix attribute binding conflicts with the SecondaryJointIds / SecondaryWeights attributes, use a non-instanced rendering with secondary weights instead", CompileState{NoCreate}); @@ -222,7 +222,7 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) { .addSource(configuration.flags() & Flag::InstancedTransformation ? "#define INSTANCED_TRANSFORMATION\n"_s : ""_s) .addSource(configuration.flags() >= Flag::InstancedTextureOffset ? "#define INSTANCED_TEXTURE_OFFSET\n"_s : ""_s); #ifndef MAGNUM_TARGET_GLES2 - if(configuration.jointCount()) { + if(configuration.perVertexJointCount() || configuration.secondaryPerVertexJointCount()) { vert.addSource(Utility::format( "#define JOINT_COUNT {}\n" "#define PER_VERTEX_JOINT_COUNT {}u\n" @@ -1124,7 +1124,7 @@ PhongGL::Configuration& PhongGL::Configuration::setJointCount(UnsignedInt count, CORRADE_ASSERT(secondaryPerVertexCount <= 4, "Shaders::PhongGL::Configuration::setJointCount(): expected at most 4 secondary per-vertex joints, got" << secondaryPerVertexCount, *this); CORRADE_ASSERT(!count == (!perVertexCount && !secondaryPerVertexCount), - "Shaders::PhongGL::Configuration::setJointCount(): either both joint count and (secondary) per-vertex joint count has to be non-zero, or all zero", *this); + "Shaders::PhongGL::Configuration::setJointCount(): count has to be non-zero iff (secondary) per-vertex joint count is non-zero", *this); _jointCount = count; _perVertexJointCount = perVertexCount; _secondaryPerVertexJointCount = secondaryPerVertexCount; diff --git a/src/Magnum/Shaders/PhongGL.h b/src/Magnum/Shaders/PhongGL.h index 0bf006ce8..b196ce3c5 100644 --- a/src/Magnum/Shaders/PhongGL.h +++ b/src/Magnum/Shaders/PhongGL.h @@ -2195,26 +2195,25 @@ class MAGNUM_SHADERS_EXPORT PhongGL::Configuration { * * If @ref Flag::UniformBuffers isn't set, @p count describes an upper * bound on how many joint matrices get supplied to each draw with - * @ref setJointMatrices() / @ref setJointMatrix(). If - * @ref Flag::UniformBuffers is set, @p count describes size of a + * @ref setJointMatrices() / @ref setJointMatrix(). + * + * If @ref Flag::UniformBuffers is set, @p count describes size of a * @ref TransformationUniform3D buffer bound with * @ref bindJointBuffer(). Uniform buffers have a statically defined * size and @cpp count*sizeof(TransformationUniform3D) @ce has to be - * within @ref GL::AbstractShaderProgram::maxUniformBlockSize(). - * - * The per-vertex joints then index into the array offset by - * @ref PhongDrawUniform::jointOffset. If @p count is @cpp 0 @ce, - * skinning is not performed. - * - * The @p perVertexCount and @p secondaryPerVertexCount then describe - * how many components are taken from @ref JointIds / @ref Weights and - * @ref SecondaryJointIds / @ref SecondaryWeights attributes. Both - * values are expected to not be larger than @cpp 4 @ce, setting either - * of these to @cpp 0 @ce means given attribute is not used at all. If - * @p count is @cpp 0 @ce, both @p perVertexCount and - * @p secondaryPerVertexCount is expected to be @cpp 0 @ce as well; if - * @p count is non-zero at least one of @p perVertexCount and - * @p secondaryPerVertexCount is expected to be non-zero as well. + * within @ref GL::AbstractShaderProgram::maxUniformBlockSize(). The + * per-vertex joints then index into the array offset by + * @ref PhongDrawUniform::jointOffset. + * + * The @p perVertexCount and @p secondaryPerVertexCount parameters + * describe how many components are taken from @ref JointIds / + * @ref Weights and @ref SecondaryJointIds / @ref SecondaryWeights + * attributes. Both values are expected to not be larger than + * @cpp 4 @ce, setting either of these to @cpp 0 @ce means given + * attribute is not used at all. If both @p perVertexCount and + * @p secondaryPerVertexCount are set to @cpp 0 @ce, skinning is not + * performed; if either of them is non-zero, @p count is expected to be + * non-zero as well. * * Default value for all three is @cpp 0 @ce. * @see @ref PhongGL::jointCount(), @ref PhongGL::perVertexJointCount(), diff --git a/src/Magnum/Shaders/Test/FlatGL_Test.cpp b/src/Magnum/Shaders/Test/FlatGL_Test.cpp index f03a3af46..3a5496239 100644 --- a/src/Magnum/Shaders/Test/FlatGL_Test.cpp +++ b/src/Magnum/Shaders/Test/FlatGL_Test.cpp @@ -64,13 +64,13 @@ const struct { "expected at most 4 secondary per-vertex joints, got 5"}, {"joint count but no per-vertex joint count", 10, 0, 0, - "either both joint count and (secondary) per-vertex joint count has to be non-zero, or all zero"}, + "count has to be non-zero iff (secondary) per-vertex joint count is non-zero"}, {"per-vertex joint count but no joint count", 0, 2, 0, - "either both joint count and (secondary) per-vertex joint count has to be non-zero, or all zero"}, + "count has to be non-zero iff (secondary) per-vertex joint count is non-zero"}, {"secondary per-vertex joint count but no joint count", 0, 0, 3, - "either both joint count and (secondary) per-vertex joint count has to be non-zero, or all zero"}, + "count has to be non-zero iff (secondary) per-vertex joint count is non-zero"}, }; #endif diff --git a/src/Magnum/Shaders/Test/MeshVisualizerGL_Test.cpp b/src/Magnum/Shaders/Test/MeshVisualizerGL_Test.cpp index b87be32a2..a8e48e3a7 100644 --- a/src/Magnum/Shaders/Test/MeshVisualizerGL_Test.cpp +++ b/src/Magnum/Shaders/Test/MeshVisualizerGL_Test.cpp @@ -74,13 +74,13 @@ const struct { "expected at most 4 secondary per-vertex joints, got 5"}, {"joint count but no per-vertex joint count", 10, 0, 0, - "either both joint count and (secondary) per-vertex joint count has to be non-zero, or all zero"}, + "count has to be non-zero iff (secondary) per-vertex joint count is non-zero"}, {"per-vertex joint count but no joint count", 0, 2, 0, - "either both joint count and (secondary) per-vertex joint count has to be non-zero, or all zero"}, + "count has to be non-zero iff (secondary) per-vertex joint count is non-zero"}, {"secondary per-vertex joint count but no joint count", 0, 0, 3, - "either both joint count and (secondary) per-vertex joint count has to be non-zero, or all zero"}, + "count has to be non-zero iff (secondary) per-vertex joint count is non-zero"}, }; #endif diff --git a/src/Magnum/Shaders/Test/PhongGL_Test.cpp b/src/Magnum/Shaders/Test/PhongGL_Test.cpp index 434f37ad5..10c638388 100644 --- a/src/Magnum/Shaders/Test/PhongGL_Test.cpp +++ b/src/Magnum/Shaders/Test/PhongGL_Test.cpp @@ -63,13 +63,13 @@ const struct { "expected at most 4 secondary per-vertex joints, got 5"}, {"joint count but no per-vertex joint count", 10, 0, 0, - "either both joint count and (secondary) per-vertex joint count has to be non-zero, or all zero"}, + "count has to be non-zero iff (secondary) per-vertex joint count is non-zero"}, {"per-vertex joint count but no joint count", 0, 2, 0, - "either both joint count and (secondary) per-vertex joint count has to be non-zero, or all zero"}, + "count has to be non-zero iff (secondary) per-vertex joint count is non-zero"}, {"secondary per-vertex joint count but no joint count", 0, 0, 3, - "either both joint count and (secondary) per-vertex joint count has to be non-zero, or all zero"}, + "count has to be non-zero iff (secondary) per-vertex joint count is non-zero"}, }; #endif