X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-scene3d%2Fpublic-api%2Floader%2Fgltf2-loader.cpp;h=69bcd515f2e58a2ddee693437a90f273295149c9;hb=3da64a8d34ca7d92e78f018b583b8a15a52816bf;hp=60f6970bd9f3d2ca14de52161ef89232d125a4a2;hpb=02355fd2a819ea721f7e205f3ef9a493af97b25f;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 60f6970..69bcd51 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,20 +14,24 @@ * limitations under the License. * */ -#include "dali-scene3d/public-api/loader/gltf2-loader.h" -#include -#include "dali-scene3d/internal/loader/gltf2-asset.h" -#include "dali-scene3d/public-api/loader/load-result.h" -#include "dali-scene3d/public-api/loader/resource-bundle.h" -#include "dali-scene3d/public-api/loader/scene-definition.h" -#include "dali-scene3d/public-api/loader/shader-definition-factory.h" -#include "dali-scene3d/public-api/loader/utils.h" -#include "dali/public-api/math/quaternion.h" - -#define ENUM_STRING_MAPPING(t, x) \ - { \ -#x, t::x \ - } + +// FILE HEADER +#include + +// EXTERNAL INCLUDES +#include +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include +#include +#include +#include +#include namespace gt = gltf2; namespace js = json; @@ -40,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"); @@ -73,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) @@ -168,6 +172,19 @@ const auto MATERIAL_PBR_READER = std::move(js::Reader() .Register(*js::MakeProperty("roughnessFactor", js::Read::Number, >::Material::Pbr::mRoughnessFactor)) .Register(*js::MakeProperty("metallicRoughnessTexture", js::ObjectReader::Read, >::Material::Pbr::mMetallicRoughnessTexture))); +const auto MATERIAL_SPECULAR_READER = std::move(js::Reader() + .Register(*js::MakeProperty("specularFactor", js::Read::Number, >::MaterialSpecular::mSpecularFactor)) + .Register(*js::MakeProperty("specularTexture", js::ObjectReader::Read, >::MaterialSpecular::mSpecularTexture)) + .Register(*js::MakeProperty("specularColorFactor", gt::ReadDaliVector, >::MaterialSpecular::mSpecularColorFactor)) + .Register(*js::MakeProperty("specularColorTexture", js::ObjectReader::Read, >::MaterialSpecular::mSpecularColorTexture))); + +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))); + const auto MATERIAL_READER = std::move(js::Reader() .Register(*new js::Property("name", js::Read::StringView, >::Material::mName)) .Register(*js::MakeProperty("pbrMetallicRoughness", js::ObjectReader::Read, >::Material::mPbrMetallicRoughness)) @@ -176,7 +193,9 @@ const auto MATERIAL_READER = std::move(js::Reader() .Register(*js::MakeProperty("emissiveTexture", js::ObjectReader::Read, >::Material::mEmissiveTexture)) .Register(*js::MakeProperty("emissiveFactor", gt::ReadDaliVector, >::Material::mEmissiveFactor)) .Register(*js::MakeProperty("alphaMode", gt::ReadStringEnum, >::Material::mAlphaMode)) - .Register(*js::MakeProperty("alphaCutoff", js::Read::Number, >::Material::mAlphaCutoff))); + .Register(*js::MakeProperty("alphaCutoff", js::Read::Number, >::Material::mAlphaCutoff)) + .Register(*js::MakeProperty("doubleSided", js::Read::Boolean, >::Material::mDoubleSided)) + .Register(*js::MakeProperty("extensions", js::ObjectReader::Read, >::Material::mMaterialExtensions))); std::map> ReadMeshPrimitiveAttributes(const json_value_s& j) { @@ -388,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) +{ + 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(w) + switch(wrapMode) { case gt::Wrap::REPEAT: return SamplerFlags::WRAP_REPEAT; @@ -403,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 { @@ -420,33 +464,65 @@ 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()), static_cast(static_cast(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& m, 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 = m.mPbrMetallicRoughness; - if(m.mAlphaMode != gt::AlphaMode::OPAQUE || pbr.mBaseColorFactor.a < 1.f) + auto& pbr = material.mPbrMetallicRoughness; + if(material.mAlphaMode == gt::AlphaMode::BLEND) { + matDef.mIsOpaque = false; matDef.mFlags |= MaterialDefinition::TRANSPARENCY; } - - if(m.mAlphaMode == gt::AlphaMode::MASK) + else if(material.mAlphaMode == gt::AlphaMode::MASK) { - matDef.SetAlphaCutoff(std::min(1.f, std::max(0.f, m.mAlphaCutoff))); + matDef.mIsMask = true; + matDef.SetAlphaCutoff(std::min(1.f, std::max(0.f, material.mAlphaCutoff))); } matDef.mBaseColorFactor = pbr.mBaseColorFactor; - matDef.mTextureStages.reserve(!!pbr.mBaseColorTexture + !!pbr.mMetallicRoughnessTexture + !!m.mNormalTexture + !!m.mOcclusionTexture + !!m.mEmissiveTexture); + matDef.mTextureStages.reserve(!!pbr.mBaseColorTexture + !!pbr.mMetallicRoughnessTexture + !!material.mNormalTexture + !!material.mOcclusionTexture + !!material.mEmissiveTexture); 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; } @@ -462,7 +538,7 @@ void ConvertMaterial(const gt::Material& m, decltype(ResourceBundle::mMaterials) { 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; } @@ -471,11 +547,11 @@ void ConvertMaterial(const gt::Material& m, decltype(ResourceBundle::mMaterials) matDef.mNeedMetallicRoughnessTexture = false; } - matDef.mNormalScale = m.mNormalTexture.mScale; - if(m.mNormalTexture) + matDef.mNormalScale = material.mNormalTexture.mScale; + if(material.mNormalTexture) { const auto semantic = MaterialDefinition::NORMAL; - matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(m.mNormalTexture)}); + matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(material.mNormalTexture, context, getTextureMetaData(imageMetaData, material.mNormalTexture))}); // TODO: and there had better be one matDef.mFlags |= semantic; } @@ -484,36 +560,61 @@ void ConvertMaterial(const gt::Material& m, decltype(ResourceBundle::mMaterials) matDef.mNeedNormalTexture = false; } - // TODO: handle doubleSided - if(m.mOcclusionTexture) + if(material.mOcclusionTexture) { const auto semantic = MaterialDefinition::OCCLUSION; - matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(m.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 = m.mOcclusionTexture.mStrength; + matDef.mOcclusionStrength = material.mOcclusionTexture.mStrength; } - if(m.mEmissiveTexture) + if(material.mEmissiveTexture) { const auto semantic = MaterialDefinition::EMISSIVE; - matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(m.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 = m.mEmissiveFactor; + matDef.mEmissiveFactor = material.mEmissiveFactor; + } + + if(material.mMaterialExtensions.mMaterialIor.mIor < MAXFLOAT) + { + 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; + + if(material.mMaterialExtensions.mMaterialSpecular.mSpecularTexture) + { + const auto semantic = MaterialDefinition::SPECULAR; + 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, context, getTextureMetaData(imageMetaData, material.mMaterialExtensions.mMaterialSpecular.mSpecularColorTexture))}); + matDef.mFlags |= semantic; } + matDef.mDoubleSided = material.mDoubleSided; + outMaterials.emplace_back(std::move(matDef), TextureSet()); } -void ConvertMaterials(const gt::Document& doc, ConversionContext& cctx) +void ConvertMaterials(const gt::Document& doc, ConversionContext& context) { - auto& outMaterials = cctx.mOutput.mResources.mMaterials; + 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); } } @@ -567,36 +668,36 @@ 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& cctx) +void ConvertMeshes(const gt::Document& doc, ConversionContext& context) { uint32_t meshCount = 0; - cctx.mMeshIds.reserve(doc.mMeshes.size()); - for(auto& m : doc.mMeshes) + context.mMeshIds.reserve(doc.mMeshes.size()); + for(auto& mesh : doc.mMeshes) { - cctx.mMeshIds.push_back(meshCount); - meshCount += m.mPrimitives.size(); + context.mMeshIds.push_back(meshCount); + meshCount += mesh.mPrimitives.size(); } - auto& outMeshes = cctx.mOutput.mResources.mMeshes; + auto& outMeshes = context.mOutput.mResources.mMeshes; outMeshes.reserve(meshCount); - for(auto& m : doc.mMeshes) + for(auto& mesh : doc.mMeshes) { - for(auto& p : m.mPrimitives) + for(auto& primitive : mesh.mPrimitives) { - MeshDefinition meshDef; + MeshDefinition meshDefinition; - auto& attribs = p.mAttributes; - meshDef.mUri = attribs.begin()->second->mBufferView->mBuffer->mUri; - meshDef.mPrimitiveType = GLTF2_TO_DALI_PRIMITIVES[p.mMode]; + auto& attribs = primitive.mAttributes; + meshDefinition.mPrimitiveType = GLTF2_TO_DALI_PRIMITIVES[primitive.mMode]; - auto& accPositions = *attribs.find(gt::Attribute::POSITION)->second; - meshDef.mPositions = ConvertMeshPrimitiveAccessor(accPositions); + 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 - meshDef.mTangentType = Property::VECTOR4; + meshDefinition.mTangentType = Property::VECTOR4; const bool needNormalsTangents = accPositions.mType == gt::AccessorType::VEC3; for(auto& am : ATTRIBUTE_MAPPINGS) @@ -604,14 +705,14 @@ void ConvertMeshes(const gt::Document& doc, ConversionContext& cctx) auto iFind = attribs.find(am.mType); if(iFind != attribs.end()) { - DALI_ASSERT_DEBUG(iFind->second->mBufferView->mBuffer->mUri.compare(meshDef.mUri) == 0); - auto& accessor = meshDef.*(am.mAccessor); + auto& accessor = meshDefinition.*(am.mAccessor); accessor = ConvertMeshPrimitiveAccessor(*iFind->second); if(iFind->first == gt::Attribute::JOINTS_0) { - meshDef.mFlags |= (iFind->second->mComponentType == gt::Component::UNSIGNED_SHORT) * MeshDefinition::U16_JOINT_IDS; - DALI_ASSERT_DEBUG(MaskMatch(meshDef.mFlags, MeshDefinition::U16_JOINT_IDS) || iFind->second->mComponentType == gt::Component::FLOAT); + meshDefinition.mFlags |= (iFind->second->mComponentType == gt::Component::UNSIGNED_SHORT) * MeshDefinition::U16_JOINT_IDS; + 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) @@ -619,11 +720,11 @@ void ConvertMeshes(const gt::Document& doc, ConversionContext& cctx) switch(am.mType) { case gt::Attribute::NORMAL: - meshDef.RequestNormals(); + meshDefinition.RequestNormals(); break; case gt::Attribute::TANGENT: - meshDef.RequestTangents(); + meshDefinition.RequestTangents(); break; default: @@ -632,18 +733,19 @@ void ConvertMeshes(const gt::Document& doc, ConversionContext& cctx) } } - if(p.mIndices) + if(primitive.mIndices) { - meshDef.mIndices = ConvertMeshPrimitiveAccessor(*p.mIndices); - meshDef.mFlags |= (p.mIndices->mComponentType == gt::Component::UNSIGNED_INT) * MeshDefinition::U32_INDICES; - DALI_ASSERT_DEBUG(MaskMatch(meshDef.mFlags, MeshDefinition::U32_INDICES) || p.mIndices->mComponentType == gt::Component::UNSIGNED_SHORT); + meshDefinition.mIndices = ConvertMeshPrimitiveAccessor(*primitive.mIndices); + meshDefinition.mFlags |= (primitive.mIndices->mComponentType == gt::Component::UNSIGNED_INT) * MeshDefinition::U32_INDICES; + 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(!p.mTargets.empty()) + if(!primitive.mTargets.empty()) { - meshDef.mBlendShapes.reserve(p.mTargets.size()); - meshDef.mBlendShapeVersion = BlendShapes::Version::VERSION_2_0; - for(const auto& target : p.mTargets) + meshDefinition.mBlendShapes.reserve(primitive.mTargets.size()); + meshDefinition.mBlendShapeVersion = BlendShapes::Version::VERSION_2_0; + for(const auto& target : primitive.mTargets) { MeshDefinition::BlendShape blendShape; @@ -664,44 +766,44 @@ void ConvertMeshes(const gt::Document& doc, ConversionContext& cctx) blendShape.tangents = ConvertMeshPrimitiveAccessor(*it->second); } - if(!m.mWeights.empty()) + if(!mesh.mWeights.empty()) { - blendShape.weight = m.mWeights[meshDef.mBlendShapes.size()]; + blendShape.weight = mesh.mWeights[meshDefinition.mBlendShapes.size()]; } - meshDef.mBlendShapes.push_back(std::move(blendShape)); + meshDefinition.mBlendShapes.push_back(std::move(blendShape)); } } - outMeshes.push_back({std::move(meshDef), MeshGeometry{}}); + outMeshes.push_back({std::move(meshDefinition), MeshGeometry{}}); } } } -ModelNode* MakeModelNode(const gt::Mesh::Primitive& prim, ConversionContext& cctx) +ModelRenderable* MakeModelRenderable(const gt::Mesh::Primitive& prim, ConversionContext& context) { - auto modelNode = new ModelNode(); + auto modelRenderable = new ModelRenderable(); - modelNode->mShaderIdx = 0; // TODO: further thought + modelRenderable->mShaderIdx = 0; // TODO: further thought auto materialIdx = prim.mMaterial.GetIndex(); if(INVALID_INDEX == materialIdx) { // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#default-material - if(INVALID_INDEX == cctx.mDefaultMaterial) + if(INVALID_INDEX == context.mDefaultMaterial) { - auto& outMaterials = cctx.mOutput.mResources.mMaterials; - cctx.mDefaultMaterial = outMaterials.size(); + auto& outMaterials = context.mOutput.mResources.mMaterials; + context.mDefaultMaterial = outMaterials.size(); - ConvertMaterial(gt::Material{}, outMaterials); + ConvertMaterial(gt::Material{}, context.mOutput.mSceneMetadata.mImageMetadata, outMaterials, context); } - materialIdx = cctx.mDefaultMaterial; + materialIdx = context.mDefaultMaterial; } - modelNode->mMaterialIdx = materialIdx; + modelRenderable->mMaterialIdx = materialIdx; - return modelNode; + return modelRenderable; } void ConvertCamera(const gt::Camera& camera, CameraParameters& camParams) @@ -725,9 +827,9 @@ void ConvertCamera(const gt::Camera& camera, CameraParameters& camParams) } } -void ConvertNode(gt::Node const& node, const Index gltfIdx, Index parentIdx, ConversionContext& cctx, bool isMRendererModel) +void ConvertNode(gt::Node const& node, const Index gltfIdx, Index parentIdx, ConversionContext& context, bool isMRendererModel) { - auto& output = cctx.mOutput; + auto& output = context.mOutput; auto& scene = output.mScene; auto& resources = output.mResources; @@ -762,42 +864,27 @@ void ConvertNode(gt::Node const& node, const Index gltfIdx, Index parentIdx, Con ExceptionFlinger(ASSERT_LOCATION) << "Node name '" << node.mName << "' is not unique; scene is invalid."; } - cctx.mNodeIndices.RegisterMapping(gltfIdx, idx); + context.mNodeIndices.RegisterMapping(gltfIdx, idx); Index skeletonIdx = node.mSkin ? node.mSkin.GetIndex() : INVALID_INDEX; - if(node.mMesh && !node.mMesh->mPrimitives.empty()) + if(node.mMesh) { - auto& mesh = *node.mMesh; - - auto iPrim = mesh.mPrimitives.begin(); - auto modelNode = MakeModelNode(*iPrim, cctx); - auto meshIdx = cctx.mMeshIds[node.mMesh.GetIndex()]; - modelNode->mMeshIdx = meshIdx; - - weakNode->mRenderable.reset(modelNode); - - DALI_ASSERT_DEBUG(resources.mMeshes[meshIdx].first.mSkeletonIdx == INVALID_INDEX || - resources.mMeshes[meshIdx].first.mSkeletonIdx == skeletonIdx); - resources.mMeshes[meshIdx].first.mSkeletonIdx = skeletonIdx; - - // As does model-exporter, we'll create anonymous child nodes for additional mesh( primitiv)es. - while(++iPrim != mesh.mPrimitives.end()) + auto& mesh = *node.mMesh; + uint32_t primitiveCount = mesh.mPrimitives.size(); + auto meshIdx = context.mMeshIds[node.mMesh.GetIndex()]; + weakNode->mRenderables.reserve(primitiveCount); + for(uint32_t i = 0; i < primitiveCount; ++i) { - std::unique_ptr child{new NodeDefinition}; - child->mParentIdx = idx; - - auto childModel = MakeModelNode(*iPrim, cctx); - - ++meshIdx; - childModel->mMeshIdx = meshIdx; - - child->mRenderable.reset(childModel); + std::unique_ptr renderable; + auto modelRenderable = MakeModelRenderable(mesh.mPrimitives[i], context); + modelRenderable->mMeshIdx = meshIdx + i; - scene.AddNode(std::move(child)); + DALI_ASSERT_DEBUG(resources.mMeshes[modelRenderable->mMeshIdx].first.mSkeletonIdx == INVALID_INDEX || + resources.mMeshes[modelRenderable->mMeshIdx].first.mSkeletonIdx == skeletonIdx); + resources.mMeshes[modelRenderable->mMeshIdx].first.mSkeletonIdx = skeletonIdx; - DALI_ASSERT_DEBUG(resources.mMeshes[meshIdx].first.mSkeletonIdx == INVALID_INDEX || - resources.mMeshes[meshIdx].first.mSkeletonIdx == skeletonIdx); - resources.mMeshes[meshIdx].first.mSkeletonIdx = skeletonIdx; + renderable.reset(modelRenderable); + weakNode->mRenderables.push_back(std::move(renderable)); } } @@ -812,13 +899,13 @@ void ConvertNode(gt::Node const& node, const Index gltfIdx, Index parentIdx, Con for(auto& n : node.mChildren) { - ConvertNode(*n, n.GetIndex(), idx, cctx, isMRendererModel); + ConvertNode(*n, n.GetIndex(), idx, context, isMRendererModel); } } -void ConvertSceneNodes(const gt::Scene& scene, ConversionContext& cctx, bool isMRendererModel) +void ConvertSceneNodes(const gt::Scene& scene, ConversionContext& context, bool isMRendererModel) { - auto& outScene = cctx.mOutput.mScene; + auto& outScene = context.mOutput.mScene; Index rootIdx = outScene.GetNodeCount(); switch(scene.mNodes.size()) { @@ -826,7 +913,7 @@ void ConvertSceneNodes(const gt::Scene& scene, ConversionContext& cctx, bool isM break; case 1: - ConvertNode(*scene.mNodes[0], scene.mNodes[0].GetIndex(), INVALID_INDEX, cctx, isMRendererModel); + ConvertNode(*scene.mNodes[0], scene.mNodes[0].GetIndex(), INVALID_INDEX, context, isMRendererModel); outScene.AddRootNode(rootIdx); break; @@ -840,45 +927,58 @@ void ConvertSceneNodes(const gt::Scene& scene, ConversionContext& cctx, bool isM for(auto& n : scene.mNodes) { - ConvertNode(*n, n.GetIndex(), rootIdx, cctx, isMRendererModel); + ConvertNode(*n, n.GetIndex(), rootIdx, context, isMRendererModel); } break; } } } -void ConvertNodes(const gt::Document& doc, ConversionContext& cctx, bool isMRendererModel) +void ConvertNodes(const gt::Document& doc, ConversionContext& context, bool isMRendererModel) { - ConvertSceneNodes(*doc.mScene, cctx, isMRendererModel); - - for(uint32_t i = 0, i1 = doc.mScene.GetIndex(); i < i1; ++i) + if(!doc.mScenes.empty()) { - ConvertSceneNodes(doc.mScenes[i], cctx, 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], cctx, 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()), static_cast(static_cast(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); @@ -886,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; @@ -902,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) { @@ -912,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; @@ -920,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()); @@ -930,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); @@ -946,9 +1046,9 @@ float LoadBlendShapeKeyFrames(const std::string& path, const gt::Animation::Chan return duration; } -void ConvertAnimations(const gt::Document& doc, ConversionContext& cctx) +void ConvertAnimations(const gt::Document& doc, ConversionContext& context) { - auto& output = cctx.mOutput; + auto& output = context.mOutput; output.mAnimationDefinitions.reserve(output.mAnimationDefinitions.size() + doc.mAnimations.size()); @@ -962,28 +1062,24 @@ void ConvertAnimations(const gt::Document& doc, ConversionContext& cctx) } 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 = cctx.mNodeIndices.GetRuntimeId(channel.mTarget.mNode.GetIndex()); - nodeName = cctx.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) { @@ -991,11 +1087,11 @@ void ConvertAnimations(const gt::Document& doc, ConversionContext& cctx) { AnimatedProperty& animatedProperty = animationDef.mProperties[propertyIndex]; - animatedProperty.mNodeName = nodeName; + animatedProperty.mNodeIndex = nodeIndex; animatedProperty.mPropertyName = POSITION_PROPERTY; animatedProperty.mKeyFrames = KeyFrames::New(); - duration = LoadKeyFrames(cctx.mPath, channel, animatedProperty.mKeyFrames, channel.mTarget.mPath); + duration = LoadKeyFrames(context, channel, animatedProperty.mKeyFrames, channel.mTarget.mPath); animatedProperty.mTimePeriod = {0.f, duration}; break; @@ -1004,11 +1100,11 @@ void ConvertAnimations(const gt::Document& doc, ConversionContext& cctx) { AnimatedProperty& animatedProperty = animationDef.mProperties[propertyIndex]; - animatedProperty.mNodeName = nodeName; + animatedProperty.mNodeIndex = nodeIndex; animatedProperty.mPropertyName = ORIENTATION_PROPERTY; animatedProperty.mKeyFrames = KeyFrames::New(); - duration = LoadKeyFrames(cctx.mPath, channel, animatedProperty.mKeyFrames, channel.mTarget.mPath); + duration = LoadKeyFrames(context, channel, animatedProperty.mKeyFrames, channel.mTarget.mPath); animatedProperty.mTimePeriod = {0.f, duration}; break; @@ -1017,18 +1113,18 @@ void ConvertAnimations(const gt::Document& doc, ConversionContext& cctx) { AnimatedProperty& animatedProperty = animationDef.mProperties[propertyIndex]; - animatedProperty.mNodeName = nodeName; + animatedProperty.mNodeIndex = nodeIndex; animatedProperty.mPropertyName = SCALE_PROPERTY; animatedProperty.mKeyFrames = KeyFrames::New(); - duration = LoadKeyFrames(cctx.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(cctx.mPath, channel, nodeName, propertyIndex, animationDef.mProperties); + duration = LoadBlendShapeKeyFrames(context, channel, nodeIndex, propertyIndex, animationDef.mProperties); break; } @@ -1048,7 +1144,7 @@ void ConvertAnimations(const gt::Document& doc, ConversionContext& cctx) } } -void ProcessSkins(const gt::Document& doc, ConversionContext& cctx) +void ProcessSkins(const gt::Document& doc, ConversionContext& context) { // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skininversebindmatrices // If an inverseBindMatrices accessor was provided, we'll load the joint data from the buffer, @@ -1063,22 +1159,26 @@ void ProcessSkins(const gt::Document& doc, ConversionContext& cctx) 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 { - DALI_ASSERT_ALWAYS(mStream.read(reinterpret_cast(ibm.AsFloat()), mElementSizeBytes)); + DALI_ASSERT_ALWAYS(mStream.read(reinterpret_cast(ibm.AsFloat()), static_cast(static_cast(mElementSizeBytes)))); } }; @@ -1090,15 +1190,15 @@ void ProcessSkins(const gt::Document& doc, ConversionContext& cctx) } }; - auto& resources = cctx.mOutput.mResources; + 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, cctx.mPath)); + ibmProvider.reset(new InverseBindMatrixAccessor(*skin.mInverseBindMatrices, context)); } else { @@ -1106,16 +1206,16 @@ void ProcessSkins(const gt::Document& doc, ConversionContext& cctx) } SkeletonDefinition skeleton; - if(s.mSkeleton.GetIndex() != INVALID_INDEX) + if(skin.mSkeleton.GetIndex() != INVALID_INDEX) { - skeleton.mRootNodeIdx = cctx.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 = cctx.mNodeIndices.GetRuntimeId(j.GetIndex()); + iJoint->mNodeIdx = context.mNodeIndices.GetRuntimeId(joint.GetIndex()); ibmProvider->Provide(iJoint->mInverseBindMatrix); @@ -1128,12 +1228,16 @@ void ProcessSkins(const gt::Document& doc, ConversionContext& cctx) void ProduceShaders(ShaderDefinitionFactory& shaderFactory, SceneDefinition& scene) { - for(size_t i0 = 0, i1 = scene.GetNodeCount(); i0 != i1; ++i0) + uint32_t nodeCount = scene.GetNodeCount(); + for(uint32_t i = 0; i < nodeCount; ++i) { - auto nodeDef = scene.GetNode(i0); - if(auto renderable = nodeDef->mRenderable.get()) + auto nodeDef = scene.GetNode(i); + for(auto& renderable : nodeDef->mRenderables) { - renderable->mShaderIdx = shaderFactory.ProduceShader(*nodeDef); + if(shaderFactory.ProduceShader(*renderable) == INVALID_INDEX) + { + DALI_LOG_ERROR("Fail to produce shader\n"); + } } } } @@ -1151,6 +1255,9 @@ void SetObjectReaders() js::SetObjectReader(TEXURE_READER); js::SetObjectReader(TEXURE_INFO_READER); js::SetObjectReader(MATERIAL_PBR_READER); + js::SetObjectReader(MATERIAL_SPECULAR_READER); + js::SetObjectReader(MATERIAL_IOR_READER); + js::SetObjectReader(MATERIAL_EXTENSION_READER); js::SetObjectReader(MATERIAL_READER); js::SetObjectReader(MESH_PRIMITIVE_READER); js::SetObjectReader(MESH_READER); @@ -1166,16 +1273,31 @@ void SetObjectReaders() js::SetObjectReader(SCENE_READER); } -void SetDefaultEnvironmentMap(const gt::Document& doc, ConversionContext& cctx) +void SetDefaultEnvironmentMap(const gt::Document& doc, ConversionContext& context) { EnvironmentDefinition envDef; envDef.mUseBrdfTexture = true; envDef.mIblIntensity = Scene3D::Loader::EnvironmentDefinition::GetDefaultIntensity(); - cctx.mOutput.mResources.mEnvironmentMaps.push_back({std::move(envDef), EnvironmentDefinition::Textures()}); + context.mOutput.mResources.mEnvironmentMaps.push_back({std::move(envDef), EnvironmentDefinition::Textures()}); } } // 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; @@ -1191,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); @@ -1218,22 +1332,26 @@ 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 cctx{params, path, INVALID_INDEX}; - - ConvertMaterials(doc, cctx); - ConvertMeshes(doc, cctx); - ConvertNodes(doc, cctx, isMRendererModel); - ConvertAnimations(doc, cctx); - ProcessSkins(doc, cctx); + ConversionContext context{params, path, INVALID_INDEX}; + + ConvertBuffers(doc, context); + ConvertMaterials(doc, context); + ConvertMeshes(doc, context); + ConvertNodes(doc, context, isMRendererModel); + ConvertAnimations(doc, context); + ProcessSkins(doc, context); ProduceShaders(shaderFactory, params.mScene); params.mScene.EnsureUniqueSkinningShaderInstances(params.mResources); // Set Default Environment map - SetDefaultEnvironmentMap(doc, cctx); + SetDefaultEnvironmentMap(doc, context); } } // namespace Loader