#define MORPH defined(MORPH_POSITION) || defined(MORPH_NORMAL) || defined(MORPH_TANGENT)
+// If needed, define these strings in code, insert after each.
+#define ADD_EXTRA_SKINNING_ATTRIBUTES
+#define ADD_EXTRA_WEIGHTS
+
#ifdef HIGHP
precision highp float;
#else
in vec4 aVertexColor;
#ifdef SKINNING
-in vec4 aJoints;
-in vec4 aWeights;
+in vec4 aJoints0;
+in vec4 aWeights0;
+ADD_EXTRA_SKINNING_ATTRIBUTES;
#endif
#ifdef MORPH
#endif
+
+
+
#ifdef SKINNING
- highp mat4 bone = uBone[int(aJoints.x)] * aWeights.x +
- uBone[int(aJoints.y)] * aWeights.y +
- uBone[int(aJoints.z)] * aWeights.z +
- uBone[int(aJoints.w)] * aWeights.w;
+ highp mat4 bone =
+ uBone[int(aJoints0.x)] * aWeights0.x +
+ uBone[int(aJoints0.y)] * aWeights0.y +
+ uBone[int(aJoints0.z)] * aWeights0.z +
+ uBone[int(aJoints0.w)] * aWeights0.w;
+
+ ADD_EXTRA_WEIGHTS;
+
position = bone * position;
normal = uYDirection * (bone * vec4(normal, 0.0)).xyz;
tangent = uYDirection * (bone * vec4(tangent, 0.0)).xyz;
#else
highp vec4 positionW = uModelMatrix * position;
#endif
+
highp vec4 positionV = uViewMatrix * positionW;
vPositionToCamera = transpose(mat3(uViewMatrix)) * -vec3(positionV.xyz / positionV.w);
#version 300 es
+#define ADD_EXTRA_SKINNING_ATTRIBUTES
+#define ADD_EXTRA_WEIGHTS
+
precision highp float;
in vec3 aPosition;
in vec2 aTexCoord;
in vec4 aVertexColor;
+#ifdef SKINNING
+in vec4 aJoints0;
+in vec4 aWeights0;
+ADD_EXTRA_SKINNING_ATTRIBUTES;
+#endif
+
out mediump vec2 vUV;
out lowp vec4 vColor;
uniform highp mat4 uProjection;
#ifdef SKINNING
- in vec4 aJoints;
- in vec4 aWeights;
- #define MAX_BONES 64
- uniform mat4 uBone[MAX_BONES];
- uniform mediump vec3 uYDirection;
+#define MAX_BONES 256
+layout(std140) uniform Bones
+{
+ mat4 uBone[MAX_BONES];
+};
+uniform mediump vec3 uYDirection;
#endif
#ifdef MORPH
#endif
#ifdef SKINNING
- highp mat4 bone = uBone[int(aJoints.x)] * aWeights.x +
- uBone[int(aJoints.y)] * aWeights.y +
- uBone[int(aJoints.z)] * aWeights.z +
- uBone[int(aJoints.w)] * aWeights.w;
- position = bone * position;
+ highp mat4 bone = uBone[int(aJoints0.x)] * aWeights0.x +
+ uBone[int(aJoints0.y)] * aWeights0.y +
+ uBone[int(aJoints0.z)] * aWeights0.z +
+ uBone[int(aJoints0.w)] * aWeights0.w;
+ ADD_EXTRA_WEIGHTS;
+
+ position = bone * position;
highp vec4 positionW = position;
#else
highp vec4 positionW = uModelMatrix * position;
auto& node = (*i0).second;
ShaderDefinition shaderDef;
ReadStringVector(node.GetChild("defines"), shaderDef.mDefines);
- auto sssIter = std::find_if(shaderDef.mDefines.begin(), shaderDef.mDefines.end(), [](std::string& item)
- { return (item == "SSS"); });
+ auto sssIter = std::find_if(shaderDef.mDefines.begin(), shaderDef.mDefines.end(), [](std::string& item) { return (item == "SSS"); });
if(sssIter != shaderDef.mDefines.end())
{
shaderDef.mDefines.erase(sssIter);
mOnError(FormatString("mesh %d: Failed to read %s.", resources.mMeshes.size(), "normals"));
}
- if(MaskMatch(attributes, MeshDefinition::TEX_COORDS) &&
- !ReadAttribAccessor(node.GetChild("textures"), meshDef.mTexCoords))
+ if(MaskMatch(attributes, MeshDefinition::TEX_COORDS))
{
- mOnError(FormatString("mesh %d: Failed to read %s.", resources.mMeshes.size(), "textures"));
+ meshDef.mTexCoords.emplace_back(MeshDefinition::Accessor{});
+ if(!ReadAttribAccessor(node.GetChild("textures"), meshDef.mTexCoords[0]))
+ {
+ mOnError(FormatString("mesh %d: Failed to read %s.", resources.mMeshes.size(), "textures"));
+ }
}
if(MaskMatch(attributes, MeshDefinition::TANGENTS) &&
mOnError(FormatString("mesh %d: Expected joints0 / weights0 attribute(s) missing.",
resources.mMeshes.size()));
}
- else if(!ReadAttribAccessor(node.GetChild("joints0"), meshDef.mJoints0) ||
- !ReadAttribAccessor(node.GetChild("weights0"), meshDef.mWeights0))
+ else
{
- mOnError(FormatString("mesh %d: Failed to read skinning information.",
- resources.mMeshes.size()));
+ meshDef.mJoints.emplace_back(MeshDefinition::Accessor{});
+ meshDef.mWeights.emplace_back(MeshDefinition::Accessor{});
+ if(!ReadAttribAccessor(node.GetChild("joints0"), meshDef.mJoints[0]) ||
+ !ReadAttribAccessor(node.GetChild("weights0"), meshDef.mWeights[0]))
+ {
+ mOnError(FormatString("mesh %d: Failed to read skinning information.",
+ resources.mMeshes.size()));
+ }
}
}
materialDef.mFlags |= semantic;
}
-/// @TODO : Some dli shader don't implement this subsurfaceMp usage.
-/// To make visual test pass, Skip subsurfaceMap texture using
-/// until dli shaders are support it.
-// if(ReadString(node.GetChild("subsurfaceMap"), texturePath))
-// {
-// ToUnixFileSeparators(texturePath);
-//
-// const auto semantic = MaterialDefinition::SUBSURFACE;
-// materialDef.mTextureStages.push_back({semantic, TextureDefinition{std::move(texturePath)}});
-// materialDef.mFlags |= semantic;
-// }
+ /// @TODO : Some dli shader don't implement this subsurfaceMp usage.
+ /// To make visual test pass, Skip subsurfaceMap texture using
+ /// until dli shaders are support it.
+ // if(ReadString(node.GetChild("subsurfaceMap"), texturePath))
+ // {
+ // ToUnixFileSeparators(texturePath);
+ //
+ // const auto semantic = MaterialDefinition::SUBSURFACE;
+ // materialDef.mTextureStages.push_back({semantic, TextureDefinition{std::move(texturePath)}});
+ // materialDef.mFlags |= semantic;
+ // }
if(ReadString(node.GetChild("occlusionMap"), texturePath))
{
iAnim != iAnimEnd;
++iAnim)
{
- const TreeNode& tnAnim = (*iAnim).second;
- uint32_t animationPropertyIndex = 0;
+ const TreeNode& tnAnim = (*iAnim).second;
+ uint32_t animationPropertyIndex = 0;
AnimationDefinition animDef;
- std::string animationName;
+ std::string animationName;
ReadString(tnAnim.GetChild(NAME), animationName);
animDef.SetName(animationName);
return ALPHA_MODE_TYPES;
}
-const std::map<std::string_view, Attribute::Type>& GetAttributeTypes()
-{
- static const std::map<std::string_view, Attribute::Type> ATTRIBUTE_TYPES{
- ENUM_STRING_MAPPING(Attribute::Type, POSITION),
- ENUM_STRING_MAPPING(Attribute::Type, NORMAL),
- ENUM_STRING_MAPPING(Attribute::Type, TANGENT),
- ENUM_STRING_MAPPING(Attribute::Type, TEXCOORD_0),
- ENUM_STRING_MAPPING(Attribute::Type, TEXCOORD_1),
- ENUM_STRING_MAPPING(Attribute::Type, COLOR_0),
- ENUM_STRING_MAPPING(Attribute::Type, JOINTS_0),
- ENUM_STRING_MAPPING(Attribute::Type, WEIGHTS_0),
- };
- return ATTRIBUTE_TYPES;
-}
-
const std::map<std::string_view, Animation::Sampler::Interpolation::Type>& GetAnimationSamplerInterpolation()
{
static const std::map<std::string_view, Animation::Sampler::Interpolation::Type> ANIMATION_SAMPLER_INTERPOLATION{
ENUM_TYPE_FROM_STRING(AccessorType, GetAccessorTypes())
ENUM_TYPE_FROM_STRING(AlphaMode, GetAlphaModeTypes())
-ENUM_TYPE_FROM_STRING(Attribute, GetAttributeTypes())
ENUM_TYPE_FROM_STRING(Animation::Sampler::Interpolation, GetAnimationSamplerInterpolation())
ENUM_TYPE_FROM_STRING(Animation::Channel::Target, GetAnimationChannelTargetPathTypes())
+const std::map<std::string_view, Attribute::Type>& GetTargetTypes()
+{
+ static const std::map<std::string_view, Attribute::Type> TARGET_TYPES{
+ ENUM_STRING_MAPPING(Attribute::Type, POSITION),
+ ENUM_STRING_MAPPING(Attribute::Type, TANGENT),
+ ENUM_STRING_MAPPING(Attribute::Type, NORMAL),
+ };
+ return TARGET_TYPES;
+}
+
+const std::map<Attribute::Type, const char*>& GetAttributeSetTypes()
+{
+ static const std::map<Attribute::Type, const char*> ATTRIBUTE_SET_TYPES{
+ {Attribute::Type::TEXCOORD_N, "TEXCOORD_%u"},
+ {Attribute::Type::COLOR_N, "COLOR_%u"},
+ {Attribute::Type::JOINTS_N, "JOINTS_%u"},
+ {Attribute::Type::WEIGHTS_N, "WEIGHTS_%u"},
+ };
+ return ATTRIBUTE_SET_TYPES;
+}
+
+uint32_t Attribute::HashFromString(const char* token, size_t length)
+{
+ auto& table1 = GetTargetTypes();
+ auto& table2 = GetAttributeSetTypes();
+
+ std::string target(token, length);
+ std::transform(target.begin(), target.end(), target.begin(), ::toupper);
+
+ auto iFind = table1.find(std::string_view(target.c_str(), length));
+ if(iFind != table1.end())
+ {
+ return Attribute::ToHash(iFind->second, false, 0);
+ }
+
+ uint32_t hash = Attribute::ToHash(Attribute::INVALID, false, 0);
+ for(const auto& [key, match] : table2)
+ {
+ int setIndex;
+ if(sscanf(target.c_str(), match, &setIndex) > 0)
+ {
+ hash = Attribute::ToHash(key, true, setIndex);
+ break;
+ }
+ }
+ return hash;
+}
+
+Attribute::Type Attribute::TargetFromString(const char* token, size_t length)
+{
+ std::string target(token, length);
+ std::transform(target.begin(), target.end(), target.begin(), ::toupper);
+
+ auto iFind = GetTargetTypes().find(std::string_view(target.c_str(), length));
+ if(iFind != GetTargetTypes().end())
+ {
+ return iFind->second;
+ }
+ return Attribute::INVALID;
+}
+
bool Component::IsUnsigned(Type t)
{
return t == UNSIGNED_BYTE || t == UNSIGNED_SHORT || t == UNSIGNED_INT;
POSITION,
NORMAL,
TANGENT,
- TEXCOORD_0,
- TEXCOORD_1,
- COLOR_0,
- JOINTS_0,
- WEIGHTS_0,
+ TEXCOORD_N,
+ COLOR_N,
+ JOINTS_N,
+ WEIGHTS_N,
INVALID
};
- static Type FromString(const char* s, size_t len);
+ using HashType = uint32_t;
+
+ // Hash bit layout
+ // +--+--+--+--+--+--+--+
+ // |31|30|29|28|27|..| 0| bit index
+ // +--+--+--+--+--+--+--+
+ // \_/ - Set is used
+ // \______/ - Type enum
+ // \_______/ - Set ID
+ static const HashType SET_SHIFT{31};
+ static const HashType TYPE_SHIFT{28};
+ static const HashType SET_MASK{0x01u << SET_SHIFT};
+ static const HashType TYPE_MASK{0x07 << TYPE_SHIFT};
+ static const HashType SET_ID_MASK{0x0fffffff};
+
+ static HashType ToHash(Type type, bool set, HashType setIndex)
+ {
+ return ((set << SET_SHIFT) & SET_MASK) | ((static_cast<HashType>(type) << TYPE_SHIFT) & TYPE_MASK) | (setIndex & SET_ID_MASK);
+ }
+
+ static Attribute::Type TypeFromHash(HashType hash)
+ {
+ return static_cast<Type>((hash & TYPE_MASK) >> TYPE_SHIFT);
+ }
+
+ static bool SetFromHash(HashType hash)
+ {
+ return (hash & SET_SHIFT) != 0;
+ }
+
+ static HashType SetIdFromHash(HashType hash)
+ {
+ return (hash & SET_ID_MASK);
+ }
+
+ /**
+ * Convert to Type + setIndex, where setIndex is N for that attr, e.g. "JOINTS_1" => {JOINTS_N, 1}
+ */
+ static HashType HashFromString(const char* s, size_t len);
+
+ /**
+ * Convert to type only, there is no set for POSITION, NORMALS or TANGENT.
+ */
+ static Attribute::Type TargetFromString(const char* s, size_t len);
Attribute() = delete;
};
INVALID
};
- std::map<Attribute::Type, Ref<Accessor>> mAttributes;
+ std::map<Attribute::HashType, Ref<Accessor>> mAttributes;
std::vector<std::map<Attribute::Type, Ref<Accessor>>> mTargets;
Ref<Accessor> mIndices;
Ref<Material> mMaterial;
Geometry::TRIANGLE_STRIP,
Geometry::TRIANGLE_FAN}; //...because Dali swaps the last two.
-static struct AttributeMapping
-{
- gltf2::Attribute::Type mType;
- MeshDefinition::Accessor MeshDefinition::*mAccessor;
- uint16_t mElementSizeRequired;
-} ATTRIBUTE_MAPPINGS[]{
- {gltf2::Attribute::NORMAL, &MeshDefinition::mNormals, sizeof(Vector3)},
- {gltf2::Attribute::TANGENT, &MeshDefinition::mTangents, sizeof(Vector3)},
- {gltf2::Attribute::TEXCOORD_0, &MeshDefinition::mTexCoords, sizeof(Vector2)},
- {gltf2::Attribute::COLOR_0, &MeshDefinition::mColors, sizeof(Vector4)},
- {gltf2::Attribute::JOINTS_0, &MeshDefinition::mJoints0, sizeof(Vector4)},
- {gltf2::Attribute::WEIGHTS_0, &MeshDefinition::mWeights0, sizeof(Vector4)},
-};
-
static const Dali::Scripting::StringEnum EXTENSION_STRING_TABLE[] =
- {
- {"NONE", gltf2::ExtensionFlags::NONE},
- {"KHR_mesh_quantization", gltf2::ExtensionFlags::KHR_MESH_QUANTIZATION},
- {"KHR_texture_transform", gltf2::ExtensionFlags::KHR_TEXTURE_TRANSFORM},
- {"KHR_materials_ior", gltf2::ExtensionFlags::KHR_MATERIALS_IOR},
- {"KHR_materials_specular", gltf2::ExtensionFlags::KHR_MATERIALS_SPECULAR},
-
+{
+ {"NONE", gltf2::ExtensionFlags::NONE},
+ {"KHR_mesh_quantization", gltf2::ExtensionFlags::KHR_MESH_QUANTIZATION},
+ {"KHR_texture_transform", gltf2::ExtensionFlags::KHR_TEXTURE_TRANSFORM},
+ {"KHR_materials_ior", gltf2::ExtensionFlags::KHR_MATERIALS_IOR},
+ {"KHR_materials_specular", gltf2::ExtensionFlags::KHR_MATERIALS_SPECULAR},
};
-
static const unsigned int EXTENSION_STRING_TABLE_COUNT = sizeof(EXTENSION_STRING_TABLE) / sizeof(EXTENSION_STRING_TABLE[0]);
std::vector<gltf2::Animation> ReadAnimationArray(const json_value_s& j)
.Register(*new json::Property<gltf2::Accessor, gltf2::Ref<gltf2::BufferView>>("bufferView",
gltf2::RefReader<gltf2::Document>::Read<gltf2::BufferView, &gltf2::Document::mBufferViews>,
&gltf2::Accessor::mBufferView))
- .Register(*new json::Property<gltf2::Accessor, uint32_t>("byteOffset",
- json::Read::Number<uint32_t>,
- &gltf2::Accessor::mByteOffset))
+ .Register(*new json::Property<gltf2::Accessor, uint32_t>("byteOffset", json::Read::Number<uint32_t>, &gltf2::Accessor::mByteOffset))
.Register(*new json::Property<gltf2::Accessor, gltf2::Component::Type>("componentType",
json::Read::Enum<gltf2::Component::Type>,
&gltf2::Accessor::mComponentType))
return MATERIAL_READER;
}
-std::map<gltf2::Attribute::Type, gltf2::Ref<gltf2::Accessor>> ReadMeshPrimitiveAttributes(const json_value_s& j)
+std::map<gltf2::Attribute::HashType, gltf2::Ref<gltf2::Accessor>> ReadMeshPrimitiveAttributes(const json_value_s& j)
+{
+ auto& jsonObject = json::Cast<json_object_s>(j);
+ std::map<gltf2::Attribute::HashType, gltf2::Ref<gltf2::Accessor>> result;
+
+ auto element = jsonObject.start;
+ while(element)
+ {
+ auto jsonString = *element->name;
+
+ gltf2::Attribute::HashType hash = gltf2::Attribute::HashFromString(jsonString.string, jsonString.string_size);
+
+ result[hash] =
+ gltf2::RefReader<gltf2::Document>::Read<gltf2::Accessor, &gltf2::Document::mAccessors>(*element->value);
+ element = element->next;
+ }
+ return result;
+}
+
+std::map<gltf2::Attribute::Type, gltf2::Ref<gltf2::Accessor>> ReadMeshPrimitiveAttributes2(const json_value_s& j)
{
auto& jsonObject = json::Cast<json_object_s>(j);
std::map<gltf2::Attribute::Type, gltf2::Ref<gltf2::Accessor>> result;
auto element = jsonObject.start;
while(element)
{
- auto jsonString = *element->name;
- result[gltf2::Attribute::FromString(jsonString.string, jsonString.string_size)] = gltf2::RefReader<gltf2::Document>::Read<gltf2::Accessor, &gltf2::Document::mAccessors>(*element->value);
- element = element->next;
+ auto jsonString = *element->name;
+
+ result[gltf2::Attribute::TargetFromString(jsonString.string, jsonString.string_size)] = gltf2::RefReader<gltf2::Document>::Read<gltf2::Accessor, &gltf2::Document::mAccessors>(*element->value);
+
+ element = element->next;
}
return result;
}
auto element = jsonObject.start;
while(element)
{
- result.push_back(std::move(ReadMeshPrimitiveAttributes(*element->value)));
+ result.push_back(std::move(ReadMeshPrimitiveAttributes2(*element->value)));
element = element->next;
}
return MeshDefinition::Accessor{
std::move(MeshDefinition::Blob{bufferViewOffset + accessor.mByteOffset,
- accessor.GetBytesLength(),
- static_cast<uint16_t>(bufferViewStride),
- static_cast<uint16_t>(accessor.GetElementSizeBytes()),
- accessor.mMin,
- accessor.mMax}),
- std::move(sparseBlob),
- accessor.mBufferView ? accessor.mBufferView->mBuffer.GetIndex() : 0};
+ accessor.GetBytesLength(),
+ static_cast<uint16_t>(bufferViewStride),
+ static_cast<uint16_t>(accessor.GetElementSizeBytes()),
+ accessor.mMin,
+ accessor.mMax}),
+ std::move(sparseBlob),
+ accessor.mBufferView ? accessor.mBufferView->mBuffer.GetIndex() : 0,
+ accessor.mNormalized};
+}
+
+MeshDefinition::Accessor* GetAccessorFromAttribute(gltf2::Attribute::HashType attributeHash,
+ MeshDefinition& meshDefinition,
+ bool& needNormals, bool& needTangents)
+{
+ MeshDefinition::Accessor* accessorDest{nullptr};
+
+ switch(gltf2::Attribute::TypeFromHash(attributeHash))
+ {
+ case gltf2::Attribute::POSITION:
+ {
+ accessorDest = &meshDefinition.mPositions;
+ break;
+ }
+ case gltf2::Attribute::NORMAL:
+ {
+ accessorDest = &meshDefinition.mNormals;
+ needNormals = false;
+ break;
+ }
+ case gltf2::Attribute::TANGENT:
+ {
+ accessorDest = &meshDefinition.mTangents;
+ needTangents = false;
+ break;
+ }
+ case gltf2::Attribute::TEXCOORD_N:
+ {
+ meshDefinition.mTexCoords.emplace_back(MeshDefinition::Accessor{});
+ accessorDest = &meshDefinition.mTexCoords.back();
+ break;
+ }
+ case gltf2::Attribute::COLOR_N:
+ {
+ meshDefinition.mColors.emplace_back(MeshDefinition::Accessor{});
+ accessorDest = &meshDefinition.mColors.back();
+ break;
+ }
+ case gltf2::Attribute::JOINTS_N:
+ {
+ meshDefinition.mJoints.emplace_back(MeshDefinition::Accessor{});
+ accessorDest = &meshDefinition.mJoints.back();
+ break;
+ }
+ case gltf2::Attribute::WEIGHTS_N:
+ {
+ meshDefinition.mWeights.emplace_back(MeshDefinition::Accessor{});
+ accessorDest = &meshDefinition.mWeights.back();
+ break;
+ }
+ case gltf2::Attribute::INVALID:
+ {
+ accessorDest = nullptr;
+ break;
+ }
+ }
+ return accessorDest;
+}
+
+void SetFlagsFromComponentType(const gltf2::Accessor& accessor,
+ gltf2::Attribute::HashType attributeHash,
+ MeshDefinition& meshDefinition,
+ bool isQuantized)
+{
+ switch(gltf2::Attribute::TypeFromHash(attributeHash))
+ {
+ case gltf2::Attribute::POSITION:
+ {
+ if(isQuantized)
+ {
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_POSITION;
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_POSITION;
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_POSITION;
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_POSITION;
+ }
+ DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_POSITION) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_POSITION) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_POSITION) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_POSITION))) || accessor.mComponentType == gltf2::Component::FLOAT);
+ break;
+ }
+ case gltf2::Attribute::NORMAL:
+ {
+ if(isQuantized)
+ {
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_NORMAL;
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_NORMAL;
+ }
+
+ DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_NORMAL) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_NORMAL))) || accessor.mComponentType == gltf2::Component::FLOAT);
+ break;
+ }
+ case gltf2::Attribute::TANGENT:
+ {
+ if(isQuantized)
+ {
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_TANGENT;
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_TANGENT;
+ }
+
+ DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_TANGENT) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_TANGENT))) || accessor.mComponentType == gltf2::Component::FLOAT);
+ break;
+ }
+ case gltf2::Attribute::TEXCOORD_N:
+ {
+ if(isQuantized)
+ {
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_TEXCOORD;
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_TEXCOORD;
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_TEXCOORD;
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_TEXCOORD;
+ }
+ DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_TEXCOORD) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_TEXCOORD) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_TEXCOORD) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_TEXCOORD))) || accessor.mComponentType == gltf2::Component::FLOAT);
+ break;
+ }
+ case gltf2::Attribute::COLOR_N:
+ {
+ break;
+ }
+ case gltf2::Attribute::JOINTS_N:
+ {
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_JOINT_IDS;
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_JOINT_IDS;
+ DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_JOINT_IDS) ||
+ MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_JOINT_IDS) ||
+ accessor.mComponentType == gltf2::Component::FLOAT);
+ break;
+ }
+ case gltf2::Attribute::WEIGHTS_N:
+ {
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_WEIGHT;
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_WEIGHT;
+ DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_WEIGHT) ||
+ MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_WEIGHT) ||
+ accessor.mComponentType == gltf2::Component::FLOAT);
+
+ break;
+ }
+ case gltf2::Attribute::INVALID:
+ {
+ break;
+ }
+ }
}
void ConvertMeshes(const gltf2::Document& document, ConversionContext& context)
auto& attribs = primitive.mAttributes;
meshDefinition.mPrimitiveType = GLTF2_TO_DALI_PRIMITIVES[primitive.mMode];
- auto positionIter = attribs.find(gltf2::Attribute::POSITION);
-
+ auto positionIter = attribs.find(gltf2::Attribute::ToHash(gltf2::Attribute::POSITION, false, 0));
if(positionIter == attribs.end())
{
DALI_LOG_ERROR("Primitive mesh dosn't have POSITION atrributes!");
continue;
}
- auto& accPositions = *positionIter->second;
- meshDefinition.mPositions = ConvertMeshPrimitiveAccessor(accPositions);
- meshDefinition.mPositions.mNormalized = accPositions.mNormalized;
-
- if(isQuantized)
- {
- meshDefinition.mFlags |= (accPositions.mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_POSITION;
- meshDefinition.mFlags |= (accPositions.mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_POSITION;
- meshDefinition.mFlags |= (accPositions.mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_POSITION;
- meshDefinition.mFlags |= (accPositions.mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_POSITION;
- }
-
- DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_POSITION) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_POSITION) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_POSITION) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_POSITION))) || accPositions.mComponentType == gltf2::Component::FLOAT);
+ auto& positionsAccessor = *positionIter->second;
// glTF2 support vector4 tangent for mesh.
// https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#meshes-overview
meshDefinition.mTangentType = Property::VECTOR4;
- const bool needNormalsTangents = accPositions.mType == gltf2::AccessorType::VEC3;
- for(auto& attributeMapping : ATTRIBUTE_MAPPINGS)
+ bool needNormals = (positionsAccessor.mType == gltf2::AccessorType::VEC3);
+ bool needTangents = (positionsAccessor.mType == gltf2::AccessorType::VEC3);
+
+ for(const auto& [attributeHash, accessor] : attribs)
{
- auto iFind = attribs.find(attributeMapping.mType);
- if(iFind != attribs.end())
+ MeshDefinition::Accessor* accessorDest = GetAccessorFromAttribute(attributeHash, meshDefinition, needNormals, needTangents);
+ if(accessorDest == nullptr)
{
- auto& accessor = meshDefinition.*(attributeMapping.mAccessor);
- accessor = ConvertMeshPrimitiveAccessor(*iFind->second);
-
- if(iFind->first == gltf2::Attribute::NORMAL)
- {
- meshDefinition.mNormals.mNormalized = iFind->second->mNormalized;
-
- if(isQuantized)
- {
- meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_NORMAL;
- meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_NORMAL;
- }
-
- DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_NORMAL) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_NORMAL))) || iFind->second->mComponentType == gltf2::Component::FLOAT);
- }
- if(iFind->first == gltf2::Attribute::TANGENT)
- {
- meshDefinition.mTangents.mNormalized = iFind->second->mNormalized;
-
- if(isQuantized)
- {
- meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_TANGENT;
- meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_TANGENT;
- }
-
- DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_TANGENT) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_TANGENT))) || iFind->second->mComponentType == gltf2::Component::FLOAT);
- }
- if(iFind->first == gltf2::Attribute::TEXCOORD_0 || iFind->first == gltf2::Attribute::TEXCOORD_1)
- {
- meshDefinition.mTexCoords.mNormalized = iFind->second->mNormalized;
-
- if(isQuantized)
- {
- meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_TEXCOORD;
- meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_TEXCOORD;
- meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_TEXCOORD;
- meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_TEXCOORD;
- }
-
- DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_TEXCOORD) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_TEXCOORD) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_TEXCOORD) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_TEXCOORD))) || iFind->second->mComponentType == gltf2::Component::FLOAT);
- }
- if(iFind->first == gltf2::Attribute::JOINTS_0)
- {
- meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_JOINT_IDS;
- meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_JOINT_IDS;
- DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_JOINT_IDS) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_JOINT_IDS) || iFind->second->mComponentType == gltf2::Component::FLOAT);
- }
- if(iFind->first == gltf2::Attribute::WEIGHTS_0)
- {
- meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_WEIGHT;
- meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_WEIGHT;
- DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_WEIGHT) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_WEIGHT) || iFind->second->mComponentType == gltf2::Component::FLOAT);
- }
+ continue;
}
- else if(needNormalsTangents)
- {
- switch(attributeMapping.mType)
- {
- case gltf2::Attribute::NORMAL:
- meshDefinition.RequestNormals();
- break;
-
- case gltf2::Attribute::TANGENT:
- meshDefinition.RequestTangents();
- break;
+ *accessorDest = ConvertMeshPrimitiveAccessor(*accessor);
+ SetFlagsFromComponentType(*accessor, attributeHash, meshDefinition, isQuantized);
+ }
- default:
- break;
- }
- }
+ if(needNormals)
+ {
+ meshDefinition.RequestNormals();
+ }
+ if(needTangents)
+ {
+ meshDefinition.RequestTangents();
}
if(primitive.mIndices)
}
template<typename T>
-void ReadJointAccessor(MeshDefinition::RawData& raw, const MeshDefinition::Accessor& accessor, std::istream& source, const std::string& meshPath)
+void ReadJointAccessor(MeshDefinition::RawData& raw, const MeshDefinition::Accessor& accessor, std::istream& source, const std::string& meshPath, const std::string& name)
{
constexpr auto sizeofBlobUnit = sizeof(T) * 4;
++floats;
}
}
- raw.mAttribs.push_back({"aJoints", Property::VECTOR4, static_cast<uint32_t>(outBufferSize / sizeof(Vector4)), std::move(buffer)});
+ raw.mAttribs.push_back({name, Property::VECTOR4, static_cast<uint32_t>(outBufferSize / sizeof(Vector4)), std::move(buffer)});
+}
+
+void ReadTypedJointAccessor(MeshDefinition::RawData& raw, uint32_t flags, MeshDefinition::Accessor& accessor, std::iostream& stream, std::string& path, const std::string& name)
+{
+ if(MaskMatch(flags, MeshDefinition::U16_JOINT_IDS))
+ {
+ ReadJointAccessor<uint16_t>(raw, accessor, stream, path, name);
+ }
+ else if(MaskMatch(flags, MeshDefinition::U8_JOINT_IDS))
+ {
+ ReadJointAccessor<uint8_t>(raw, accessor, stream, path, name);
+ }
+ else
+ {
+ ReadJointAccessor<float>(raw, accessor, stream, path, name);
+ }
}
template<typename T>
-void ReadWeightAccessor(MeshDefinition::RawData& raw, const MeshDefinition::Accessor& accessor, std::istream& source, const std::string& meshPath)
+void ReadWeightAccessor(MeshDefinition::RawData& raw, const MeshDefinition::Accessor& accessor, std::istream& source, const std::string& meshPath, const std::string& name)
{
constexpr auto sizeofBlobUnit = sizeof(T) * 4;
++floats;
}
}
- raw.mAttribs.push_back({"aWeights", Property::VECTOR4, static_cast<uint32_t>(outBufferSize / sizeof(Vector4)), std::move(buffer)});
+ raw.mAttribs.push_back({name, Property::VECTOR4, static_cast<uint32_t>(outBufferSize / sizeof(Vector4)), std::move(buffer)});
+}
+
+void ReadTypedWeightAccessor(MeshDefinition::RawData& raw, uint32_t flags, MeshDefinition::Accessor& accessor, std::iostream& stream, std::string& path, std::string name)
+{
+ if(MaskMatch(flags, MeshDefinition::U16_WEIGHT))
+ {
+ ReadWeightAccessor<uint16_t>(raw, accessor, stream, path, name);
+ }
+ else if(MaskMatch(flags, MeshDefinition::U8_WEIGHT))
+ {
+ ReadWeightAccessor<uint8_t>(raw, accessor, stream, path, name);
+ }
+ else
+ {
+ ReadWeightAccessor<float>(raw, accessor, stream, path, name);
+ }
}
template<bool use32BitsIndices, typename IndexProviderType = IndexProvider<use32BitsIndices>>
MeshDefinition::Accessor::Accessor(const MeshDefinition::Blob& blob,
const MeshDefinition::SparseBlob& sparse,
- Index bufferIndex)
+ Index bufferIndex,
+ bool normalized)
: mBlob{blob},
mSparse{(sparse.mIndices.IsDefined() && sparse.mValues.IsDefined()) ? new SparseBlob{sparse} : nullptr},
- mBufferIdx(bufferIndex)
+ mBufferIdx(bufferIndex),
+ mNormalized(normalized)
{
}
MeshDefinition::Accessor::Accessor(MeshDefinition::Blob&& blob,
MeshDefinition::SparseBlob&& sparse,
- Index bufferIndex)
+ Index bufferIndex,
+ bool normalized)
: mBlob{std::move(blob)},
mSparse{(sparse.mIndices.IsDefined() && sparse.mValues.IsDefined()) ? new SparseBlob{std::move(sparse)} : nullptr},
- mBufferIdx(bufferIndex)
+ mBufferIdx(bufferIndex),
+ mNormalized(normalized)
{
}
bool MeshDefinition::IsSkinned() const
{
- return mJoints0.IsDefined() && mWeights0.IsDefined();
+ return !mJoints.empty() && !mWeights.empty();
}
bool MeshDefinition::HasBlendShapes() const
}
}
- const auto hasUvs = mTexCoords.IsDefined();
- if(hasUvs)
+ if(!mTexCoords.empty() && mTexCoords[0].IsDefined())
{
- const auto bufferSize = mTexCoords.mBlob.GetBufferSize();
-
+ auto& texCoords = mTexCoords[0];
+ const auto bufferSize = texCoords.mBlob.GetBufferSize();
uint32_t uvCount;
if(MaskMatch(mFlags, S8_TEXCOORD) || MaskMatch(mFlags, U8_TEXCOORD))
{
- DALI_ASSERT_ALWAYS(((mTexCoords.mBlob.mLength % (sizeof(uint8_t) * 2) == 0) ||
- mTexCoords.mBlob.mStride >= (sizeof(uint8_t) * 2)) &&
+ DALI_ASSERT_ALWAYS(((texCoords.mBlob.mLength % (sizeof(uint8_t) * 2) == 0) ||
+ texCoords.mBlob.mStride >= (sizeof(uint8_t) * 2)) &&
"TexCoords buffer length not a multiple of element size");
uvCount = static_cast<uint32_t>(bufferSize / (sizeof(uint8_t) * 2));
}
else if(MaskMatch(mFlags, S16_TEXCOORD) || MaskMatch(mFlags, U16_TEXCOORD))
{
- DALI_ASSERT_ALWAYS(((mTexCoords.mBlob.mLength % (sizeof(uint16_t) * 2) == 0) ||
- mTexCoords.mBlob.mStride >= (sizeof(uint16_t) * 2)) &&
+ DALI_ASSERT_ALWAYS(((texCoords.mBlob.mLength % (sizeof(uint16_t) * 2) == 0) ||
+ texCoords.mBlob.mStride >= (sizeof(uint16_t) * 2)) &&
"TexCoords buffer length not a multiple of element size");
uvCount = static_cast<uint32_t>(bufferSize / (sizeof(uint16_t) * 2));
}
else
{
- DALI_ASSERT_ALWAYS(((mTexCoords.mBlob.mLength % sizeof(Vector2) == 0) ||
- mTexCoords.mBlob.mStride >= sizeof(Vector2)) &&
+ DALI_ASSERT_ALWAYS(((texCoords.mBlob.mLength % sizeof(Vector2) == 0) ||
+ texCoords.mBlob.mStride >= sizeof(Vector2)) &&
"TexCoords buffer length not a multiple of element size");
uvCount = static_cast<uint32_t>(bufferSize / sizeof(Vector2));
}
std::vector<uint8_t> buffer(bufferSize);
std::string path;
- auto& stream = GetAvailableData(fileStream, meshPath, buffers[mTexCoords.mBufferIdx], path);
- if(!ReadAccessor(mTexCoords, stream, buffer.data()))
+ auto& stream = GetAvailableData(fileStream, meshPath, buffers[texCoords.mBufferIdx], path);
+ if(!ReadAccessor(texCoords, stream, buffer.data()))
{
ExceptionFlinger(ASSERT_LOCATION) << "Failed to read uv-s from '" << path << "'.";
}
- GetDequantizedData(buffer, 2u, uvCount, mFlags & TEXCOORDS_MASK, mTexCoords.mNormalized);
+ GetDequantizedData(buffer, 2u, uvCount, mFlags & TEXCOORDS_MASK, texCoords.mNormalized);
if(MaskMatch(mFlags, FLIP_UVS_VERTICAL))
{
}
}
- if(mTexCoords.mNormalized)
+ if(texCoords.mNormalized)
{
- GetDequantizedMinMax(mTexCoords.mBlob.mMin, mTexCoords.mBlob.mMax, mFlags & TEXCOORDS_MASK);
+ GetDequantizedMinMax(texCoords.mBlob.mMin, texCoords.mBlob.mMax, mFlags & TEXCOORDS_MASK);
}
- mTexCoords.mBlob.ApplyMinMax(static_cast<uint32_t>(uvCount), reinterpret_cast<float*>(buffer.data()));
-
+ texCoords.mBlob.ApplyMinMax(static_cast<uint32_t>(uvCount), reinterpret_cast<float*>(buffer.data()));
raw.mAttribs.push_back({"aTexCoord", Property::VECTOR2, static_cast<uint32_t>(uvCount), std::move(buffer)});
}
GenerateTangents<true, true, true>,
},
}};
+ const bool hasUvs = !mTexCoords.empty() && mTexCoords[0].IsDefined();
const bool generateSuccessed = GenerateTangentsFunction[MaskMatch(mFlags, U32_INDICES)][mTangentType == Property::VECTOR3][hasUvs](raw);
if(!generateSuccessed)
{
}
}
- if(mColors.IsDefined())
+ // Only support 1 vertex color
+ if(!mColors.empty() && mColors[0].IsDefined())
{
- uint32_t propertySize = mColors.mBlob.mElementSizeHint;
+ uint32_t propertySize = mColors[0].mBlob.mElementSizeHint;
Property::Type propertyType = (propertySize == sizeof(Vector4)) ? Property::VECTOR4 : ((propertySize == sizeof(Vector3)) ? Property::VECTOR3 : Property::NONE);
if(propertyType != Property::NONE)
{
- DALI_ASSERT_ALWAYS(((mColors.mBlob.mLength % propertySize == 0) ||
- mColors.mBlob.mStride >= propertySize) &&
+ DALI_ASSERT_ALWAYS(((mColors[0].mBlob.mLength % propertySize == 0) ||
+ mColors[0].mBlob.mStride >= propertySize) &&
"Colors buffer length not a multiple of element size");
- const auto bufferSize = mColors.mBlob.GetBufferSize();
+ const auto bufferSize = mColors[0].mBlob.GetBufferSize();
std::vector<uint8_t> buffer(bufferSize);
std::string path;
- auto& stream = GetAvailableData(fileStream, meshPath, buffers[mColors.mBufferIdx], path);
- if(!ReadAccessor(mColors, stream, buffer.data()))
+ auto& stream = GetAvailableData(fileStream, meshPath, buffers[mColors[0].mBufferIdx], path);
+ if(!ReadAccessor(mColors[0], stream, buffer.data()))
{
ExceptionFlinger(ASSERT_LOCATION) << "Failed to read colors from '" << path << "'.";
}
- mColors.mBlob.ApplyMinMax(bufferSize / propertySize, reinterpret_cast<float*>(buffer.data()));
+ mColors[0].mBlob.ApplyMinMax(bufferSize / propertySize, reinterpret_cast<float*>(buffer.data()));
raw.mAttribs.push_back({"aVertexColor", propertyType, static_cast<uint32_t>(bufferSize / propertySize), std::move(buffer)});
}
if(IsSkinned())
{
- std::string pathJoint;
- auto& streamJoint = GetAvailableData(fileStream, meshPath, buffers[mJoints0.mBufferIdx], pathJoint);
- if(MaskMatch(mFlags, U16_JOINT_IDS))
- {
- ReadJointAccessor<uint16_t>(raw, mJoints0, streamJoint, pathJoint);
- }
- else if(MaskMatch(mFlags, U8_JOINT_IDS))
- {
- ReadJointAccessor<uint8_t>(raw, mJoints0, streamJoint, pathJoint);
- }
- else
- {
- ReadJointAccessor<float>(raw, mJoints0, streamJoint, pathJoint);
- }
-
- std::string pathWeight;
- auto& streamWeight = GetAvailableData(fileStream, meshPath, buffers[mWeights0.mBufferIdx], pathWeight);
- if(MaskMatch(mFlags, U16_WEIGHT))
- {
- ReadWeightAccessor<uint16_t>(raw, mWeights0, streamWeight, pathWeight);
- }
- else if(MaskMatch(mFlags, U8_WEIGHT))
- {
- ReadWeightAccessor<uint8_t>(raw, mWeights0, streamWeight, pathWeight);
- }
- else
- {
- ReadWeightAccessor<float>(raw, mWeights0, streamWeight, pathWeight);
+ int setIndex = 0;
+ for(auto& accessor : mJoints)
+ {
+ std::string pathJoint;
+ auto& streamJoint = GetAvailableData(fileStream, meshPath, buffers[accessor.mBufferIdx], pathJoint);
+ std::ostringstream jointName;
+ jointName << "aJoints" << setIndex;
+ ++setIndex;
+ ReadTypedJointAccessor(raw, mFlags, accessor, streamJoint, pathJoint, jointName.str());
+ }
+ setIndex = 0;
+ for(auto& accessor : mWeights)
+ {
+ std::string pathWeight;
+ auto& streamWeight = GetAvailableData(fileStream, meshPath, buffers[accessor.mBufferIdx], pathWeight);
+ std::ostringstream weightName;
+ weightName << "aWeights" << setIndex;
+ ++setIndex;
+ ReadTypedWeightAccessor(raw, mFlags, accessor, streamWeight, pathWeight, weightName.str());
}
}
Accessor(const MeshDefinition::Blob& blob,
const MeshDefinition::SparseBlob& sparse,
- Index bufferIndex = INVALID_INDEX);
+ Index bufferIndex = INVALID_INDEX,
+ bool normalized = false);
+
Accessor(MeshDefinition::Blob&& blob,
MeshDefinition::SparseBlob&& sparse,
- Index bufferIndex = INVALID_INDEX);
+ Index bufferIndex = INVALID_INDEX,
+ bool normalized = false);
bool IsDefined() const
{
std::string mUri; // When the mesh data is loaded from embedded resources, this URI is used as a data stream.
Accessor mIndices;
Accessor mPositions;
- Accessor mNormals; // data can be generated based on positions
- Accessor mTexCoords;
- Accessor mColors;
+ Accessor mNormals; // data can be generated based on positions
Accessor mTangents; // data can be generated based on normals and texCoords (the latter isn't mandatory; the results will be better if available)
- Accessor mJoints0;
- Accessor mWeights0;
+ std::vector<Accessor> mTexCoords;
+ std::vector<Accessor> mColors;
+ std::vector<Accessor> mJoints;
+ std::vector<Accessor> mWeights;
Property::Type mTangentType{Property::VECTOR3};
Blob mBlendShapeHeader;
// EXTERNAL INCLUDES
#include <dali/public-api/object/property-array.h>
+#include <regex>
// INTERNAL INCLUDES
#include <dali-scene3d/internal/graphics/builtin-shader-extern-gen.h>
{
}
-void ShaderDefinition::ApplyDefine(std::string& shaderCode, const std::string& definevar)
+void ApplyDefine(std::string& shaderCode, const std::string& definevar)
{
const std::string IF_1 = "#if 1";
}
}
+void RedefineMacro(std::string& shaderCode, const std::string& macro, const std::string& value)
+{
+ std::string definition = "#define " + macro;
+ std::size_t found = shaderCode.find(definition);
+ if(found != std::string::npos)
+ {
+ std::size_t insertionPoint = found + definition.length();
+
+ // Automatically insert line-continuation character into value
+ std::regex re("\n");
+ std::sregex_token_iterator first{value.begin(), value.end(), re, -1}, last;
+ for(auto i = first; i != last; ++i)
+ {
+ std::string line = std::string("\\\n") + (*i).str();
+ shaderCode.insert(insertionPoint, line);
+ insertionPoint += line.length();
+ }
+ }
+}
+
ShaderDefinition::RawData
ShaderDefinition::LoadRaw(const std::string& shadersPath) const
{
ApplyDefine(raw.mFragmentShaderSource, definevar);
ApplyDefine(raw.mShadowVertexShaderSource, definevar);
}
+ for(const auto& macroDef : mMacros)
+ {
+ RedefineMacro(raw.mVertexShaderSource, macroDef.macro, macroDef.definition);
+ RedefineMacro(raw.mFragmentShaderSource, macroDef.macro, macroDef.definition);
+ RedefineMacro(raw.mShadowVertexShaderSource, macroDef.macro, macroDef.definition);
+ }
}
return raw;
// INTERNAL INCLUDES
#include <dali-scene3d/public-api/loader/renderer-state.h>
+#include <dali-scene3d/public-api/loader/shader-option.h>
namespace Dali::Scene3D::Loader
{
std::string mShadowFragmentShaderSource;
};
- /*
- * @brief Apply the defines values to shader.
- */
- static void ApplyDefine(std::string& shaderCode, const std::string& definevar);
-
ShaderDefinition() = default;
ShaderDefinition(const ShaderDefinition& other);
ShaderDefinition& operator=(const ShaderDefinition& other);
- ShaderDefinition(ShaderDefinition&&) = default;
+ ShaderDefinition(ShaderDefinition&&) = default;
ShaderDefinition& operator=(ShaderDefinition&&) = default;
/*
std::shared_ptr<RawData> mRawData;
RendererState::Type mRendererState = RendererState::NONE;
- std::string mVertexShaderPath;
- std::string mFragmentShaderPath;
- std::vector<std::string> mDefines;
- std::vector<std::string> mHints;
- Property::Map mUniforms;
- bool mUseBuiltInShader{false};
+ std::string mVertexShaderPath;
+ std::string mFragmentShaderPath;
+ std::vector<std::string> mDefines;
+ std::vector<ShaderOption::MacroDefinition> mMacros;
+ std::vector<std::string> mHints;
+ Property::Map mUniforms;
+ bool mUseBuiltInShader{false};
};
} // namespace Dali::Scene3D::Loader
static constexpr uint32_t INDEX_FOR_LIGHT_CONSTRAINT_TAG = 10;
static constexpr uint32_t INDEX_FOR_SHADOW_CONSTRAINT_TAG = 100;
+static const char* ADD_EXTRA_SKINNING_ATTRIBUTES{"ADD_EXTRA_SKINNING_ATTRIBUTES"};
+static const char* ADD_EXTRA_WEIGHTS{"ADD_EXTRA_WEIGHTS"};
+
ShaderOption MakeOption(const MaterialDefinition& materialDef, const MeshDefinition& meshDef)
{
ShaderOption option;
if(meshDef.IsSkinned())
{
option.AddOption(ShaderOption::Type::SKINNING);
+
+ // Add options for ADD_EXTRA_SKINNING_ATTRIBUTES and ADD_EXTRA_WEIGHTS:
+ size_t numberOfSets = meshDef.mJoints.size();
+ if(numberOfSets > 1)
+ {
+ std::ostringstream attributes;
+ std::ostringstream weights;
+ for(size_t i = 1; i < numberOfSets; ++i)
+ {
+ attributes << "in vec4 aJoints" << i << ";\n";
+ attributes << "in vec4 aWeights" << i << ";\n";
+
+ weights << "bone +=\n"
+ << "uBone[int(aJoints" << i << ".x)] * aWeights" << i << ".x +\n"
+ << "uBone[int(aJoints" << i << ".y)] * aWeights" << i << ".y +\n"
+ << "uBone[int(aJoints" << i << ".z)] * aWeights" << i << ".z +\n"
+ << "uBone[int(aJoints" << i << ".w)] * aWeights" << i << ".w;\n";
+ }
+ option.AddMacroDefinition(ADD_EXTRA_SKINNING_ATTRIBUTES, attributes.str());
+ option.AddMacroDefinition(ADD_EXTRA_WEIGHTS, weights.str());
+ }
}
if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
option.AddOption(ShaderOption::Type::FLIP_UVS_VERTICAL);
}
- if(meshDef.mColors.IsDefined())
+ if(!meshDef.mColors.empty() && meshDef.mColors[0].IsDefined())
{
option.AddOption(ShaderOption::Type::COLOR_ATTRIBUTE);
}
shaderDef.mUseBuiltInShader = true;
shaderOption.GetDefines(shaderDef.mDefines);
+ shaderDef.mMacros = shaderOption.GetMacroDefinitions();
shaderDef.mUniforms["uCubeMatrix"] = Matrix::IDENTITY;
shaderMap[hash] = mImpl->mShaders.size();
std::string shadowViewProjectionPropertyName(Scene3D::Internal::Light::GetShadowViewProjectionMatrixUniformName());
auto shadowViewProjectionPropertyIndex = shader.RegisterProperty(shadowViewProjectionPropertyName, Matrix::IDENTITY);
Dali::CameraActor shadowLightCamera = Dali::Scene3D::Internal::GetImplementation(mImpl->mShadowLight).GetCamera();
- auto tempViewProjectionMatrixIndex = shadowLightCamera.GetPropertyIndex("tempViewProjectionMatrix");
+ auto tempViewProjectionMatrixIndex = shadowLightCamera.GetPropertyIndex("tempViewProjectionMatrix");
if(tempViewProjectionMatrixIndex != Dali::Property::INVALID_INDEX)
{
tempViewProjectionMatrixIndex = shadowLightCamera.RegisterProperty("tempViewProjectionMatrix", Matrix::IDENTITY);
}
- Dali::Constraint shadowViewProjectionConstraint = Dali::Constraint::New<Matrix>(shader, shadowViewProjectionPropertyIndex, [](Matrix& output, const PropertyInputContainer& inputs)
- {
- output = inputs[0]->GetMatrix(); });
+ Dali::Constraint shadowViewProjectionConstraint = Dali::Constraint::New<Matrix>(shader, shadowViewProjectionPropertyIndex, [](Matrix& output, const PropertyInputContainer& inputs) { output = inputs[0]->GetMatrix(); });
shadowViewProjectionConstraint.AddSource(Source{shadowLightCamera, tempViewProjectionMatrixIndex});
shadowViewProjectionConstraint.ApplyPost();
shadowViewProjectionConstraint.SetTag(INDEX_FOR_SHADOW_CONSTRAINT_TAG);
#include <dali-scene3d/public-api/loader/shader-option.h>
// EXTERNAL INCLUDES
+#include <algorithm>
#include <string>
namespace Dali::Scene3D::Loader
"MORPH_VERSION_2_0",
};
static constexpr uint32_t NUMBER_OF_OPTIONS = sizeof(OPTION_KEYWORD) / sizeof(OPTION_KEYWORD[0]);
+
+inline void HashString(std::uint64_t& hash, const char* string)
+{
+ char c;
+ while((c = *string++))
+ {
+ hash = hash * 33 + c;
+ }
+}
} // namespace
+ShaderOption::ShaderOption(const ShaderOption& rhs)
+{
+ mOptionHash = rhs.mOptionHash;
+ for(auto& macroDef : rhs.mMacros)
+ {
+ mMacros.emplace_back(macroDef);
+ }
+}
+
+ShaderOption& ShaderOption::operator=(const ShaderOption& rhs)
+{
+ if(this != &rhs)
+ {
+ mOptionHash = rhs.mOptionHash;
+ for(auto& macroDef : rhs.mMacros)
+ {
+ mMacros.emplace_back(macroDef);
+ }
+ }
+ return *this;
+}
+
void ShaderOption::SetTransparency()
{
mOptionHash |= (1 << NUMBER_OF_OPTIONS);
mOptionHash |= (1 << static_cast<uint32_t>(shaderOptionType));
}
+void ShaderOption::AddMacroDefinition(std::string macro, std::string definition)
+{
+ auto iter = std::find_if(mMacros.begin(), mMacros.end(), [macro](ShaderOption::MacroDefinition& md) { return md.macro == macro; });
+ if(iter != mMacros.end())
+ {
+ iter->definition = definition;
+ }
+ else
+ {
+ mMacros.emplace_back(MacroDefinition{macro, definition});
+ }
+}
+
+const std::vector<ShaderOption::MacroDefinition>& ShaderOption::GetMacroDefinitions() const
+{
+ return mMacros;
+}
+
uint64_t ShaderOption::GetOptionHash() const
{
- return mOptionHash;
+ uint64_t optionHash = mOptionHash;
+ if(!mMacros.empty())
+ {
+ uint64_t hash = 5381;
+ for(auto& macroDef : mMacros)
+ {
+ HashString(hash, macroDef.macro.c_str());
+ HashString(hash, macroDef.definition.c_str());
+ }
+ optionHash |= (hash << 32 & 0xFFFFFFFF00000000);
+ }
+ return optionHash;
}
void ShaderOption::GetDefines(std::vector<std::string>& defines) const
// EXTERNAL INCLUDER
#include <dali/public-api/common/vector-wrapper.h>
#include <memory>
+#include <string>
#include <string_view>
// INTERNAL INCLUDES
namespace Dali::Scene3D::Loader
{
-
class DALI_SCENE3D_API ShaderOption
{
public:
MORPH_VERSION_2_0
};
+ struct MacroDefinition
+ {
+ std::string macro;
+ std::string definition;
+ };
+
+ ShaderOption() = default;
+ ShaderOption(const ShaderOption& rhs);
+ ShaderOption& operator=(const ShaderOption& rhs);
+
public:
/**
* @brief Sets transparency option.
void AddOption(Type shaderOptionType);
/**
+ * Enables empty preprocessor definitions to be defined to a value
+ */
+ void AddMacroDefinition(std::string macro, std::string definition);
+
+ /**
* @brief Retrieves current shader option hash
*
* @return Hash value of currently added options.
*/
static std::string_view GetDefineKeyword(Type shaderOptionType);
+ /**
+ * Get any macro definitions
+ */
+ const std::vector<MacroDefinition>& GetMacroDefinitions() const;
+
private:
uint64_t mOptionHash{0u};
+
+ std::vector<MacroDefinition> mMacros;
};
} // namespace Dali::Scene3D::Loader