X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-scene3d%2Fpublic-api%2Floader%2Fgltf2-loader.cpp;h=be1be4108b45a923660f04ed1a5b70a01447de75;hb=2785f4990a014b76e582434db4bf9180ff145932;hp=e6d34fc3e68a214c758df36b2bc0393a902cc6b8;hpb=d422b1fb69102251e623b19f6b8e4afe6f66cd24;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-scene3d/public-api/loader/gltf2-loader.cpp b/dali-scene3d/public-api/loader/gltf2-loader.cpp index e6d34fc..be1be41 100644 --- a/dali-scene3d/public-api/loader/gltf2-loader.cpp +++ b/dali-scene3d/public-api/loader/gltf2-loader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,21 +14,24 @@ * limitations under the License. * */ -#include + +// FILE HEADER #include + +// EXTERNAL INCLUDES +#include +#include +#include +#include +#include + +// INTERNAL INCLUDES #include #include #include #include #include #include -#include -#include - -#define ENUM_STRING_MAPPING(t, x) \ - { \ -#x, t::x \ - } namespace gt = gltf2; namespace js = json; @@ -41,6 +44,9 @@ namespace Loader { namespace { +Dali::Mutex gInitializeMutex; +Dali::Mutex gReadMutex; + const std::string POSITION_PROPERTY("position"); const std::string ORIENTATION_PROPERTY("orientation"); const std::string SCALE_PROPERTY("scale"); @@ -74,9 +80,6 @@ struct AttributeMapping std::vector ReadAnimationArray(const json_value_s& j) { - gt::Animation proxy; - SetRefReaderObject(proxy); - auto results = js::Read::Array::Read>(j); for(auto& animation : results) @@ -178,7 +181,6 @@ const auto MATERIAL_SPECULAR_READER = std::move(js::Reader const auto MATERIAL_IOR_READER = std::move(js::Reader() .Register(*js::MakeProperty("ior", js::Read::Number, >::MaterialIor::mIor))); - const auto MATERIAL_EXTENSION_READER = std::move(js::Reader() .Register(*js::MakeProperty("KHR_materials_ior", js::ObjectReader::Read, >::MaterialExtensions::mMaterialIor)) .Register(*js::MakeProperty("KHR_materials_specular", js::ObjectReader::Read, >::MaterialExtensions::mMaterialSpecular))); @@ -405,9 +407,31 @@ struct ConversionContext NodeIndexMapper mNodeIndices; }; -SamplerFlags::Type ConvertWrapMode(gt::Wrap::Type w) +void ConvertBuffer(const gt::Buffer& buffer, decltype(ResourceBundle::mBuffers)& outBuffers, const std::string& resourcePath) +{ + BufferDefinition bufferDefinition; + + bufferDefinition.mResourcePath = resourcePath; + bufferDefinition.mUri = buffer.mUri; + bufferDefinition.mByteLength = buffer.mByteLength; + + outBuffers.emplace_back(std::move(bufferDefinition)); +} + +void ConvertBuffers(const gt::Document& doc, ConversionContext& context) { - switch(w) + auto& outBuffers = context.mOutput.mResources.mBuffers; + outBuffers.reserve(doc.mBuffers.size()); + + for(auto& buffer : doc.mBuffers) + { + ConvertBuffer(buffer, outBuffers, context.mPath); + } +} + +SamplerFlags::Type ConvertWrapMode(gt::Wrap::Type wrapMode) +{ + switch(wrapMode) { case gt::Wrap::REPEAT: return SamplerFlags::WRAP_REPEAT; @@ -420,11 +444,14 @@ SamplerFlags::Type ConvertWrapMode(gt::Wrap::Type w) } } -SamplerFlags::Type ConvertSampler(const gt::Ref& s) +SamplerFlags::Type ConvertSampler(const gt::Ref& sampler) { - if(s) + if(sampler) { - return (s->mMinFilter < gt::Filter::NEAREST_MIPMAP_NEAREST) ? (s->mMinFilter - gt::Filter::NEAREST) : ((s->mMinFilter - gt::Filter::NEAREST_MIPMAP_NEAREST) + 2) | ((s->mMagFilter - gt::Filter::NEAREST) << SamplerFlags::FILTER_MAG_SHIFT) | (ConvertWrapMode(s->mWrapS) << SamplerFlags::WRAP_S_SHIFT) | (ConvertWrapMode(s->mWrapT) << SamplerFlags::WRAP_T_SHIFT); + return ((sampler->mMinFilter < gt::Filter::NEAREST_MIPMAP_NEAREST) ? (sampler->mMinFilter - gt::Filter::NEAREST) : ((sampler->mMinFilter - gt::Filter::NEAREST_MIPMAP_NEAREST) + 2)) | + ((sampler->mMagFilter - gt::Filter::NEAREST) << SamplerFlags::FILTER_MAG_SHIFT) | + (ConvertWrapMode(sampler->mWrapS) << SamplerFlags::WRAP_S_SHIFT) | + (ConvertWrapMode(sampler->mWrapT) << SamplerFlags::WRAP_T_SHIFT); } else { @@ -437,23 +464,55 @@ SamplerFlags::Type ConvertSampler(const gt::Ref& s) } } -TextureDefinition ConvertTextureInfo(const gt::TextureInfo& mm) +TextureDefinition ConvertTextureInfo(const gt::TextureInfo& mm, ConversionContext& context, const ImageMetadata& metaData = ImageMetadata()) { - return TextureDefinition{std::string(mm.mTexture->mSource->mUri), ConvertSampler(mm.mTexture->mSampler)}; + TextureDefinition textureDefinition; + std::string uri = std::string(mm.mTexture->mSource->mUri); + if(uri.empty()) + { + uint32_t bufferIndex = mm.mTexture->mSource->mBufferView->mBuffer.GetIndex(); + if(bufferIndex != INVALID_INDEX && context.mOutput.mResources.mBuffers[bufferIndex].IsAvailable()) + { + auto& stream = context.mOutput.mResources.mBuffers[bufferIndex].GetBufferStream(); + stream.clear(); + stream.seekg(mm.mTexture->mSource->mBufferView->mByteOffset, stream.beg); + std::vector dataBuffer; + dataBuffer.resize(mm.mTexture->mSource->mBufferView->mByteLength); + stream.read(reinterpret_cast(dataBuffer.data()), mm.mTexture->mSource->mBufferView->mByteLength); + return TextureDefinition{std::move(dataBuffer), ConvertSampler(mm.mTexture->mSampler), metaData.mMinSize, metaData.mSamplingMode}; + } + return TextureDefinition(); + } + else + { + return TextureDefinition{uri, ConvertSampler(mm.mTexture->mSampler), metaData.mMinSize, metaData.mSamplingMode}; + } } -void ConvertMaterial(const gt::Material& material, decltype(ResourceBundle::mMaterials)& outMaterials) +void ConvertMaterial(const gt::Material& material, const std::unordered_map& imageMetaData, decltype(ResourceBundle::mMaterials)& outMaterials, ConversionContext& context) { + auto getTextureMetaData = [](const std::unordered_map& metaData, const gt::TextureInfo& info) { + if(!info.mTexture->mSource->mUri.empty()) + { + if(auto search = metaData.find(info.mTexture->mSource->mUri.data()); search != metaData.end()) + { + return search->second; + } + } + return ImageMetadata(); + }; + MaterialDefinition matDef; auto& pbr = material.mPbrMetallicRoughness; - if(pbr.mBaseColorFactor.a < 1.f) + if(material.mAlphaMode == gt::AlphaMode::BLEND) { + matDef.mIsOpaque = false; matDef.mFlags |= MaterialDefinition::TRANSPARENCY; } - - if(material.mAlphaMode == gt::AlphaMode::MASK) + else if(material.mAlphaMode == gt::AlphaMode::MASK) { + matDef.mIsMask = true; matDef.SetAlphaCutoff(std::min(1.f, std::max(0.f, material.mAlphaCutoff))); } @@ -463,7 +522,7 @@ void ConvertMaterial(const gt::Material& material, decltype(ResourceBundle::mMat if(pbr.mBaseColorTexture) { const auto semantic = MaterialDefinition::ALBEDO; - matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(pbr.mBaseColorTexture)}); + matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(pbr.mBaseColorTexture, context, getTextureMetaData(imageMetaData, pbr.mBaseColorTexture))}); // TODO: and there had better be one matDef.mFlags |= semantic; } @@ -479,7 +538,7 @@ void ConvertMaterial(const gt::Material& material, decltype(ResourceBundle::mMat { const auto semantic = MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS | MaterialDefinition::GLTF_CHANNELS; - matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(pbr.mMetallicRoughnessTexture)}); + matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(pbr.mMetallicRoughnessTexture, context, getTextureMetaData(imageMetaData, pbr.mMetallicRoughnessTexture))}); // TODO: and there had better be one matDef.mFlags |= semantic; } @@ -492,7 +551,7 @@ void ConvertMaterial(const gt::Material& material, decltype(ResourceBundle::mMat if(material.mNormalTexture) { const auto semantic = MaterialDefinition::NORMAL; - matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(material.mNormalTexture)}); + matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(material.mNormalTexture, context, getTextureMetaData(imageMetaData, material.mNormalTexture))}); // TODO: and there had better be one matDef.mFlags |= semantic; } @@ -504,7 +563,7 @@ void ConvertMaterial(const gt::Material& material, decltype(ResourceBundle::mMat if(material.mOcclusionTexture) { const auto semantic = MaterialDefinition::OCCLUSION; - matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(material.mOcclusionTexture)}); + matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(material.mOcclusionTexture, context, getTextureMetaData(imageMetaData, material.mOcclusionTexture))}); // TODO: and there had better be one matDef.mFlags |= semantic; matDef.mOcclusionStrength = material.mOcclusionTexture.mStrength; @@ -513,7 +572,7 @@ void ConvertMaterial(const gt::Material& material, decltype(ResourceBundle::mMat if(material.mEmissiveTexture) { const auto semantic = MaterialDefinition::EMISSIVE; - matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(material.mEmissiveTexture)}); + matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(material.mEmissiveTexture, context, getTextureMetaData(imageMetaData, material.mEmissiveTexture))}); // TODO: and there had better be one matDef.mFlags |= semantic; matDef.mEmissiveFactor = material.mEmissiveFactor; @@ -521,8 +580,8 @@ void ConvertMaterial(const gt::Material& material, decltype(ResourceBundle::mMat if(material.mMaterialExtensions.mMaterialIor.mIor < MAXFLOAT) { - float ior = material.mMaterialExtensions.mMaterialIor.mIor; - matDef.mDielectricSpecular = powf((ior-1.0f)/(ior+1.0f), 2.0f); + float ior = material.mMaterialExtensions.mMaterialIor.mIor; + matDef.mDielectricSpecular = powf((ior - 1.0f) / (ior + 1.0f), 2.0f); } matDef.mSpecularFactor = material.mMaterialExtensions.mMaterialSpecular.mSpecularFactor; matDef.mSpecularColorFactor = material.mMaterialExtensions.mMaterialSpecular.mSpecularColorFactor; @@ -530,14 +589,14 @@ void ConvertMaterial(const gt::Material& material, decltype(ResourceBundle::mMat if(material.mMaterialExtensions.mMaterialSpecular.mSpecularTexture) { const auto semantic = MaterialDefinition::SPECULAR; - matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(material.mMaterialExtensions.mMaterialSpecular.mSpecularTexture)}); + matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(material.mMaterialExtensions.mMaterialSpecular.mSpecularTexture, context, getTextureMetaData(imageMetaData, material.mMaterialExtensions.mMaterialSpecular.mSpecularTexture))}); matDef.mFlags |= semantic; } if(material.mMaterialExtensions.mMaterialSpecular.mSpecularColorTexture) { const auto semantic = MaterialDefinition::SPECULAR_COLOR; - matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(material.mMaterialExtensions.mMaterialSpecular.mSpecularColorTexture)}); + matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(material.mMaterialExtensions.mMaterialSpecular.mSpecularColorTexture, context, getTextureMetaData(imageMetaData, material.mMaterialExtensions.mMaterialSpecular.mSpecularColorTexture))}); matDef.mFlags |= semantic; } @@ -548,12 +607,14 @@ void ConvertMaterial(const gt::Material& material, decltype(ResourceBundle::mMat void ConvertMaterials(const gt::Document& doc, ConversionContext& context) { + auto& imageMetaData = context.mOutput.mSceneMetadata.mImageMetadata; + auto& outMaterials = context.mOutput.mResources.mMaterials; outMaterials.reserve(doc.mMaterials.size()); for(auto& m : doc.mMaterials) { - ConvertMaterial(m, outMaterials); + ConvertMaterial(m, imageMetaData, outMaterials, context); } } @@ -607,7 +668,8 @@ MeshDefinition::Accessor ConvertMeshPrimitiveAccessor(const gt::Accessor& acc) static_cast(acc.GetElementSizeBytes()), acc.mMin, acc.mMax}), - std::move(sparseBlob)}; + std::move(sparseBlob), + acc.mBufferView ? acc.mBufferView->mBuffer.GetIndex() : 0}; } void ConvertMeshes(const gt::Document& doc, ConversionContext& context) @@ -628,11 +690,10 @@ void ConvertMeshes(const gt::Document& doc, ConversionContext& context) { MeshDefinition meshDefinition; - auto& attribs = primitive.mAttributes; - meshDefinition.mUri = attribs.begin()->second->mBufferView->mBuffer->mUri; + auto& attribs = primitive.mAttributes; meshDefinition.mPrimitiveType = GLTF2_TO_DALI_PRIMITIVES[primitive.mMode]; - auto& accPositions = *attribs.find(gt::Attribute::POSITION)->second; + auto& accPositions = *attribs.find(gt::Attribute::POSITION)->second; meshDefinition.mPositions = ConvertMeshPrimitiveAccessor(accPositions); // glTF2 support vector4 tangent for mesh. // https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#meshes-overview @@ -644,14 +705,14 @@ void ConvertMeshes(const gt::Document& doc, ConversionContext& context) auto iFind = attribs.find(am.mType); if(iFind != attribs.end()) { - DALI_ASSERT_DEBUG(iFind->second->mBufferView->mBuffer->mUri.compare(meshDefinition.mUri) == 0); auto& accessor = meshDefinition.*(am.mAccessor); accessor = ConvertMeshPrimitiveAccessor(*iFind->second); if(iFind->first == gt::Attribute::JOINTS_0) { meshDefinition.mFlags |= (iFind->second->mComponentType == gt::Component::UNSIGNED_SHORT) * MeshDefinition::U16_JOINT_IDS; - DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_JOINT_IDS) || iFind->second->mComponentType == gt::Component::FLOAT); + meshDefinition.mFlags |= (iFind->second->mComponentType == gt::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 == gt::Component::FLOAT); } } else if(needNormalsTangents) @@ -676,7 +737,8 @@ void ConvertMeshes(const gt::Document& doc, ConversionContext& context) { meshDefinition.mIndices = ConvertMeshPrimitiveAccessor(*primitive.mIndices); meshDefinition.mFlags |= (primitive.mIndices->mComponentType == gt::Component::UNSIGNED_INT) * MeshDefinition::U32_INDICES; - DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U32_INDICES) || primitive.mIndices->mComponentType == gt::Component::UNSIGNED_SHORT); + meshDefinition.mFlags |= (primitive.mIndices->mComponentType == gt::Component::UNSIGNED_BYTE) * MeshDefinition::U8_INDICES; + DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U32_INDICES) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_INDICES) || primitive.mIndices->mComponentType == gt::Component::UNSIGNED_SHORT); } if(!primitive.mTargets.empty()) @@ -730,10 +792,10 @@ ModelRenderable* MakeModelRenderable(const gt::Mesh::Primitive& prim, Conversion // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#default-material if(INVALID_INDEX == context.mDefaultMaterial) { - auto& outMaterials = context.mOutput.mResources.mMaterials; + auto& outMaterials = context.mOutput.mResources.mMaterials; context.mDefaultMaterial = outMaterials.size(); - ConvertMaterial(gt::Material{}, outMaterials); + ConvertMaterial(gt::Material{}, context.mOutput.mSceneMetadata.mImageMetadata, outMaterials, context); } materialIdx = context.mDefaultMaterial; @@ -814,8 +876,8 @@ void ConvertNode(gt::Node const& node, const Index gltfIdx, Index parentIdx, Con for(uint32_t i = 0; i < primitiveCount; ++i) { std::unique_ptr renderable; - auto modelRenderable = MakeModelRenderable(mesh.mPrimitives[i], context); - modelRenderable->mMeshIdx = meshIdx + i; + auto modelRenderable = MakeModelRenderable(mesh.mPrimitives[i], context); + modelRenderable->mMeshIdx = meshIdx + i; DALI_ASSERT_DEBUG(resources.mMeshes[modelRenderable->mMeshIdx].first.mSkeletonIdx == INVALID_INDEX || resources.mMeshes[modelRenderable->mMeshIdx].first.mSkeletonIdx == skeletonIdx); @@ -874,36 +936,49 @@ void ConvertSceneNodes(const gt::Scene& scene, ConversionContext& context, bool void ConvertNodes(const gt::Document& doc, ConversionContext& context, bool isMRendererModel) { - ConvertSceneNodes(*doc.mScene, context, isMRendererModel); - - for(uint32_t i = 0, i1 = doc.mScene.GetIndex(); i < i1; ++i) + if(!doc.mScenes.empty()) { - ConvertSceneNodes(doc.mScenes[i], context, isMRendererModel); - } + uint32_t rootSceneIndex = 0u; + if(doc.mScene) + { + rootSceneIndex = doc.mScene.GetIndex(); + } + ConvertSceneNodes(doc.mScenes[rootSceneIndex], context, isMRendererModel); - for(uint32_t i = doc.mScene.GetIndex() + 1; i < doc.mScenes.size(); ++i) - { - ConvertSceneNodes(doc.mScenes[i], context, isMRendererModel); + for(uint32_t i = 0, i1 = rootSceneIndex; i < i1; ++i) + { + ConvertSceneNodes(doc.mScenes[i], context, isMRendererModel); + } + + for(uint32_t i = rootSceneIndex + 1; i < doc.mScenes.size(); ++i) + { + ConvertSceneNodes(doc.mScenes[i], context, isMRendererModel); + } } } template -void LoadDataFromAccessor(const std::string& path, Vector& dataBuffer, uint32_t offset, uint32_t size) +void LoadDataFromAccessor(ConversionContext& context, uint32_t bufferIndex, Vector& dataBuffer, uint32_t offset, uint32_t size) { - std::ifstream animationBinaryFile(path, std::ifstream::binary); - - if(!animationBinaryFile.is_open()) + if(bufferIndex >= context.mOutput.mResources.mBuffers.size()) { - throw std::runtime_error("Failed to load " + path); + DALI_LOG_ERROR("Invailid buffer index\n"); + return; } - animationBinaryFile.seekg(offset); - animationBinaryFile.read(reinterpret_cast(dataBuffer.Begin()), size); - animationBinaryFile.close(); + auto& buffer = context.mOutput.mResources.mBuffers[bufferIndex]; + if(!buffer.IsAvailable()) + { + DALI_LOG_ERROR("Failed to load from buffer stream.\n"); + } + auto& stream = buffer.GetBufferStream(); + stream.clear(); + stream.seekg(offset, stream.beg); + stream.read(reinterpret_cast(dataBuffer.Begin()), size); } template -float LoadDataFromAccessors(const std::string& path, const gltf2::Accessor& input, const gltf2::Accessor& output, Vector& inputDataBuffer, Vector& outputDataBuffer) +float LoadDataFromAccessors(ConversionContext& context, const gltf2::Accessor& input, const gltf2::Accessor& output, Vector& inputDataBuffer, Vector& outputDataBuffer) { inputDataBuffer.Resize(input.mCount); outputDataBuffer.Resize(output.mCount); @@ -911,15 +986,15 @@ float LoadDataFromAccessors(const std::string& path, const gltf2::Accessor& inpu const uint32_t inputDataBufferSize = input.GetBytesLength(); const uint32_t outputDataBufferSize = output.GetBytesLength(); - LoadDataFromAccessor(path + std::string(input.mBufferView->mBuffer->mUri), inputDataBuffer, input.mBufferView->mByteOffset + input.mByteOffset, inputDataBufferSize); - LoadDataFromAccessor(path + std::string(output.mBufferView->mBuffer->mUri), outputDataBuffer, output.mBufferView->mByteOffset + output.mByteOffset, outputDataBufferSize); + LoadDataFromAccessor(context, output.mBufferView->mBuffer.GetIndex(), inputDataBuffer, input.mBufferView->mByteOffset + input.mByteOffset, inputDataBufferSize); + LoadDataFromAccessor(context, output.mBufferView->mBuffer.GetIndex(), outputDataBuffer, output.mBufferView->mByteOffset + output.mByteOffset, outputDataBufferSize); ApplyAccessorMinMax(output, reinterpret_cast(outputDataBuffer.begin())); return inputDataBuffer[input.mCount - 1u]; } template -float LoadKeyFrames(const std::string& path, const gt::Animation::Channel& channel, KeyFrames& keyFrames, gt::Animation::Channel::Target::Type type) +float LoadKeyFrames(ConversionContext& context, const gt::Animation::Channel& channel, KeyFrames& keyFrames, gt::Animation::Channel::Target::Type type) { const gltf2::Accessor& input = *channel.mSampler->mInput; const gltf2::Accessor& output = *channel.mSampler->mOutput; @@ -927,7 +1002,7 @@ float LoadKeyFrames(const std::string& path, const gt::Animation::Channel& chann Vector inputDataBuffer; Vector outputDataBuffer; - const float duration = LoadDataFromAccessors(path, input, output, inputDataBuffer, outputDataBuffer); + const float duration = std::max(LoadDataFromAccessors(context, input, output, inputDataBuffer, outputDataBuffer), AnimationDefinition::MIN_DURATION_SECONDS); for(uint32_t i = 0; i < input.mCount; ++i) { @@ -937,7 +1012,7 @@ float LoadKeyFrames(const std::string& path, const gt::Animation::Channel& chann return duration; } -float LoadBlendShapeKeyFrames(const std::string& path, const gt::Animation::Channel& channel, const std::string& nodeName, uint32_t& propertyIndex, std::vector& properties) +float LoadBlendShapeKeyFrames(ConversionContext& context, const gt::Animation::Channel& channel, Index nodeIndex, uint32_t& propertyIndex, std::vector& properties) { const gltf2::Accessor& input = *channel.mSampler->mInput; const gltf2::Accessor& output = *channel.mSampler->mOutput; @@ -945,7 +1020,7 @@ float LoadBlendShapeKeyFrames(const std::string& path, const gt::Animation::Chan Vector inputDataBuffer; Vector outputDataBuffer; - const float duration = LoadDataFromAccessors(path, input, output, inputDataBuffer, outputDataBuffer); + const float duration = LoadDataFromAccessors(context, input, output, inputDataBuffer, outputDataBuffer); char weightNameBuffer[32]; auto prefixSize = snprintf(weightNameBuffer, sizeof(weightNameBuffer), "%s[", BLEND_SHAPE_WEIGHTS_UNIFORM.c_str()); @@ -955,7 +1030,7 @@ float LoadBlendShapeKeyFrames(const std::string& path, const gt::Animation::Chan { AnimatedProperty& animatedProperty = properties[propertyIndex++]; - animatedProperty.mNodeName = nodeName; + animatedProperty.mNodeIndex = nodeIndex; snprintf(pWeightName, remainingSize, "%d]", weightIndex); animatedProperty.mPropertyName = std::string(weightNameBuffer); @@ -987,28 +1062,24 @@ void ConvertAnimations(const gt::Document& doc, ConversionContext& context) } uint32_t numberOfProperties = 0u; - - for(const auto& channel : animation.mChannels) - { - numberOfProperties += channel.mSampler->mOutput->mCount; - } - animationDef.mProperties.resize(numberOfProperties); - - Index propertyIndex = 0u; for(const auto& channel : animation.mChannels) { - std::string nodeName; - if(!channel.mTarget.mNode->mName.empty()) + if(channel.mTarget.mPath == gt::Animation::Channel::Target::WEIGHTS) { - nodeName = channel.mTarget.mNode->mName; + numberOfProperties += channel.mSampler->mOutput->mCount / channel.mSampler->mInput->mCount; } else { - Index index = context.mNodeIndices.GetRuntimeId(channel.mTarget.mNode.GetIndex()); - nodeName = context.mOutput.mScene.GetNode(index)->mName; + numberOfProperties++; } + } + animationDef.mProperties.resize(numberOfProperties); - float duration = 0.f; + Index propertyIndex = 0u; + for(const auto& channel : animation.mChannels) + { + Index nodeIndex = context.mNodeIndices.GetRuntimeId(channel.mTarget.mNode.GetIndex()); + float duration = 0.f; switch(channel.mTarget.mPath) { @@ -1016,11 +1087,11 @@ void ConvertAnimations(const gt::Document& doc, ConversionContext& context) { AnimatedProperty& animatedProperty = animationDef.mProperties[propertyIndex]; - animatedProperty.mNodeName = nodeName; + animatedProperty.mNodeIndex = nodeIndex; animatedProperty.mPropertyName = POSITION_PROPERTY; animatedProperty.mKeyFrames = KeyFrames::New(); - duration = LoadKeyFrames(context.mPath, channel, animatedProperty.mKeyFrames, channel.mTarget.mPath); + duration = LoadKeyFrames(context, channel, animatedProperty.mKeyFrames, channel.mTarget.mPath); animatedProperty.mTimePeriod = {0.f, duration}; break; @@ -1029,11 +1100,11 @@ void ConvertAnimations(const gt::Document& doc, ConversionContext& context) { AnimatedProperty& animatedProperty = animationDef.mProperties[propertyIndex]; - animatedProperty.mNodeName = nodeName; + animatedProperty.mNodeIndex = nodeIndex; animatedProperty.mPropertyName = ORIENTATION_PROPERTY; animatedProperty.mKeyFrames = KeyFrames::New(); - duration = LoadKeyFrames(context.mPath, channel, animatedProperty.mKeyFrames, channel.mTarget.mPath); + duration = LoadKeyFrames(context, channel, animatedProperty.mKeyFrames, channel.mTarget.mPath); animatedProperty.mTimePeriod = {0.f, duration}; break; @@ -1042,18 +1113,18 @@ void ConvertAnimations(const gt::Document& doc, ConversionContext& context) { AnimatedProperty& animatedProperty = animationDef.mProperties[propertyIndex]; - animatedProperty.mNodeName = nodeName; + animatedProperty.mNodeIndex = nodeIndex; animatedProperty.mPropertyName = SCALE_PROPERTY; animatedProperty.mKeyFrames = KeyFrames::New(); - duration = LoadKeyFrames(context.mPath, channel, animatedProperty.mKeyFrames, channel.mTarget.mPath); + duration = LoadKeyFrames(context, channel, animatedProperty.mKeyFrames, channel.mTarget.mPath); animatedProperty.mTimePeriod = {0.f, duration}; break; } case gt::Animation::Channel::Target::WEIGHTS: { - duration = LoadBlendShapeKeyFrames(context.mPath, channel, nodeName, propertyIndex, animationDef.mProperties); + duration = LoadBlendShapeKeyFrames(context, channel, nodeIndex, propertyIndex, animationDef.mProperties); break; } @@ -1088,17 +1159,21 @@ void ProcessSkins(const gt::Document& doc, ConversionContext& context) struct InverseBindMatrixAccessor : public IInverseBindMatrixProvider { - std::ifstream mStream; + std::istream& mStream; const uint32_t mElementSizeBytes; - InverseBindMatrixAccessor(const gt::Accessor& accessor, const std::string& path) - : mStream(path + std::string(accessor.mBufferView->mBuffer->mUri), std::ios::binary), + InverseBindMatrixAccessor(const gt::Accessor& accessor, ConversionContext& context) + : mStream(context.mOutput.mResources.mBuffers[accessor.mBufferView->mBuffer.GetIndex()].GetBufferStream()), mElementSizeBytes(accessor.GetElementSizeBytes()) { - DALI_ASSERT_ALWAYS(mStream); DALI_ASSERT_DEBUG(accessor.mType == gt::AccessorType::MAT4 && accessor.mComponentType == gt::Component::FLOAT); - mStream.seekg(accessor.mBufferView->mByteOffset + accessor.mByteOffset); + if(!mStream.rdbuf()->in_avail()) + { + DALI_LOG_ERROR("Failed to load from stream\n"); + } + mStream.clear(); + mStream.seekg(accessor.mBufferView->mByteOffset + accessor.mByteOffset, mStream.beg); } virtual void Provide(Matrix& ibm) override @@ -1118,12 +1193,12 @@ void ProcessSkins(const gt::Document& doc, ConversionContext& context) auto& resources = context.mOutput.mResources; resources.mSkeletons.reserve(doc.mSkins.size()); - for(auto& s : doc.mSkins) + for(auto& skin : doc.mSkins) { std::unique_ptr ibmProvider; - if(s.mInverseBindMatrices) + if(skin.mInverseBindMatrices) { - ibmProvider.reset(new InverseBindMatrixAccessor(*s.mInverseBindMatrices, context.mPath)); + ibmProvider.reset(new InverseBindMatrixAccessor(*skin.mInverseBindMatrices, context)); } else { @@ -1131,16 +1206,16 @@ void ProcessSkins(const gt::Document& doc, ConversionContext& context) } SkeletonDefinition skeleton; - if(s.mSkeleton.GetIndex() != INVALID_INDEX) + if(skin.mSkeleton.GetIndex() != INVALID_INDEX) { - skeleton.mRootNodeIdx = context.mNodeIndices.GetRuntimeId(s.mSkeleton.GetIndex()); + skeleton.mRootNodeIdx = context.mNodeIndices.GetRuntimeId(skin.mSkeleton.GetIndex()); } - skeleton.mJoints.resize(s.mJoints.size()); + skeleton.mJoints.resize(skin.mJoints.size()); auto iJoint = skeleton.mJoints.begin(); - for(auto& j : s.mJoints) + for(auto& joint : skin.mJoints) { - iJoint->mNodeIdx = context.mNodeIndices.GetRuntimeId(j.GetIndex()); + iJoint->mNodeIdx = context.mNodeIndices.GetRuntimeId(joint.GetIndex()); ibmProvider->Provide(iJoint->mInverseBindMatrix); @@ -1208,6 +1283,21 @@ void SetDefaultEnvironmentMap(const gt::Document& doc, ConversionContext& contex } // namespace +void InitializeGltfLoader() +{ + // Set ObjectReader only once (for all gltf loading). + static bool setObjectReadersRequired = true; + { + Mutex::ScopedLock lock(gInitializeMutex); + if(setObjectReadersRequired) + { + // NOTE: only referencing own, anonymous namespace, const objects; the pointers will never need to change. + SetObjectReaders(); + setObjectReadersRequired = false; + } + } +} + void LoadGltfScene(const std::string& url, ShaderDefinitionFactory& shaderFactory, LoadResult& params) { bool failed = false; @@ -1223,14 +1313,6 @@ void LoadGltfScene(const std::string& url, ShaderDefinitionFactory& shaderFactor throw std::runtime_error("Failed to parse " + url); } - static bool setObjectReaders = true; - if(setObjectReaders) - { - // NOTE: only referencing own, anonymous namespace, const objects; the pointers will never need to change. - SetObjectReaders(); - setObjectReaders = false; - } - gt::Document doc; auto& rootObj = js::Cast(*root); @@ -1250,12 +1332,16 @@ void LoadGltfScene(const std::string& url, ShaderDefinitionFactory& shaderFactor isMRendererModel = (doc.mAsset.mGenerator.find(MRENDERER_MODEL_IDENTIFICATION) != std::string_view::npos); } - gt::SetRefReaderObject(doc); - DOCUMENT_READER.Read(rootObj, doc); + { + Mutex::ScopedLock lock(gReadMutex); + gt::SetRefReaderObject(doc); + DOCUMENT_READER.Read(rootObj, doc); + } auto path = url.substr(0, url.rfind('/') + 1); ConversionContext context{params, path, INVALID_INDEX}; + ConvertBuffers(doc, context); ConvertMaterials(doc, context); ConvertMeshes(doc, context); ConvertNodes(doc, context, isMRendererModel);