From 35ea9a04faa2f2fdca4d8d4a378ac4524896e15b Mon Sep 17 00:00:00 2001 From: Richard Date: Wed, 16 Nov 2022 14:56:40 +0000 Subject: [PATCH] Texture size reduction on the fly for 3D model using metadata Change-Id: Id07b93141797569bc99496c8baa9f72e6a4dde15 --- automated-tests/resources/AnimatedCube.metadata | 17 +++ .../src/dali-scene3d/utc-Dali-DliLoader.cpp | 13 ++- .../src/dali-scene3d/utc-Dali-Gltf2Loader.cpp | 87 +++++++++++--- .../internal/controls/model/model-impl.cpp | 9 +- dali-scene3d/internal/loader/gltf2-asset.cpp | 70 ++---------- dali-scene3d/internal/loader/gltf2-asset.h | 35 ++++-- dali-scene3d/public-api/file.list | 1 + dali-scene3d/public-api/loader/gltf2-loader.cpp | 70 +++++++----- dali-scene3d/public-api/loader/load-result.h | 14 ++- .../public-api/loader/load-scene-metadata.cpp | 126 +++++++++++++++++++++ .../public-api/loader/load-scene-metadata.h | 66 +++++++++++ .../public-api/loader/material-definition.cpp | 26 +++-- .../public-api/loader/material-definition.h | 5 +- 13 files changed, 405 insertions(+), 134 deletions(-) create mode 100644 automated-tests/resources/AnimatedCube.metadata create mode 100644 dali-scene3d/public-api/loader/load-scene-metadata.cpp create mode 100644 dali-scene3d/public-api/loader/load-scene-metadata.h diff --git a/automated-tests/resources/AnimatedCube.metadata b/automated-tests/resources/AnimatedCube.metadata new file mode 100644 index 0000000..70b5b7f --- /dev/null +++ b/automated-tests/resources/AnimatedCube.metadata @@ -0,0 +1,17 @@ + { + "images": [ + { + "uri": "AnimatedCube_BaseColor.png", + "minWidth": 256, + "minHeight": 256, + "samplingMode": "BOX_THEN_NEAREST" + }, + { + "uri": "AnimatedCube_MetallicRoughness.png", + "minWidth": 256, + "minHeight": 256, + "samplingMode": "NEAREST" + } + ] +} + diff --git a/automated-tests/src/dali-scene3d/utc-Dali-DliLoader.cpp b/automated-tests/src/dali-scene3d/utc-Dali-DliLoader.cpp index 6a33200..c663327 100644 --- a/automated-tests/src/dali-scene3d/utc-Dali-DliLoader.cpp +++ b/automated-tests/src/dali-scene3d/utc-Dali-DliLoader.cpp @@ -18,13 +18,13 @@ // Enable debug log for test coverage #define DEBUG_ENABLED 1 +#include +#include +#include +#include +#include #include #include -#include "dali-scene3d/internal/loader/json-util.h" -#include "dali-scene3d/public-api/loader/dli-loader.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" using namespace Dali; using namespace Dali::Scene3D::Loader; @@ -61,9 +61,12 @@ struct Context std::vector animations; std::vector animGroups; + SceneMetadata metaData; + LoadResult output{ resources, scene, + metaData, animations, animGroups, cameraParameters, diff --git a/automated-tests/src/dali-scene3d/utc-Dali-Gltf2Loader.cpp b/automated-tests/src/dali-scene3d/utc-Dali-Gltf2Loader.cpp index d6687c5..eb19c4d 100644 --- a/automated-tests/src/dali-scene3d/utc-Dali-Gltf2Loader.cpp +++ b/automated-tests/src/dali-scene3d/utc-Dali-Gltf2Loader.cpp @@ -18,13 +18,13 @@ // Enable debug log for test coverage #define DEBUG_ENABLED 1 +#include +#include +#include +#include +#include #include #include -#include "dali-scene3d/public-api/loader/gltf2-loader.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" using namespace Dali; using namespace Dali::Scene3D::Loader; @@ -61,6 +61,7 @@ struct Context ResourceBundle resources; SceneDefinition scene; + SceneMetadata metaData; std::vector animations; std::vector animationGroups; @@ -70,6 +71,7 @@ struct Context LoadResult loadResult{ resources, scene, + metaData, animations, animationGroups, cameras, @@ -153,6 +155,21 @@ int UtcDaliGltfLoaderSuccess1(void) { Context ctx; + LoadSceneMetadata(TEST_RESOURCE_DIR "/AnimatedCube.metadata", ctx.metaData); + + std::unordered_map imageMetadataGroundTruth; + imageMetadataGroundTruth["AnimatedCube_BaseColor.png"] = ImageMetadata{ImageDimensions(256, 256), Dali::SamplingMode::BOX_THEN_NEAREST}; + imageMetadataGroundTruth["AnimatedCube_MetallicRoughness.png"] = ImageMetadata{ImageDimensions(256, 256), Dali::SamplingMode::NEAREST}; + + auto metaData = ctx.metaData.mImageMetadata.begin(); + for(auto& groundTruth : imageMetadataGroundTruth) + { + DALI_TEST_EQUAL(groundTruth.first, metaData->first); + DALI_TEST_EQUAL(groundTruth.second.mMinSize, metaData->second.mMinSize); + DALI_TEST_EQUAL(groundTruth.second.mSamplingMode, metaData->second.mSamplingMode); + ++metaData; + } + ShaderDefinitionFactory sdf; sdf.SetResources(ctx.resources); @@ -164,6 +181,17 @@ int UtcDaliGltfLoaderSuccess1(void) // Default envmap is used DALI_TEST_EQUAL(1u, ctx.resources.mEnvironmentMaps.size()); + TestApplication app; + + Customization::Choices choices; + for(auto iRoot : ctx.scene.GetRoots()) + { + auto resourceRefs = ctx.resources.CreateRefCounter(); + ctx.scene.CountResourceRefs(iRoot, choices, resourceRefs); + ctx.resources.CountEnvironmentReferences(resourceRefs); + ctx.resources.LoadResources(resourceRefs, ctx.pathProvider); + } + auto& materials = ctx.resources.mMaterials; DALI_TEST_EQUAL(2u, materials.size()); const MaterialDefinition materialGroundTruth[]{ @@ -188,22 +216,34 @@ int UtcDaliGltfLoaderSuccess1(void) { {MaterialDefinition::ALBEDO, {"AnimatedCube_BaseColor.png", - SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}}, + SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT), + ImageDimensions(256, 256), + SamplingMode::BOX_THEN_NEAREST}}, {MaterialDefinition::NORMAL, {"AnimatedCube_BaseColor.png", - SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}}, + SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT), + ImageDimensions(256, 256), + SamplingMode::BOX_THEN_NEAREST}}, {MaterialDefinition::OCCLUSION, {"AnimatedCube_BaseColor.png", - SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}}, + SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT), + ImageDimensions(256, 256), + SamplingMode::BOX_THEN_NEAREST}}, {MaterialDefinition::EMISSIVE, {"AnimatedCube_BaseColor.png", - SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}}, + SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT), + ImageDimensions(256, 256), + SamplingMode::BOX_THEN_NEAREST}}, {MaterialDefinition::SPECULAR, {"AnimatedCube_BaseColor.png", - SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}}, + SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT), + ImageDimensions(256, 256), + SamplingMode::BOX_THEN_NEAREST}}, {MaterialDefinition::SPECULAR_COLOR, {"AnimatedCube_BaseColor.png", - SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}}, + SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT), + ImageDimensions(256, 256), + SamplingMode::BOX_THEN_NEAREST}}, }}, {MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS | MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION | @@ -226,23 +266,34 @@ int UtcDaliGltfLoaderSuccess1(void) { {MaterialDefinition::ALBEDO, {"AnimatedCube_BaseColor.png", - SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}}, + SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT), + ImageDimensions(256, 256), + SamplingMode::BOX_THEN_NEAREST}}, {MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS | MaterialDefinition::GLTF_CHANNELS, {"AnimatedCube_MetallicRoughness.png", - SamplerFlags::Encode(FilterMode::NEAREST_MIPMAP_LINEAR, FilterMode::NEAREST, WrapMode::CLAMP_TO_EDGE, WrapMode::MIRRORED_REPEAT)}}, + SamplerFlags::Encode(FilterMode::NEAREST_MIPMAP_LINEAR, FilterMode::NEAREST, WrapMode::CLAMP_TO_EDGE, WrapMode::MIRRORED_REPEAT), + ImageDimensions(256, 256), + SamplingMode::NEAREST}}, {MaterialDefinition::NORMAL, {"AnimatedCube_BaseColor.png", - SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}}, + SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT), + ImageDimensions(256, 256), + SamplingMode::BOX_THEN_NEAREST}}, {MaterialDefinition::OCCLUSION, {"AnimatedCube_BaseColor.png", - SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}}, + SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT), + ImageDimensions(256, 256), + SamplingMode::BOX_THEN_NEAREST}}, {MaterialDefinition::EMISSIVE, {"AnimatedCube_BaseColor.png", - SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}}, + SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT), + ImageDimensions(256, 256), + SamplingMode::BOX_THEN_NEAREST}}, }}, }; auto iMaterial = materials.begin(); + auto iMetadata = ctx.metaData.mImageMetadata.begin(); for(auto& m : materialGroundTruth) { printf("material %ld\n", iMaterial - materials.begin()); @@ -271,9 +322,13 @@ int UtcDaliGltfLoaderSuccess1(void) DALI_TEST_EQUAL(iTexture->mSemantic, ts.mSemantic); DALI_TEST_EQUAL(iTexture->mTexture.mImageUri, ts.mTexture.mImageUri); DALI_TEST_EQUAL(uint32_t(iTexture->mTexture.mSamplerFlags), uint32_t(ts.mTexture.mSamplerFlags)); // don't interpret it as a character + DALI_TEST_EQUAL(iTexture->mTexture.mMinImageDimensions, ts.mTexture.mMinImageDimensions); + DALI_TEST_EQUAL(iTexture->mTexture.mSamplingMode, ts.mTexture.mSamplingMode); + ++iTexture; } ++iMaterial; + ++iMetadata; } auto& meshes = ctx.resources.mMeshes; diff --git a/dali-scene3d/internal/controls/model/model-impl.cpp b/dali-scene3d/internal/controls/model/model-impl.cpp index 86893a7..73f1248 100644 --- a/dali-scene3d/internal/controls/model/model-impl.cpp +++ b/dali-scene3d/internal/controls/model/model-impl.cpp @@ -425,7 +425,14 @@ void Model::LoadModel() std::vector animations; animations.clear(); - Dali::Scene3D::Loader::LoadResult output{resources, scene, animations, animGroups, cameraParameters, lights}; + Dali::Scene3D::Loader::SceneMetadata metaData; + + std::filesystem::path metaDataUrl = modelUrl; + metaDataUrl.replace_extension("metadata"); + + Dali::Scene3D::Loader::LoadSceneMetadata(metaDataUrl.c_str(), metaData); + + Dali::Scene3D::Loader::LoadResult output{resources, scene, metaData, animations, animGroups, cameraParameters, lights}; if(extension == DLI_EXTENSION) { diff --git a/dali-scene3d/internal/loader/gltf2-asset.cpp b/dali-scene3d/internal/loader/gltf2-asset.cpp index 8297045..a747405 100644 --- a/dali-scene3d/internal/loader/gltf2-asset.cpp +++ b/dali-scene3d/internal/loader/gltf2-asset.cpp @@ -14,15 +14,14 @@ * limitations under the License. * */ -#include "dali-scene3d/internal/loader/gltf2-asset.h" + +// EXTERNAL INCLUDES +#include #include #include -#include "dali/public-api/math/matrix.h" -#define ENUM_STRING_MAPPING(t, x) \ - { \ -#x, t::x \ - } +// INTERNAL INCLUDES +#include using namespace Dali; @@ -82,6 +81,12 @@ const std::map ANIMATION_CHA } // namespace +ENUM_TYPE_FROM_STRING(AccessorType, ACCESSOR_TYPES) +ENUM_TYPE_FROM_STRING(AlphaMode, ALPHA_MODE_TYPES) +ENUM_TYPE_FROM_STRING(Attribute, ATTRIBUTE_TYPES) +ENUM_TYPE_FROM_STRING(Animation::Sampler::Interpolation, ANIMATION_SAMPLER_INTERPOLATION) +ENUM_TYPE_FROM_STRING(Animation::Channel::Target, ANIMATION_CHANNEL_TARGET_PATH_TYPES) + bool Component::IsUnsigned(Type t) { return t == UNSIGNED_BYTE || t == UNSIGNED_SHORT || t == UNSIGNED_INT; @@ -110,64 +115,11 @@ uint32_t AccessorType::ElementCount(Type t) return ACCESSOR_TYPE_ELEMENT_COUNT[t]; } -AccessorType::Type AccessorType::FromString(const char* s, size_t len) -{ - auto iFind = ACCESSOR_TYPES.find(std::string_view(s, len)); - if(iFind != ACCESSOR_TYPES.end()) - { - return iFind->second; - } - return AccessorType::INVALID; -} - -AlphaMode::Type AlphaMode::FromString(const char* s, size_t len) -{ - auto iFind = ALPHA_MODE_TYPES.find(std::string_view(s, len)); - if(iFind != ALPHA_MODE_TYPES.end()) - { - return iFind->second; - } - return AlphaMode::INVALID; -} - -Attribute::Type Attribute::FromString(const char* s, size_t len) -{ - auto iFind = ATTRIBUTE_TYPES.find(std::string_view(s, len)); - if(iFind != ATTRIBUTE_TYPES.end()) - { - return iFind->second; - } - return Attribute::INVALID; -} - -Animation::Sampler::Interpolation::Type Animation::Sampler::Interpolation::FromString(const char* s, size_t len) -{ - auto iFind = ANIMATION_SAMPLER_INTERPOLATION.find(std::string_view(s, len)); - if(iFind != ANIMATION_SAMPLER_INTERPOLATION.end()) - { - return iFind->second; - } - return Animation::Sampler::Interpolation::Type::INVALID; -} - uint32_t ComponentTypedBufferViewClient::GetBytesPerComponent() const { return Component::Size(mComponentType); } -Animation::Channel::Target::Type Animation::Channel::Target::FromString(const char* s, size_t len) -{ - std::string target(s, len); - std::transform(target.begin(), target.end(), target.begin(), ::toupper); - - auto iFind = ANIMATION_CHANNEL_TARGET_PATH_TYPES.find(std::string_view(target.c_str(), len)); - if(iFind != ANIMATION_CHANNEL_TARGET_PATH_TYPES.end()) - { - return iFind->second; - } - return Animation::Channel::Target::INVALID; -}; - void Node::SetMatrix(const Matrix& m) { m.GetTransformComponents(mTranslation, mRotation, mScale); diff --git a/dali-scene3d/internal/loader/gltf2-asset.h b/dali-scene3d/internal/loader/gltf2-asset.h index 3fa2705..19d56b6 100644 --- a/dali-scene3d/internal/loader/gltf2-asset.h +++ b/dali-scene3d/internal/loader/gltf2-asset.h @@ -29,6 +29,25 @@ #include "dali/public-api/math/quaternion.h" #include "dali/public-api/math/vector4.h" +#define ENUM_STRING_MAPPING(t, x) \ + { \ +#x, t::x \ + } + +#define ENUM_TYPE_FROM_STRING(structName, table) \ + structName::Type structName::FromString(const char* s, size_t len) \ + { \ + std::string target(s, len); \ + std::transform(target.begin(), target.end(), target.begin(), ::toupper); \ + \ + auto iFind = table.find(std::string_view(target.c_str(), len)); \ + if(iFind != table.end()) \ + { \ + return iFind->second; \ + } \ + return structName::INVALID; \ + } + namespace gltf2 { using Index = Dali::Scene3D::Loader::Index; @@ -365,14 +384,14 @@ struct Material : Named //TODO: extras }; - Pbr mPbrMetallicRoughness; - TextureInfo mNormalTexture; - TextureInfo mOcclusionTexture; - TextureInfo mEmissiveTexture; - Dali::Vector3 mEmissiveFactor; - AlphaMode::Type mAlphaMode = AlphaMode::OPAQUE; - float mAlphaCutoff = .5f; - bool mDoubleSided = false; + Pbr mPbrMetallicRoughness; + TextureInfo mNormalTexture; + TextureInfo mOcclusionTexture; + TextureInfo mEmissiveTexture; + Dali::Vector3 mEmissiveFactor; + AlphaMode::Type mAlphaMode = AlphaMode::OPAQUE; + float mAlphaCutoff = .5f; + bool mDoubleSided = false; //extensions MaterialExtensions mMaterialExtensions; diff --git a/dali-scene3d/public-api/file.list b/dali-scene3d/public-api/file.list index 1ce931f..29a1b33 100644 --- a/dali-scene3d/public-api/file.list +++ b/dali-scene3d/public-api/file.list @@ -18,6 +18,7 @@ set(scene3d_src_files ${scene3d_src_files} ${scene3d_public_api_dir}/loader/facial-animation-loader.cpp ${scene3d_public_api_dir}/loader/gltf2-loader.cpp ${scene3d_public_api_dir}/loader/ktx-loader.cpp + ${scene3d_public_api_dir}/loader/load-scene-metadata.cpp ${scene3d_public_api_dir}/loader/material-definition.cpp ${scene3d_public_api_dir}/loader/matrix-stack.cpp ${scene3d_public_api_dir}/loader/mesh-definition.cpp diff --git a/dali-scene3d/public-api/loader/gltf2-loader.cpp b/dali-scene3d/public-api/loader/gltf2-loader.cpp index e6d34fc..75d7ad0 100644 --- a/dali-scene3d/public-api/loader/gltf2-loader.cpp +++ b/dali-scene3d/public-api/loader/gltf2-loader.cpp @@ -14,21 +14,23 @@ * limitations under the License. * */ -#include + +// FILE HEADER #include + +// EXTERNAL INCLUDES +#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; @@ -178,7 +180,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))); @@ -437,13 +438,24 @@ SamplerFlags::Type ConvertSampler(const gt::Ref& s) } } -TextureDefinition ConvertTextureInfo(const gt::TextureInfo& mm) +TextureDefinition ConvertTextureInfo(const gt::TextureInfo& mm, const ImageMetadata& metaData = ImageMetadata()) { - return TextureDefinition{std::string(mm.mTexture->mSource->mUri), ConvertSampler(mm.mTexture->mSampler)}; + return TextureDefinition{std::string(mm.mTexture->mSource->mUri), 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) { + auto getTextureMetaData = [](const std::unordered_map& metaData, const gt::TextureInfo& info) { + if(auto search = metaData.find(info.mTexture->mSource->mUri.data()); search != metaData.end()) + { + return search->second; + } + else + { + return ImageMetadata(); + } + }; + MaterialDefinition matDef; auto& pbr = material.mPbrMetallicRoughness; @@ -463,7 +475,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, getTextureMetaData(imageMetaData, pbr.mBaseColorTexture))}); // TODO: and there had better be one matDef.mFlags |= semantic; } @@ -479,7 +491,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, getTextureMetaData(imageMetaData, pbr.mMetallicRoughnessTexture))}); // TODO: and there had better be one matDef.mFlags |= semantic; } @@ -492,7 +504,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, getTextureMetaData(imageMetaData, material.mNormalTexture))}); // TODO: and there had better be one matDef.mFlags |= semantic; } @@ -504,7 +516,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, getTextureMetaData(imageMetaData, material.mOcclusionTexture))}); // TODO: and there had better be one matDef.mFlags |= semantic; matDef.mOcclusionStrength = material.mOcclusionTexture.mStrength; @@ -513,7 +525,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, getTextureMetaData(imageMetaData, material.mEmissiveTexture))}); // TODO: and there had better be one matDef.mFlags |= semantic; matDef.mEmissiveFactor = material.mEmissiveFactor; @@ -521,8 +533,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 +542,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, 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, getTextureMetaData(imageMetaData, material.mMaterialExtensions.mMaterialSpecular.mSpecularColorTexture))}); matDef.mFlags |= semantic; } @@ -548,12 +560,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); } } @@ -628,11 +642,11 @@ void ConvertMeshes(const gt::Document& doc, ConversionContext& context) { MeshDefinition meshDefinition; - auto& attribs = primitive.mAttributes; + auto& attribs = primitive.mAttributes; meshDefinition.mUri = attribs.begin()->second->mBufferView->mBuffer->mUri; 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 @@ -730,10 +744,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); } materialIdx = context.mDefaultMaterial; @@ -814,8 +828,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); diff --git a/dali-scene3d/public-api/loader/load-result.h b/dali-scene3d/public-api/loader/load-result.h index a9428eb..bd7e486 100644 --- a/dali-scene3d/public-api/loader/load-result.h +++ b/dali-scene3d/public-api/loader/load-result.h @@ -18,10 +18,11 @@ */ // INTERNAL INCLUDES -#include "dali-scene3d/public-api/api.h" -#include "dali-scene3d/public-api/loader/animation-definition.h" -#include "dali-scene3d/public-api/loader/camera-parameters.h" -#include "dali-scene3d/public-api/loader/light-parameters.h" +#include +#include +#include +#include +#include namespace Dali { @@ -48,6 +49,11 @@ struct DALI_SCENE3D_API LoadResult SceneDefinition& mScene; /** + * @brief The metadata of the scene. + */ + SceneMetadata& mSceneMetadata; + + /** * @brief The list of animation definitions, in lexicographical order of their names. */ std::vector& mAnimationDefinitions; diff --git a/dali-scene3d/public-api/loader/load-scene-metadata.cpp b/dali-scene3d/public-api/loader/load-scene-metadata.cpp new file mode 100644 index 0000000..76c1056 --- /dev/null +++ b/dali-scene3d/public-api/loader/load-scene-metadata.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2022 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// INTERNAL INCLUDES +#include +#include +#include +#include + +namespace js = json; +namespace gt = gltf2; + +namespace Dali::Scene3D::Loader +{ +namespace +{ +struct ImageData +{ + struct SamplingMode + { + enum Type + { + INVALID = -1, + BOX = Dali::SamplingMode::BOX, + NEAREST = Dali::SamplingMode::NEAREST, + LINEAR = Dali::SamplingMode::LINEAR, + BOX_THEN_NEAREST = Dali::SamplingMode::BOX_THEN_NEAREST, + BOX_THEN_LINEAR = Dali::SamplingMode::BOX_THEN_LINEAR, + NO_FILTER = Dali::SamplingMode::NO_FILTER, + DONT_CARE = Dali::SamplingMode::DONT_CARE + }; + + static Type FromString(const char* s, size_t len); + }; + + std::string mImageUri{}; ///< The URI of the image + uint16_t mMinWidth{}; ///< The minimum width of the image + uint16_t mMinHeight{}; ///< The mimimum height of the image + + ImageData::SamplingMode::Type mSamplingMode{ImageData::SamplingMode::BOX_THEN_LINEAR}; ///< The sampling mode used to resize the image. +}; + +const std::map SAMPLING_MODE_TYPES{ + ENUM_STRING_MAPPING(ImageData::SamplingMode, BOX), + ENUM_STRING_MAPPING(ImageData::SamplingMode, NEAREST), + ENUM_STRING_MAPPING(ImageData::SamplingMode, LINEAR), + ENUM_STRING_MAPPING(ImageData::SamplingMode, BOX_THEN_NEAREST), + ENUM_STRING_MAPPING(ImageData::SamplingMode, BOX_THEN_LINEAR), + ENUM_STRING_MAPPING(ImageData::SamplingMode, NO_FILTER), + ENUM_STRING_MAPPING(ImageData::SamplingMode, DONT_CARE), +}; + +ENUM_TYPE_FROM_STRING(ImageData::SamplingMode, SAMPLING_MODE_TYPES) + +struct MetaData +{ + std::vector mImageData; +}; + +const auto IMAGE_METADATA_READER = std::move(js::Reader() + .Register(*js::MakeProperty("uri", js::Read::String, &ImageData::mImageUri)) + .Register(*js::MakeProperty("minWidth", js::Read::Number, &ImageData::mMinWidth)) + .Register(*js::MakeProperty("minHeight", js::Read::Number, &ImageData::mMinHeight)) + .Register(*js::MakeProperty("samplingMode", gt::ReadStringEnum, &ImageData::mSamplingMode))); + +const auto METADATA_READER = std::move(js::Reader() + .Register(*js::MakeProperty("images", js::Read::Array::Read>, &MetaData::mImageData))); + +} // namespace + +void LoadSceneMetadata(const std::string& url, SceneMetadata& sceneMetadata) +{ + bool failed = false; + auto js = LoadTextFile(url.c_str(), &failed); + if(failed) + { + return; + } + + json::unique_ptr root(json_parse(js.c_str(), js.size())); + if(!root) + { + throw std::runtime_error("Failed to parse " + url); + } + auto& rootObj = js::Cast(*root); + + static bool setObjectReaders = true; + if(setObjectReaders) + { + js::SetObjectReader(IMAGE_METADATA_READER); + + setObjectReaders = false; + } + + MetaData metaData; + METADATA_READER.Read(rootObj, metaData); + + sceneMetadata.mImageMetadata.reserve(metaData.mImageData.size() + metaData.mImageData.size()); + for(auto&& data : metaData.mImageData) + { + if(data.mSamplingMode == ImageData::SamplingMode::INVALID) + { + throw std::runtime_error("Sampling mode type unsupported."); + } + else + { + sceneMetadata.mImageMetadata.insert({data.mImageUri, ImageMetadata{ImageDimensions(data.mMinWidth, data.mMinHeight), static_cast(data.mSamplingMode)}}); + } + } +} + +} // namespace Dali::Scene3D::Loader diff --git a/dali-scene3d/public-api/loader/load-scene-metadata.h b/dali-scene3d/public-api/loader/load-scene-metadata.h new file mode 100644 index 0000000..ca7e16f --- /dev/null +++ b/dali-scene3d/public-api/loader/load-scene-metadata.h @@ -0,0 +1,66 @@ +#ifndef DALI_SCENE3D_LOADER_LOAD_SCENE_METADATA_H_ +#define DALI_SCENE3D_LOADER_LOAD_SCENE_METADATA_H_ +/* + * Copyright (c) 2022 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// EXTERNAL INCLUDES +#include +#include +#include + +// INTERNAL INCLUDES +#include + +namespace Dali::Scene3D::Loader +{ +/** + * @brief Defines the matadata for an image. + */ +struct ImageMetadata +{ + ImageDimensions mMinSize{}; ///< The minimum required image size for rendering + SamplingMode::Type mSamplingMode{SamplingMode::BOX_THEN_LINEAR}; ///< The sampling mode used to resize the image +}; + +/** + * @brief Stores the metadata for a scene. + * + * @note The supported format is the following: + * { + * "images": (optional) [ { + * "uri": name of the image file, + * "minWidth": minimum width required for rendering, + * "minHeight": minimum height required for rendering. + * "samplingMode": sampling mode used to resize the image (@see Dali::SamplingMode). (optional) + * } ] + * } + */ +struct SceneMetadata +{ + std::unordered_map mImageMetadata{}; ///< The container of image metadata (i.e. the pairs of image URI and image metadata) +}; + +/** + * @brief Attempts to load and process a json file specifying scene metadata + * for pre-processing the scene resources: e.g. the minimum size required for rendering images, etc. + * @note Will fail quietly if the file is not present. + */ +DALI_SCENE3D_API void LoadSceneMetadata(const std::string& url, SceneMetadata& sceneMetadata); + +} // namespace Dali::Scene3D::Loader + +#endif // DALI_SCENE3D_LOADER_LOAD_SCENE_METADATA_H_ diff --git a/dali-scene3d/public-api/loader/material-definition.cpp b/dali-scene3d/public-api/loader/material-definition.cpp index 7f86add..7245652 100644 --- a/dali-scene3d/public-api/loader/material-definition.cpp +++ b/dali-scene3d/public-api/loader/material-definition.cpp @@ -100,9 +100,11 @@ Sampler SamplerFlags::MakeSampler(Type flags) return sampler; } -TextureDefinition::TextureDefinition(const std::string& imageUri, SamplerFlags::Type samplerFlags) +TextureDefinition::TextureDefinition(const std::string& imageUri, SamplerFlags::Type samplerFlags, ImageDimensions minImageDimensions, SamplingMode::Type samplingMode) : mImageUri(imageUri), - mSamplerFlags(samplerFlags) + mSamplerFlags(samplerFlags), + mMinImageDimensions(minImageDimensions), + mSamplingMode(samplingMode) { } @@ -130,12 +132,12 @@ MaterialDefinition::LoadRaw(const std::string& imagesPath) const // Check for compulsory textures: Albedo, Metallic, Roughness, Normal if(checkStage(ALBEDO | METALLIC)) { - raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags}); + raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri, iTexture->mTexture.mMinImageDimensions, FittingMode::DEFAULT, iTexture->mTexture.mSamplingMode, true), iTexture->mTexture.mSamplerFlags}); ++iTexture; if(checkStage(NORMAL | ROUGHNESS)) { - raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags}); + raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri, iTexture->mTexture.mMinImageDimensions, FittingMode::DEFAULT, iTexture->mTexture.mSamplingMode, true), iTexture->mTexture.mSamplerFlags}); ++iTexture; } else // single value normal-roughness @@ -149,7 +151,7 @@ MaterialDefinition::LoadRaw(const std::string& imagesPath) const { if(checkStage(ALBEDO)) { - raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags}); + raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri, iTexture->mTexture.mMinImageDimensions, FittingMode::DEFAULT, iTexture->mTexture.mSamplingMode, true), iTexture->mTexture.mSamplerFlags}); ++iTexture; } else if(mNeedAlbedoTexture) // single value albedo, albedo-alpha or albedo-metallic @@ -183,7 +185,7 @@ MaterialDefinition::LoadRaw(const std::string& imagesPath) const const bool createMetallicRoughnessAndNormal = hasTransparency || std::distance(mTextureStages.begin(), iTexture) > 0; if(checkStage(METALLIC | ROUGHNESS)) { - raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags}); + raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri, iTexture->mTexture.mMinImageDimensions, FittingMode::DEFAULT, iTexture->mTexture.mSamplingMode, true), iTexture->mTexture.mSamplerFlags}); ++iTexture; } else if(createMetallicRoughnessAndNormal && mNeedMetallicRoughnessTexture) @@ -197,7 +199,7 @@ MaterialDefinition::LoadRaw(const std::string& imagesPath) const if(checkStage(NORMAL)) { - raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags}); + raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri, iTexture->mTexture.mMinImageDimensions, FittingMode::DEFAULT, iTexture->mTexture.mSamplingMode, true), iTexture->mTexture.mSamplerFlags}); ++iTexture; } else if(mNeedNormalTexture) @@ -220,31 +222,31 @@ MaterialDefinition::LoadRaw(const std::string& imagesPath) const // Extra textures. if(checkStage(SUBSURFACE)) { - raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags}); + raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri, iTexture->mTexture.mMinImageDimensions, FittingMode::DEFAULT, iTexture->mTexture.mSamplingMode, true), iTexture->mTexture.mSamplerFlags}); ++iTexture; } if(checkStage(OCCLUSION)) { - raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags}); + raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri, iTexture->mTexture.mMinImageDimensions, FittingMode::DEFAULT, iTexture->mTexture.mSamplingMode, true), iTexture->mTexture.mSamplerFlags}); ++iTexture; } if(checkStage(EMISSIVE)) { - raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags}); + raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri, iTexture->mTexture.mMinImageDimensions, FittingMode::DEFAULT, iTexture->mTexture.mSamplingMode, true), iTexture->mTexture.mSamplerFlags}); ++iTexture; } if(checkStage(SPECULAR)) { - raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags}); + raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri, iTexture->mTexture.mMinImageDimensions, FittingMode::DEFAULT, iTexture->mTexture.mSamplingMode, true), iTexture->mTexture.mSamplerFlags}); ++iTexture; } if(checkStage(SPECULAR_COLOR)) { - raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags}); + raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri, iTexture->mTexture.mMinImageDimensions, FittingMode::DEFAULT, iTexture->mTexture.mSamplingMode, true), iTexture->mTexture.mSamplerFlags}); ++iTexture; } diff --git a/dali-scene3d/public-api/loader/material-definition.h b/dali-scene3d/public-api/loader/material-definition.h index 119f7c4..08b59c6 100644 --- a/dali-scene3d/public-api/loader/material-definition.h +++ b/dali-scene3d/public-api/loader/material-definition.h @@ -24,6 +24,7 @@ #include "dali-scene3d/public-api/loader/utils.h" // EXTERNAL INCLUDES +#include #include #include "dali/public-api/common/vector-wrapper.h" #include "dali/public-api/math/vector4.h" @@ -115,8 +116,10 @@ struct DALI_SCENE3D_API TextureDefinition { std::string mImageUri; SamplerFlags::Type mSamplerFlags; + ImageDimensions mMinImageDimensions; + SamplingMode::Type mSamplingMode; - TextureDefinition(const std::string& imageUri = "", SamplerFlags::Type samplerFlags = SamplerFlags::DEFAULT); + TextureDefinition(const std::string& imageUri = "", SamplerFlags::Type samplerFlags = SamplerFlags::DEFAULT, ImageDimensions minImageDimensions = ImageDimensions(), SamplingMode::Type samplingMode = SamplingMode::BOX_THEN_LINEAR); }; /** -- 2.7.4