From: seunghobaek Date: Fri, 11 Nov 2022 12:50:25 +0000 (+0900) Subject: Asynchronous loading of Scene3D resources X-Git-Tag: dali_2.2.9~2^2 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=d3ab7a4cc307562e687de2b2751f2f0a687c2835 Asynchronous loading of Scene3D resources Change-Id: Idd19cbcfc1bdcfb7e8cd9d2ea6691a9060bcfb78 Signed-off-by: seunghobaek --- diff --git a/automated-tests/src/dali-scene3d/utc-Dali-Gltf2Loader.cpp b/automated-tests/src/dali-scene3d/utc-Dali-Gltf2Loader.cpp index a6256f5..c1fcf61 100644 --- a/automated-tests/src/dali-scene3d/utc-Dali-Gltf2Loader.cpp +++ b/automated-tests/src/dali-scene3d/utc-Dali-Gltf2Loader.cpp @@ -55,7 +55,8 @@ namespace { struct Context { - ResourceBundle::PathProvider pathProvider = [](ResourceType::Value type) { + ResourceBundle::PathProvider pathProvider = [](ResourceType::Value type) + { return TEST_RESOURCE_DIR "/"; }; @@ -102,6 +103,7 @@ int UtcDaliGltfLoaderFailedToLoad(void) ShaderDefinitionFactory sdf; sdf.SetResources(ctx.resources); + InitializeGltfLoader(); DALI_TEST_THROW(LoadGltfScene("non-existent.gltf", sdf, ctx.loadResult), std::runtime_error, ExceptionMessageStartsWith{"Failed to load"}); @@ -130,6 +132,7 @@ int UtcDaliGltfLoaderFailedToParse(void) ShaderDefinitionFactory sdf; sdf.SetResources(ctx.resources); + InitializeGltfLoader(); DALI_TEST_THROW(LoadGltfScene(TEST_RESOURCE_DIR "/invalid.gltf", sdf, ctx.loadResult), std::runtime_error, ExceptionMessageStartsWith{"Failed to parse"}); @@ -173,6 +176,7 @@ int UtcDaliGltfLoaderSuccess1(void) ShaderDefinitionFactory sdf; sdf.SetResources(ctx.resources); + InitializeGltfLoader(); LoadGltfScene(TEST_RESOURCE_DIR "/AnimatedCube.gltf", sdf, ctx.loadResult); DALI_TEST_EQUAL(1u, ctx.scene.GetRoots().size()); @@ -195,105 +199,155 @@ int UtcDaliGltfLoaderSuccess1(void) auto& materials = ctx.resources.mMaterials; DALI_TEST_EQUAL(2u, materials.size()); const MaterialDefinition materialGroundTruth[]{ - {MaterialDefinition::ALBEDO | MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION | - MaterialDefinition::NORMAL | MaterialDefinition::SPECULAR | MaterialDefinition::SPECULAR_COLOR | - (0x80 << MaterialDefinition::ALPHA_CUTOFF_SHIFT), - 0, - Color::WHITE, - 1.f, - 0.f, - Vector4(1.000, 0.766, 0.336, 1.0), - 1.f, - 1.f, - Vector3(0.2, 0.1, 0.0), - 0.0f, - 0.5f, - Vector3(0, 0, 1), - true, - false, - true, - false, - true, - true, - { - {MaterialDefinition::ALBEDO, - {"AnimatedCube_BaseColor.png", - 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), - 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), - 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), - 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), - 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), - ImageDimensions(256, 256), - SamplingMode::BOX_THEN_NEAREST}}, - }}, - {MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS | - MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION | - MaterialDefinition::NORMAL | MaterialDefinition::GLTF_CHANNELS, - 0, - Color::WHITE, - 1.f, - 0.f, - Vector4(1.000, 0.766, 0.336, 1.0), - 1.f, - 1.f, - Vector3(0.2, 0.1, 0.0), - 0.04f, - 1.0f, - Vector3::ONE, - true, - true, - true, - false, - true, - false, - { - {MaterialDefinition::ALBEDO, - {"AnimatedCube_BaseColor.png", - 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), - ImageDimensions(256, 256), - SamplingMode::NEAREST}}, - {MaterialDefinition::NORMAL, - {"AnimatedCube_BaseColor.png", - 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), - 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), - ImageDimensions(256, 256), - SamplingMode::BOX_THEN_NEAREST}}, - }}, + { + nullptr, + MaterialDefinition::ALBEDO | MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION | + MaterialDefinition::NORMAL | MaterialDefinition::SPECULAR | MaterialDefinition::SPECULAR_COLOR | + (0x80 << MaterialDefinition::ALPHA_CUTOFF_SHIFT), + 0, + Color::WHITE, + 1.f, + 0.f, + Vector4(1.000, 0.766, 0.336, 1.0), + 1.f, + 1.f, + Vector3(0.2, 0.1, 0.0), + 0.0f, + 0.5f, + Vector3(0, 0, 1), + true, + false, + true, + false, + true, + true, + { + { + MaterialDefinition::ALBEDO, + { + "AnimatedCube_BaseColor.png", + 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), + 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), + 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), + 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), + 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), + ImageDimensions(256, 256), + SamplingMode::BOX_THEN_NEAREST, + }, + }, + }, + }, + { + nullptr, + MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS | + MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION | MaterialDefinition::NORMAL | + MaterialDefinition::GLTF_CHANNELS, + 0, + Color::WHITE, + 1.f, + 0.f, + Vector4(1.000, 0.766, 0.336, 1.0), + 1.f, + 1.f, + Vector3(0.2, 0.1, 0.0), + 0.04f, + 1.0f, + Vector3::ONE, + true, + true, + true, + false, + true, + false, + { + { + MaterialDefinition::ALBEDO, + { + "AnimatedCube_BaseColor.png", + 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), + ImageDimensions(256, 256), + SamplingMode::NEAREST, + }, + }, + { + MaterialDefinition::NORMAL, + { + "AnimatedCube_BaseColor.png", + 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), + 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), + ImageDimensions(256, 256), + SamplingMode::BOX_THEN_NEAREST, + }, + }, + }, + }, }; auto iMaterial = materials.begin(); @@ -344,6 +398,7 @@ int UtcDaliGltfLoaderSuccess1(void) using Accessor = MeshDefinition::Accessor; const MeshDefinition meshGroundTruth[]{ { + nullptr, 0, Geometry::TRIANGLES, "AnimatedCube.bin", @@ -355,6 +410,7 @@ int UtcDaliGltfLoaderSuccess1(void) Accessor{Blob{0, 0}, {}}, }, { + nullptr, 0, Geometry::TRIANGLES, "AnimatedCube.bin", @@ -407,10 +463,11 @@ int UtcDaliGltfLoaderSuccess1(void) int UtcDaliGltfLoaderSuccess2(void) { - Context ctx; + Context ctx; ShaderDefinitionFactory sdf; sdf.SetResources(ctx.resources); + InitializeGltfLoader(); LoadGltfScene(TEST_RESOURCE_DIR "/AnimatedCubeStride.gltf", sdf, ctx.loadResult); DALI_TEST_EQUAL(1u, ctx.scene.GetRoots().size()); @@ -437,7 +494,8 @@ int UtcDaliGltfLoaderSuccessShort(void) TestApplication app; const std::string resourcePath = TEST_RESOURCE_DIR "/"; - auto pathProvider = [resourcePath](ResourceType::Value) { + auto pathProvider = [resourcePath](ResourceType::Value) + { return resourcePath; }; @@ -468,6 +526,7 @@ int UtcDaliGltfLoaderSuccessShort(void) sdf.SetResources(resources); printf("%s\n", modelName); + InitializeGltfLoader(); LoadGltfScene(resourcePath + modelName + ".gltf", sdf, ctx.loadResult); DALI_TEST_CHECK(ctx.scene.GetNodeCount() > 0); @@ -529,6 +588,7 @@ int UtcDaliGltfLoaderMRendererTest(void) sdf.SetResources(ctx.resources); auto& resources = ctx.resources; + InitializeGltfLoader(); LoadGltfScene(TEST_RESOURCE_DIR "/MRendererTest.gltf", sdf, ctx.loadResult); auto& scene = ctx.scene; @@ -583,7 +643,6 @@ int UtcDaliGltfLoaderMRendererTest(void) END_TEST; } - int UtcDaliGltfLoaderAnimationLoadingTest(void) { Context ctx; @@ -592,6 +651,7 @@ int UtcDaliGltfLoaderAnimationLoadingTest(void) sdf.SetResources(ctx.resources); auto& resources = ctx.resources; + InitializeGltfLoader(); LoadGltfScene(TEST_RESOURCE_DIR "/BoxAnimated.gltf", sdf, ctx.loadResult); auto& scene = ctx.scene; diff --git a/automated-tests/src/dali-scene3d/utc-Dali-Model.cpp b/automated-tests/src/dali-scene3d/utc-Dali-Model.cpp index db7a5e6..5d2c344 100644 --- a/automated-tests/src/dali-scene3d/utc-Dali-Model.cpp +++ b/automated-tests/src/dali-scene3d/utc-Dali-Model.cpp @@ -22,6 +22,7 @@ #include #include +#include #include @@ -93,6 +94,19 @@ void TestFocusChangedCallback(Actor, Actor) gFocusChangedCallBackCalled = true; } +// For ResourceReady +static bool gOnRelayoutCallBackCalled = false; +void OnRelayoutCallback(Actor actor) +{ + gOnRelayoutCallBackCalled = true; +} + +static bool gResourceReadyCalled = false; +void OnResourceReady(Control control) +{ + gResourceReadyCalled = true; +} + } // namespace // Negative test case for a method @@ -251,15 +265,23 @@ int UtcDaliModelOnScene01(void) ToolkitTestApplication application; Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_FILE_NAME); - application.GetScene().Add(model); + gResourceReadyCalled = false; + model.ResourceReadySignal().Connect(&OnResourceReady); + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); application.SendNotification(); application.Render(); + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + uint32_t modelCount = model.GetModelRoot().GetChildCount(); DALI_TEST_EQUALS(1, modelCount, TEST_LOCATION); - END_TEST; } @@ -268,12 +290,21 @@ int UtcDaliModelOnScene02(void) ToolkitTestApplication application; Scene3D::Model model = Scene3D::Model::New(TEST_DLI_FILE_NAME); - application.GetScene().Add(model); + gResourceReadyCalled = false; + model.ResourceReadySignal().Connect(&OnResourceReady); + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); application.SendNotification(); application.Render(); + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + uint32_t modelCount = model.GetModelRoot().GetChildCount(); DALI_TEST_EQUALS(1, modelCount, TEST_LOCATION); @@ -313,7 +344,20 @@ int UtcDaliModelGetNaturalSize(void) Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_FILE_NAME); Vector3 naturalSize = model.GetNaturalSize(); + DALI_TEST_EQUALS(Vector3::ZERO, naturalSize, TEST_LOCATION); + + application.GetScene().Add(model); + gResourceReadyCalled = false; + model.ResourceReadySignal().Connect(&OnResourceReady); + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); + application.SendNotification(); + + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + + naturalSize = model.GetNaturalSize(); DALI_TEST_EQUALS(Vector3(2, 2, 2), naturalSize, TEST_LOCATION); Actor root = model.GetModelRoot(); @@ -327,12 +371,21 @@ int UtcDaliModelSetImageBasedLightSource01(void) ToolkitTestApplication application; Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_FILE_NAME); - application.GetScene().Add(model); + gResourceReadyCalled = false; + model.ResourceReadySignal().Connect(&OnResourceReady); + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + application.SendNotification(); application.Render(); + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + Actor meshActor = model.FindChildByName("AnimatedCube"); DALI_TEST_CHECK(meshActor); @@ -345,14 +398,27 @@ int UtcDaliModelSetImageBasedLightSource01(void) Texture diffuseTexture = textureSet.GetTexture(7u); Texture specularTexture = textureSet.GetTexture(8u); + gResourceReadyCalled = false; + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); model.SetImageBasedLightSource(TEST_DIFFUSE_TEXTURE, TEST_SPECULAR_TEXTURE); + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION); + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + Texture newDiffuseTexture = textureSet.GetTexture(7u); Texture newSpecularTexture = textureSet.GetTexture(8u); DALI_TEST_NOT_EQUALS(diffuseTexture, newDiffuseTexture, 0.0f, TEST_LOCATION); DALI_TEST_NOT_EQUALS(specularTexture, newSpecularTexture, 0.0f, TEST_LOCATION); + model.Unparent(); + model.Reset(); END_TEST; } @@ -361,12 +427,21 @@ int UtcDaliModelSetImageBasedLightSource02(void) ToolkitTestApplication application; Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_FILE_NAME); - application.GetScene().Add(model); + gResourceReadyCalled = false; + model.ResourceReadySignal().Connect(&OnResourceReady); + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + application.SendNotification(); application.Render(); + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + Actor meshActor = model.FindChildByName("AnimatedCube"); DALI_TEST_CHECK(meshActor); @@ -379,6 +454,7 @@ int UtcDaliModelSetImageBasedLightSource02(void) Texture diffuseTexture = textureSet.GetTexture(7u); Texture specularTexture = textureSet.GetTexture(8u); + // if url is empty, loading is not requested. model.SetImageBasedLightSource("", ""); Texture newDiffuseTexture = textureSet.GetTexture(7u); @@ -395,12 +471,21 @@ int UtcDaliModelSetImageBasedLightSource03(void) ToolkitTestApplication application; Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_FILE_NAME); - application.GetScene().Add(model); + gResourceReadyCalled = false; + model.ResourceReadySignal().Connect(&OnResourceReady); + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + application.SendNotification(); application.Render(); + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + Actor meshActor = model.FindChildByName("AnimatedCube"); DALI_TEST_CHECK(meshActor); @@ -413,8 +498,19 @@ int UtcDaliModelSetImageBasedLightSource03(void) Texture diffuseTexture = textureSet.GetTexture(7u); Texture specularTexture = textureSet.GetTexture(8u); + gResourceReadyCalled = false; + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); model.SetImageBasedLightSource("dummy.ktx", "dummy.ktx"); + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION); + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + Texture newDiffuseTexture = textureSet.GetTexture(7u); Texture newSpecularTexture = textureSet.GetTexture(8u); @@ -424,6 +520,29 @@ int UtcDaliModelSetImageBasedLightSource03(void) END_TEST; } +int UtcDaliModelSetImageBasedLightSource04(void) +{ + ToolkitTestApplication application; + + Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_FILE_NAME); + model.SetImageBasedLightSource(TEST_DIFFUSE_TEXTURE, TEST_SPECULAR_TEXTURE); + application.GetScene().Add(model); + + gResourceReadyCalled = false; + model.ResourceReadySignal().Connect(&OnResourceReady); + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(3), true, TEST_LOCATION); + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + END_TEST; +} + int UtcDaliModelImageBasedFactor(void) { ToolkitTestApplication application; @@ -453,12 +572,21 @@ int UtcDaliModelChildrenSensitive01(void) // Allow children actor's event before on scene. view.SetChildrenSensitive(true); DALI_TEST_EQUALS(view.GetChildrenSensitive(), true, TEST_LOCATION); - application.GetScene().Add(view); + gResourceReadyCalled = false; + view.ResourceReadySignal().Connect(&OnResourceReady); + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); application.SendNotification(); application.Render(); + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + Actor meshActor = view.FindChildByName("AnimatedCube"); DALI_TEST_CHECK(meshActor); @@ -541,12 +669,21 @@ int UtcDaliModelChildrenSensitive02(void) // Block children actor's event before on scene. view.SetChildrenSensitive(false); DALI_TEST_EQUALS(view.GetChildrenSensitive(), false, TEST_LOCATION); - application.GetScene().Add(view); + gResourceReadyCalled = false; + view.ResourceReadySignal().Connect(&OnResourceReady); + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); application.SendNotification(); application.Render(); + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + Actor meshActor = view.FindChildByName("AnimatedCube"); DALI_TEST_CHECK(meshActor); @@ -612,12 +749,21 @@ int UtcDaliModelChildrenFocusable01(void) // Allow children actor's focus before on scene. view.SetChildrenFocusable(true); DALI_TEST_EQUALS(view.GetChildrenFocusable(), true, TEST_LOCATION); - application.GetScene().Add(view); + gResourceReadyCalled = false; + view.ResourceReadySignal().Connect(&OnResourceReady); + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); application.SendNotification(); application.Render(); + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + Actor meshActor = view.FindChildByName("AnimatedCube"); DALI_TEST_CHECK(meshActor); @@ -711,12 +857,21 @@ int UtcDaliModelModelChildrenFocusable02(void) // Block children actor's focus before on scene. view.SetChildrenFocusable(false); DALI_TEST_EQUALS(view.GetChildrenFocusable(), false, TEST_LOCATION); - application.GetScene().Add(view); + gResourceReadyCalled = false; + view.ResourceReadySignal().Connect(&OnResourceReady); + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); application.SendNotification(); application.Render(); + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + Actor meshActor = view.FindChildByName("AnimatedCube"); DALI_TEST_CHECK(meshActor); @@ -783,12 +938,21 @@ int UtcDaliModelAnimation01(void) Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_FILE_NAME); model.SetProperty(Dali::Actor::Property::SIZE, Vector2(50, 50)); - application.GetScene().Add(model); + gResourceReadyCalled = false; + model.ResourceReadySignal().Connect(&OnResourceReady); + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); application.SendNotification(); application.Render(); + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + uint32_t animationCount = model.GetAnimationCount(); DALI_TEST_EQUALS(1, animationCount, TEST_LOCATION); @@ -808,9 +972,16 @@ int UtcDaliModelAnimation02(void) Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_ANIMATION_TEST_FILE_NAME); model.SetProperty(Dali::Actor::Property::SIZE, Vector2(50, 50)); - application.GetScene().Add(model); + gResourceReadyCalled = false; + model.ResourceReadySignal().Connect(&OnResourceReady); + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); application.SendNotification(); application.Render(); @@ -836,12 +1007,21 @@ int UtcDaliModelAnimation03(void) Scene3D::Model model = Scene3D::Model::New(TEST_DLI_EXERCISE_FILE_NAME); model.SetProperty(Dali::Actor::Property::SIZE, Vector2(50, 50)); - application.GetScene().Add(model); + gResourceReadyCalled = false; + model.ResourceReadySignal().Connect(&OnResourceReady); + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + application.SendNotification(); application.Render(); + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + uint32_t animationCount = model.GetAnimationCount(); DALI_TEST_EQUALS(18, animationCount, TEST_LOCATION); @@ -861,9 +1041,16 @@ int UtcDaliModelMultiplePrimitives(void) Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_MULTIPLE_PRIMITIVE_FILE_NAME); model.SetProperty(Dali::Actor::Property::SIZE, Vector2(50, 50)); - application.GetScene().Add(model); + gResourceReadyCalled = false; + model.ResourceReadySignal().Connect(&OnResourceReady); + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); application.SendNotification(); application.Render(); @@ -882,9 +1069,16 @@ int UtcDaliModelColorMode(void) Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_FILE_NAME); model.SetProperty(Dali::Actor::Property::SIZE, Vector2(50, 50)); model.SetProperty(Dali::Actor::Property::COLOR, Color::RED); - application.GetScene().Add(model); + gResourceReadyCalled = false; + model.ResourceReadySignal().Connect(&OnResourceReady); + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); application.SendNotification(); application.Render(); @@ -897,23 +1091,6 @@ int UtcDaliModelColorMode(void) END_TEST; } - -// For ResourceReady -namespace -{ -static bool gOnRelayoutCallBackCalled = false; -void OnRelayoutCallback(Actor actor) -{ - gOnRelayoutCallBackCalled = true; -} - -static bool gResourceReadyCalled = false; -void OnResourceReady(Control control) -{ - gResourceReadyCalled = true; -} -} // namespace - int UtcDaliModelResourceReady(void) { ToolkitTestApplication application; @@ -935,6 +1112,10 @@ int UtcDaliModelResourceReady(void) application.SendNotification(); application.Render(); + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); + application.SendNotification(); + application.Render(); + DALI_TEST_EQUALS(gOnRelayoutCallBackCalled, false, TEST_LOCATION); DALI_TEST_EQUALS(model.IsResourceReady(), true, TEST_LOCATION); DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); diff --git a/automated-tests/src/dali-scene3d/utc-Dali-SceneView.cpp b/automated-tests/src/dali-scene3d/utc-Dali-SceneView.cpp index f1b6bd7..ed3af58 100644 --- a/automated-tests/src/dali-scene3d/utc-Dali-SceneView.cpp +++ b/automated-tests/src/dali-scene3d/utc-Dali-SceneView.cpp @@ -22,6 +22,7 @@ #include #include +#include using namespace Dali; using namespace Dali::Toolkit; @@ -70,8 +71,11 @@ const char* TEST_GLTF_FILE_NAME = TEST_RESOURCE_DIR "/AnimatedCube.gltf"; * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -const char* TEST_DIFFUSE_TEXTURE = TEST_RESOURCE_DIR "/forest_irradiance.ktx"; -const char* TEST_SPECULAR_TEXTURE = TEST_RESOURCE_DIR "/forest_radiance.ktx"; +const char* TEST_EQUIRECTANGULAR_TEXTURE = TEST_RESOURCE_DIR "/application-icon-20.png"; +const char* TEST_DIFFUSE_TEXTURE = TEST_RESOURCE_DIR "/forest_irradiance.ktx"; +const char* TEST_SPECULAR_TEXTURE = TEST_RESOURCE_DIR "/forest_radiance.ktx"; +const char* TEST_DIFFUSE_TEXTURE2 = TEST_RESOURCE_DIR "//forest_irradiance.ktx"; +const char* TEST_SPECULAR_TEXTURE2 = TEST_RESOURCE_DIR "//forest_radiance.ktx"; Dali::Texture GetDiffuseTexture(Dali::Scene3D::Model model) { @@ -114,6 +118,20 @@ Dali::Texture GetSpecularTexture(Dali::Scene3D::Model model) return texture; } + + +// For ResourceReady +static bool gOnRelayoutCallBackCalled = false; +void OnRelayoutCallback(Actor actor) +{ + gOnRelayoutCallBackCalled = true; +} + +static bool gResourceReadyCalled = false; +void OnResourceReady(Control control) +{ + gResourceReadyCalled = true; +} } // namespace // Negative test case for a method @@ -422,6 +440,7 @@ int UtcDaliSceneViewImageBasedLight01(void) ToolkitTestApplication application; Scene3D::SceneView view = Scene3D::SceneView::New(); + view.ResourceReadySignal().Connect(OnResourceReady); view.SetProperty(Dali::Actor::Property::SIZE, Vector2(100, 100)); application.GetScene().Add(view); @@ -435,25 +454,59 @@ int UtcDaliSceneViewImageBasedLight01(void) view.Add(modelView1); view.Add(modelView2); + application.SendNotification(); + application.Render(); + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION); + application.SendNotification(); + application.Render(); + DALI_TEST_NOT_EQUALS(GetDiffuseTexture(modelView1), GetDiffuseTexture(modelView2), 0.0f, TEST_LOCATION); DALI_TEST_NOT_EQUALS(GetSpecularTexture(modelView1), GetSpecularTexture(modelView2), 0.0f, TEST_LOCATION); DALI_TEST_NOT_EQUALS(GetDiffuseTexture(modelView1), GetDiffuseTexture(modelView3), 0.0f, TEST_LOCATION); DALI_TEST_NOT_EQUALS(GetSpecularTexture(modelView1), GetSpecularTexture(modelView3), 0.0f, TEST_LOCATION); + gResourceReadyCalled = false; + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); view.SetImageBasedLightSource(TEST_DIFFUSE_TEXTURE, TEST_SPECULAR_TEXTURE); + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION); + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + DALI_TEST_EQUALS(GetDiffuseTexture(modelView1), GetDiffuseTexture(modelView2), TEST_LOCATION); DALI_TEST_EQUALS(GetSpecularTexture(modelView1), GetSpecularTexture(modelView2), TEST_LOCATION); DALI_TEST_NOT_EQUALS(GetDiffuseTexture(modelView1), GetDiffuseTexture(modelView3), 0.0f, TEST_LOCATION); DALI_TEST_NOT_EQUALS(GetSpecularTexture(modelView1), GetSpecularTexture(modelView3), 0.0f, TEST_LOCATION); view.Add(modelView3); + application.SendNotification(); + application.Render(); + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); + application.SendNotification(); + application.Render(); DALI_TEST_EQUALS(GetDiffuseTexture(modelView1), GetDiffuseTexture(modelView3), TEST_LOCATION); DALI_TEST_EQUALS(GetSpecularTexture(modelView1), GetSpecularTexture(modelView3), TEST_LOCATION); view.Remove(modelView1); - view.SetImageBasedLightSource(TEST_DIFFUSE_TEXTURE, TEST_SPECULAR_TEXTURE); + + gResourceReadyCalled = false; + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + view.SetImageBasedLightSource(TEST_DIFFUSE_TEXTURE2, TEST_SPECULAR_TEXTURE2); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION); + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); DALI_TEST_NOT_EQUALS(GetDiffuseTexture(modelView1), GetDiffuseTexture(modelView2), 0.0f, TEST_LOCATION); DALI_TEST_NOT_EQUALS(GetSpecularTexture(modelView1), GetSpecularTexture(modelView2), 0.0f, TEST_LOCATION); @@ -470,6 +523,7 @@ int UtcDaliSceneViewImageBasedLight02(void) ToolkitTestApplication application; Scene3D::SceneView view = Scene3D::SceneView::New(); + view.ResourceReadySignal().Connect(OnResourceReady); view.SetProperty(Dali::Actor::Property::SIZE, Vector2(100, 100)); application.GetScene().Add(view); @@ -478,13 +532,43 @@ int UtcDaliSceneViewImageBasedLight02(void) application.Render(); Scene3D::Model modelView1 = Scene3D::Model::New(TEST_GLTF_FILE_NAME); + modelView1.ResourceReadySignal().Connect(OnResourceReady); view.Add(modelView1); + application.SendNotification(); + application.Render(); + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); + application.SendNotification(); + application.Render(); + gResourceReadyCalled = false; + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); view.SetImageBasedLightSource(TEST_DIFFUSE_TEXTURE, TEST_SPECULAR_TEXTURE); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION); + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + Dali::Texture diffuseTexture = GetDiffuseTexture(modelView1); Dali::Texture specularTexture = GetSpecularTexture(modelView1); - modelView1.SetImageBasedLightSource(TEST_SPECULAR_TEXTURE, TEST_DIFFUSE_TEXTURE); + gResourceReadyCalled = false; + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + modelView1.SetImageBasedLightSource(TEST_DIFFUSE_TEXTURE2, TEST_SPECULAR_TEXTURE2); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION); + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + DALI_TEST_NOT_EQUALS(GetDiffuseTexture(modelView1), diffuseTexture, 0.0f, TEST_LOCATION); DALI_TEST_NOT_EQUALS(GetSpecularTexture(modelView1), specularTexture, 0.0f, TEST_LOCATION); diffuseTexture = GetDiffuseTexture(modelView1); @@ -508,7 +592,7 @@ int UtcDaliSceneViewImageBasedLight03(void) Scene3D::SceneView view = Scene3D::SceneView::New(); view.SetProperty(Dali::Actor::Property::SIZE, Vector2(100, 100)); - + view.ResourceReadySignal().Connect(OnResourceReady); application.GetScene().Add(view); application.SendNotification(); @@ -516,12 +600,29 @@ int UtcDaliSceneViewImageBasedLight03(void) Scene3D::Model modelView1 = Scene3D::Model::New(TEST_GLTF_FILE_NAME); view.Add(modelView1); - modelView1.SetImageBasedLightSource(TEST_SPECULAR_TEXTURE, TEST_DIFFUSE_TEXTURE); + + application.SendNotification(); + application.Render(); + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(3), true, TEST_LOCATION); + application.SendNotification(); + application.Render(); + Dali::Texture diffuseTexture = GetDiffuseTexture(modelView1); Dali::Texture specularTexture = GetSpecularTexture(modelView1); - view.SetImageBasedLightSource(TEST_DIFFUSE_TEXTURE, TEST_SPECULAR_TEXTURE); + gResourceReadyCalled = false; + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + view.SetImageBasedLightSource(TEST_DIFFUSE_TEXTURE2, TEST_SPECULAR_TEXTURE2); + + application.SendNotification(); + application.Render(); + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION); + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + DALI_TEST_EQUALS(GetDiffuseTexture(modelView1), diffuseTexture, TEST_LOCATION); DALI_TEST_EQUALS(GetSpecularTexture(modelView1), specularTexture, TEST_LOCATION); @@ -609,22 +710,6 @@ int UtcDaliSceneViewUseFramebuffer02(void) END_TEST; } -// For ResourceReady -namespace -{ -static bool gOnRelayoutCallBackCalled = false; -void OnRelayoutCallback(Actor actor) -{ - gOnRelayoutCallBackCalled = true; -} - -static bool gResourceReadyCalled = false; -void OnResourceReady(Control control) -{ - gResourceReadyCalled = true; -} -} - int UtcDaliSceneViewResourceReady(void) { ToolkitTestApplication application; @@ -658,6 +743,9 @@ int UtcDaliSceneViewResourceReady(void) application.SendNotification(); application.Render(); + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION); + application.SendNotification(); + application.Render(); DALI_TEST_EQUALS(gOnRelayoutCallBackCalled, false, TEST_LOCATION); DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); @@ -673,28 +761,110 @@ int UtcDaliSceneViewSetSkybox(void) Scene3D::SceneView view = Scene3D::SceneView::New(); view.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); view.ResourceReadySignal().Connect(OnResourceReady); - // SceneView::IsResourceReady() returns true by default. - DALI_TEST_EQUALS(view.IsResourceReady(), true, TEST_LOCATION); + application.GetScene().Add(view); - // Sanity check - DALI_TEST_CHECK(!gResourceReadyCalled); + application.SendNotification(); + application.Render(); + + uint32_t childCount = view.GetChildAt(0u).GetChildCount(); + view.SetSkybox(TEST_SPECULAR_TEXTURE); + + gResourceReadyCalled = false; + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + DALI_TEST_EQUALS(view.GetChildAt(0u).GetChildCount(), childCount + 1, TEST_LOCATION); + + view.Unparent(); + view.Reset(); + + END_TEST; +} + +int UtcDaliSceneViewSetSkyboxEquirectangular(void) +{ + ToolkitTestApplication application; + + gResourceReadyCalled = false; + Scene3D::SceneView view = Scene3D::SceneView::New(); + view.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + view.ResourceReadySignal().Connect(OnResourceReady); application.GetScene().Add(view); application.SendNotification(); application.Render(); - DALI_TEST_EQUALS(view.IsResourceReady(), true, TEST_LOCATION); + uint32_t childCount = view.GetChildAt(0u).GetChildCount(); + view.SetSkybox(TEST_EQUIRECTANGULAR_TEXTURE, Scene3D::SceneView::SkyboxType::EQUIRECTANGULAR); + + gResourceReadyCalled = false; DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + application.SendNotification(); + application.Render(); + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + + DALI_TEST_EQUALS(view.GetChildAt(0u).GetChildCount(), childCount + 1, TEST_LOCATION); + + view.Unparent(); + view.Reset(); + + END_TEST; +} + +int UtcDaliSceneViewSetSkyboxEmpty(void) +{ + ToolkitTestApplication application; + gResourceReadyCalled = false; + Scene3D::SceneView view = Scene3D::SceneView::New(); + view.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + view.ResourceReadySignal().Connect(OnResourceReady); + application.GetScene().Add(view); - view.SetSkybox(TEST_SPECULAR_TEXTURE); + application.SendNotification(); + application.Render(); + + uint32_t childCount = view.GetChildAt(0u).GetChildCount(); + view.SetSkybox(""); + DALI_TEST_EQUALS(view.GetChildAt(0u).GetChildCount(), childCount, TEST_LOCATION); + + view.Unparent(); + view.Reset(); + + END_TEST; +} + +int UtcDaliSceneViewSetSkyboxEquirectangularEmpty(void) +{ + ToolkitTestApplication application; + + gResourceReadyCalled = false; + Scene3D::SceneView view = Scene3D::SceneView::New(); + view.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + view.ResourceReadySignal().Connect(OnResourceReady); + application.GetScene().Add(view); application.SendNotification(); application.Render(); - DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + uint32_t childCount = view.GetChildAt(0u).GetChildCount(); + view.SetSkybox("", Scene3D::SceneView::SkyboxType::EQUIRECTANGULAR); + DALI_TEST_EQUALS(view.GetChildAt(0u).GetChildCount(), childCount, TEST_LOCATION); + + view.Unparent(); + view.Reset(); END_TEST; } @@ -729,6 +899,30 @@ int UtcDaliSceneViewSetSkyboxOrientation(void) END_TEST; } +int UtcDaliSceneViewSetImageBasedLightAndSkybox(void) +{ + ToolkitTestApplication application; + + Scene3D::SceneView view = Scene3D::SceneView::New(); + view.ResourceReadySignal().Connect(OnResourceReady); + view.SetProperty(Dali::Actor::Property::SIZE, Vector2(100, 100)); + view.SetImageBasedLightSource(TEST_DIFFUSE_TEXTURE, TEST_SPECULAR_TEXTURE); + view.SetSkybox(TEST_SPECULAR_TEXTURE); + application.GetScene().Add(view); + + // Check SceneView needs 3 trigger to load both of image based light and skybox. + gResourceReadyCalled = false; + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + application.SendNotification(); + application.Render(); + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(3), true, TEST_LOCATION); + application.SendNotification(); + application.Render(); + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + + END_TEST; +} + int UtcDaliSceneViewCreateAndRemoveRenderTask(void) { ToolkitTestApplication application; diff --git a/dali-scene3d/internal/common/environment-map-load-task.cpp b/dali-scene3d/internal/common/environment-map-load-task.cpp new file mode 100644 index 0000000..82d8646 --- /dev/null +++ b/dali-scene3d/internal/common/environment-map-load-task.cpp @@ -0,0 +1,73 @@ +/* + * 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. + * + */ + +// CLASS HEADER +#include + +// INTERNAL INCLUDES +#include + + +namespace Dali +{ +namespace Scene3D +{ +namespace Internal +{ + +EnvironmentMapLoadTask::EnvironmentMapLoadTask(const std::string& environmentMapUrl, CallbackBase* callback) +: AsyncTask(callback), + mEnvironmentMapUrl(environmentMapUrl), + mIsReady(true), + mHasSucceeded(false) +{ +} + +EnvironmentMapLoadTask::~EnvironmentMapLoadTask() +{ +} + +void EnvironmentMapLoadTask::Process() +{ + mHasSucceeded = Scene3D::Loader::LoadCubeMapData(mEnvironmentMapUrl, mEnvironmentMapPixelData); +} + +bool EnvironmentMapLoadTask::IsReady() +{ + return mIsReady; +} + +bool EnvironmentMapLoadTask::HasSucceeded() const +{ + return mHasSucceeded; +} + +Dali::Scene3D::Loader::CubeData EnvironmentMapLoadTask::GetEnvironmentMap() const +{ + Dali::Scene3D::Loader::CubeData environmentMapPixelData; + if(mIsReady && mHasSucceeded && !mEnvironmentMapPixelData.data.empty()) + { + environmentMapPixelData = mEnvironmentMapPixelData; + } + return environmentMapPixelData; +} + +} // namespace Internal + +} // namespace Scene3D + +} // namespace Dali diff --git a/dali-scene3d/internal/common/environment-map-load-task.h b/dali-scene3d/internal/common/environment-map-load-task.h new file mode 100644 index 0000000..8b1ac7c --- /dev/null +++ b/dali-scene3d/internal/common/environment-map-load-task.h @@ -0,0 +1,100 @@ +#ifndef DALI_SCENE3D_ENVIRONMENT_MAP_LOAD_TASK_H +#define DALI_SCENE3D_ENVIRONMENT_MAP_LOAD_TASK_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 +#include + +// INTERNAL INCLUDES +#include +#include + +namespace Dali +{ +namespace Scene3D +{ +namespace Internal +{ +class EnvironmentMapLoadTask; +typedef IntrusivePtr EnvironmentMapLoadTaskPtr; + +class EnvironmentMapLoadTask : public AsyncTask +{ +public: + /** + * Constructor + * @param[in] environmentMapUrl The url of the environment map image file. + * @param[in] callback The callback that is called when the operation is completed. + */ + EnvironmentMapLoadTask(const std::string& environmentMapUrl, CallbackBase* callback); + + /** + * Destructor. + */ + ~EnvironmentMapLoadTask(); + + /** + * Process the task + */ + void Process() override; + + /** + * Whether the task is ready to process. + * @return True if the task is ready to process. + */ + bool IsReady() override; + + /** + * Whether the task has succeeded. + * @return True if the task has succeeded. + */ + bool HasSucceeded() const; + + /** + * Retrieves loaded Environment Map + * @return CubeData loaded from url. + * + * TODO: Supports Equirectangular environment map + */ + Dali::Scene3D::Loader::CubeData GetEnvironmentMap() const; + +private: + // Undefined + EnvironmentMapLoadTask(const EnvironmentMapLoadTask& task) = delete; + + // Undefined + EnvironmentMapLoadTask& operator=(const EnvironmentMapLoadTask& task) = delete; + +private: + std::string mEnvironmentMapUrl; + Dali::Scene3D::Loader::CubeData mEnvironmentMapPixelData; + + bool mIsReady; + bool mHasSucceeded; +}; + +} // namespace Internal + +} // namespace Scene3D + +} // namespace Dali + +#endif // DALI_SCENE3D_ENVIRONMENT_MAP_LOAD_TASK_H diff --git a/dali-scene3d/internal/common/model-load-task.cpp b/dali-scene3d/internal/common/model-load-task.cpp new file mode 100644 index 0000000..bfd9256 --- /dev/null +++ b/dali-scene3d/internal/common/model-load-task.cpp @@ -0,0 +1,148 @@ +/* + * 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. + * + */ + +// CLASS HEADER +#include + +// EXTERNAL INCLUDES +#include +#include + +// INTERNAL INCLUDES +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace Dali +{ +namespace Scene3D +{ +namespace Internal +{ +namespace +{ +static constexpr Vector3 Y_DIRECTION(1.0f, -1.0f, 1.0f); + +static constexpr std::string_view OBJ_EXTENSION = ".obj"; +static constexpr std::string_view GLTF_EXTENSION = ".gltf"; +static constexpr std::string_view DLI_EXTENSION = ".dli"; +static constexpr std::string_view METADATA_EXTENSION = "metadata"; +} // namespace + +ModelLoadTask::ModelLoadTask(const std::string& modelUrl, const std::string& resourceDirectoryUrl, CallbackBase* callback) +: AsyncTask(callback), + mModelUrl(modelUrl), + mResourceDirectoryUrl(resourceDirectoryUrl), + mHasSucceeded(false) +{ +} + +ModelLoadTask::~ModelLoadTask() +{ +} + +void ModelLoadTask::Process() +{ + std::filesystem::path modelUrl(mModelUrl); + if(mResourceDirectoryUrl.empty()) + { + mResourceDirectoryUrl = std::string(modelUrl.parent_path()) + "/"; + } + std::string extension = modelUrl.extension(); + std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); + + Dali::Scene3D::Loader::ResourceBundle::PathProvider pathProvider = [&](Dali::Scene3D::Loader::ResourceType::Value type) + { + return mResourceDirectoryUrl; + }; + mAnimations.clear(); + + std::filesystem::path metaDataUrl = modelUrl; + metaDataUrl.replace_extension(METADATA_EXTENSION.data()); + + Dali::Scene3D::Loader::LoadSceneMetadata(metaDataUrl.c_str(), mMetaData); + + Dali::Scene3D::Loader::LoadResult result{mResources, mScene, mMetaData, mAnimations, mAnimGroups, mCameraParameters, mLights}; + + if(extension == DLI_EXTENSION) + { + Dali::Scene3D::Loader::DliLoader loader; + Dali::Scene3D::Loader::DliLoader::InputParams input{ + pathProvider(Dali::Scene3D::Loader::ResourceType::Mesh), + nullptr, + {}, + {}, + nullptr, + {}}; + Dali::Scene3D::Loader::DliLoader::LoadParams loadParams{input, result}; + if(!loader.LoadScene(mModelUrl, loadParams)) + { + DALI_LOG_ERROR("Failed to load scene from '%s': %s\n", mModelUrl.c_str(), loader.GetParseError().c_str()); + return; + } + } + else if(extension == GLTF_EXTENSION) + { + Dali::Scene3D::Loader::ShaderDefinitionFactory sdf; + sdf.SetResources(mResources); + Dali::Scene3D::Loader::LoadGltfScene(mModelUrl, sdf, result); + } + else + { + DALI_LOG_ERROR("Unsupported model type.\n"); + return; + } + + for(auto iRoot : mScene.GetRoots()) + { + mResourceRefCounts.push_back(mResources.CreateRefCounter()); + mScene.CountResourceRefs(iRoot, mResourceChoices, mResourceRefCounts.back()); + mResources.CountEnvironmentReferences(mResourceRefCounts.back()); + + mResources.LoadRawResources(mResourceRefCounts.back(), pathProvider); + + // glTF Mesh is defined in right hand coordinate system, with positive Y for Up direction. + // Because DALi uses left hand system, Y direciton will be flipped for environment map sampling. + for(auto&& env : mResources.mEnvironmentMaps) + { + env.first.mYDirection = Y_DIRECTION; + } + } + mHasSucceeded = true; +} + +bool ModelLoadTask::IsReady() +{ + return true; +} + +bool ModelLoadTask::HasSucceeded() const +{ + return mHasSucceeded; +} + +} // namespace Internal + +} // namespace Scene3D + +} // namespace Dali diff --git a/dali-scene3d/internal/common/model-load-task.h b/dali-scene3d/internal/common/model-load-task.h new file mode 100644 index 0000000..0e68e06 --- /dev/null +++ b/dali-scene3d/internal/common/model-load-task.h @@ -0,0 +1,103 @@ +#ifndef DALI_SCENE3D_MODEL_LOAD_TASK_H +#define DALI_SCENE3D_MODEL_LOAD_TASK_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 +#include + +// INTERNAL INCLUDES +#include +#include +#include + +namespace Dali +{ +namespace Scene3D +{ +namespace Internal +{ +class ModelLoadTask; +typedef IntrusivePtr ModelLoadTaskPtr; + +class ModelLoadTask : public AsyncTask +{ +public: + /** + * Constructor + * @param[in] modelUrl model file path.(e.g., glTF, and DLI). + * @param[in] resourceDirectoryUrl resource file path that includes binary, image etc. + * @param[in] callback The callback that is called when the operation is completed. + */ + ModelLoadTask(const std::string& modelUrl, const std::string& resourceDirectoryUrl, CallbackBase* callback); + + /** + * Destructor. + */ + ~ModelLoadTask(); + + /** + * Process the task + */ + void Process() override; + + /** + * Whether the task is ready to process. + * @return True if the task is ready to process. + */ + bool IsReady() override; + + /** + * Whether the task has succeeded. + * @return True if the task has succeeded. + */ + bool HasSucceeded() const; + +private: + // Undefined + ModelLoadTask(const ModelLoadTask& task) = delete; + + // Undefined + ModelLoadTask& operator=(const ModelLoadTask& task) = delete; + +public: + std::string mModelUrl; + std::string mResourceDirectoryUrl; + + Dali::Scene3D::Loader::ResourceBundle mResources; + Dali::Scene3D::Loader::SceneDefinition mScene; + Dali::Scene3D::Loader::SceneMetadata mMetaData; + std::vector mAnimGroups; + std::vector mCameraParameters; + std::vector mLights; + std::vector mAnimations; + + Dali::Scene3D::Loader::Customization::Choices mResourceChoices; + std::vector mResourceRefCounts; + bool mHasSucceeded; +}; + +} // namespace Internal + +} // namespace Scene3D + +} // namespace Dali + +#endif // DALI_SCENE3D_MODEL_LOAD_TASK_H diff --git a/dali-scene3d/internal/controls/model/model-impl.cpp b/dali-scene3d/internal/controls/model/model-impl.cpp index bed5f34..d936271 100644 --- a/dali-scene3d/internal/controls/model/model-impl.cpp +++ b/dali-scene3d/internal/controls/model/model-impl.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include // INTERNAL INCLUDES @@ -70,11 +71,6 @@ static constexpr Vector3 Y_DIRECTION(1.0f, -1.0f, 1.0f); static constexpr bool DEFAULT_MODEL_CHILDREN_SENSITIVE = false; static constexpr bool DEFAULT_MODEL_CHILDREN_FOCUSABLE = false; -static constexpr std::string_view KTX_EXTENSION = ".ktx"; -static constexpr std::string_view OBJ_EXTENSION = ".obj"; -static constexpr std::string_view GLTF_EXTENSION = ".gltf"; -static constexpr std::string_view DLI_EXTENSION = ".dli"; - struct BoundingVolume { void Init() @@ -188,12 +184,16 @@ Model::Model(const std::string& modelUrl, const std::string& resourceDirectoryUr mModelChildrenSensitive(DEFAULT_MODEL_CHILDREN_SENSITIVE), mModelChildrenFocusable(DEFAULT_MODEL_CHILDREN_FOCUSABLE), mModelResourceReady(false), - mIBLResourceReady(true) + mIblDiffuseResourceReady(true), + mIblSpecularResourceReady(true), + mIblDiffuseDirty(false), + mIblSpecularDirty(false) { } Model::~Model() { + ResetResourceTasks(); } Dali::Scene3D::Model Model::New(const std::string& modelUrl, const std::string& resourceDirectoryUrl) @@ -251,17 +251,98 @@ bool Model::GetChildrenFocusable() const void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor) { - mIBLResourceReady = false; - Texture diffuseTexture = (!diffuseUrl.empty()) ? Dali::Scene3D::Loader::LoadCubeMap(diffuseUrl) : Texture(); - Texture specularTexture = (!specularUrl.empty()) ? Dali::Scene3D::Loader::LoadCubeMap(specularUrl) : Texture(); - SetImageBasedLightTexture(diffuseTexture, specularTexture, scaleFactor); - mIBLResourceReady = true; + bool needIblReset = false; + bool isOnScene = Self().GetProperty(Dali::Actor::Property::CONNECTED_TO_SCENE); + if(mDiffuseIblUrl != diffuseUrl) + { + mDiffuseIblUrl = diffuseUrl; + if(mDiffuseIblUrl.empty()) + { + needIblReset = true; + } + else + { + mIblDiffuseDirty = true; + mIblDiffuseResourceReady = false; + } + } + + if(mSpecularIblUrl != specularUrl) + { + mSpecularIblUrl = specularUrl; + if(mSpecularIblUrl.empty()) + { + needIblReset = true; + } + else + { + mIblSpecularDirty = true; + mIblSpecularResourceReady = false; + } + } + + // If one or both of diffuse url and specular url are empty, + // we don't need to request to load texture. + if(needIblReset) + { + if(mIblDiffuseLoadTask) + { + Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask); + mIblDiffuseLoadTask.Reset(); + } + + if(mIblSpecularLoadTask) + { + Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask); + mIblSpecularLoadTask.Reset(); + } + + mIblDiffuseDirty = false; + mIblSpecularDirty = false; + mIblDiffuseResourceReady = true; + mIblSpecularResourceReady = true; + + mDiffuseTexture.Reset(); + mSpecularTexture.Reset(); + UpdateImageBasedLightTexture(); + } + else + { + if(isOnScene && mIblDiffuseDirty) + { + if(mIblDiffuseLoadTask) + { + Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask); + mIblDiffuseLoadTask.Reset(); + } + mIblDiffuseLoadTask = new EnvironmentMapLoadTask(mDiffuseIblUrl, MakeCallback(this, &Model::OnIblDiffuseLoadComplete)); + Dali::AsyncTaskManager::Get().AddTask(mIblDiffuseLoadTask); + mIblDiffuseDirty = false; + } + + if(isOnScene && mIblSpecularDirty) + { + if(mIblSpecularLoadTask) + { + Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask); + mIblSpecularLoadTask.Reset(); + } + mIblSpecularLoadTask = new EnvironmentMapLoadTask(mSpecularIblUrl, MakeCallback(this, &Model::OnIblSpecularLoadComplete)); + Dali::AsyncTaskManager::Get().AddTask(mIblSpecularLoadTask); + mIblSpecularDirty = false; + } + } + + if(!Dali::Equals(mIblScaleFactor, scaleFactor)) + { + mIblScaleFactor = scaleFactor; + UpdateImageBasedLightScaleFactor(); + } - // If Model resource is already ready, then set resource ready. - // If Model resource is still not ready, wait for model resource ready. + // If diffuse and specular textures are already loaded, emits resource ready signal here. if(IsResourceReady()) { - SetResourceReady(false); + Control::SetResourceReady(false); } } @@ -336,9 +417,16 @@ void Model::OnInitialize() void Model::OnSceneConnection(int depth) { - if(!mModelRoot) + if(!mModelLoadTask && !mModelRoot) + { + Scene3D::Loader::InitializeGltfLoader(); + mModelLoadTask = new ModelLoadTask(mModelUrl, mResourceDirectoryUrl, MakeCallback(this, &Model::OnModelLoadComplete)); + Dali::AsyncTaskManager::Get().AddTask(mModelLoadTask); + } + // If diffuse and specular url is not valid, IBL does not need to be loaded. + if(!mDiffuseIblUrl.empty() && !mSpecularIblUrl.empty()) { - LoadModel(); + SetImageBasedLightSource(mDiffuseIblUrl, mSpecularIblUrl, mIblScaleFactor); } Actor parent = Self().GetParent(); @@ -372,7 +460,8 @@ Vector3 Model::GetNaturalSize() { if(!mModelRoot) { - LoadModel(); + DALI_LOG_ERROR("Model is still not loaded.\n"); + return Vector3::ZERO; } return mNaturalSize; @@ -400,121 +489,187 @@ void Model::OnRelayout(const Vector2& size, RelayoutContainer& container) bool Model::IsResourceReady() const { - return mModelResourceReady && mIBLResourceReady; + return mModelResourceReady && mIblDiffuseResourceReady && mIblSpecularResourceReady; } -void Model::LoadModel() +void Model::ScaleModel() { - std::filesystem::path modelUrl(mModelUrl); - if(mResourceDirectoryUrl.empty()) + if(mModelRoot) { - mResourceDirectoryUrl = std::string(modelUrl.parent_path()) + "/"; + float scale = 1.0f; + Vector3 size = Self().GetProperty(Dali::Actor::Property::SIZE); + if(size.x > 0.0f && size.y > 0.0f) + { + scale = MAXFLOAT; + scale = std::min(size.x / mNaturalSize.x, scale); + scale = std::min(size.y / mNaturalSize.y, scale); + } + // Models in glTF and dli are defined as right hand coordinate system. + // DALi uses left hand coordinate system. Scaling negative is for change winding order. + mModelRoot.SetProperty(Dali::Actor::Property::SCALE, Y_DIRECTION * scale); } - std::string extension = modelUrl.extension(); - std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); +} - Dali::Scene3D::Loader::ResourceBundle::PathProvider pathProvider = [&](Dali::Scene3D::Loader::ResourceType::Value type) { - return mResourceDirectoryUrl; - }; +void Model::FitModelPosition() +{ + if(mModelRoot) + { + // Loaded model pivot is not the model center. + mModelRoot.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); + mModelRoot.SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3::ONE - mModelPivot); + } +} - Dali::Scene3D::Loader::ResourceBundle resources; - Dali::Scene3D::Loader::SceneDefinition scene; - std::vector animGroups; - std::vector cameraParameters; - std::vector lights; +void Model::CollectRenderableActor(Actor actor) +{ + uint32_t rendererCount = actor.GetRendererCount(); + if(rendererCount) + { + mRenderableActors.push_back(actor); + } - std::vector animations; - animations.clear(); + uint32_t childrenCount = actor.GetChildCount(); + for(uint32_t i = 0; i < childrenCount; ++i) + { + CollectRenderableActor(actor.GetChildAt(i)); + } +} - Dali::Scene3D::Loader::SceneMetadata metaData; +void Model::UpdateImageBasedLightTexture() +{ + Dali::Texture currentDiffuseTexture = (mDiffuseTexture && mSpecularTexture) ? mDiffuseTexture : mSceneDiffuseTexture; + Dali::Texture currentSpecularTexture = (mDiffuseTexture && mSpecularTexture) ? mSpecularTexture : mSceneSpecularTexture; + float currentIblScaleFactor = (mDiffuseTexture && mSpecularTexture) ? mIblScaleFactor : mSceneIblScaleFactor; - std::filesystem::path metaDataUrl = modelUrl; - metaDataUrl.replace_extension("metadata"); + if(!currentDiffuseTexture || !currentSpecularTexture) + { + currentDiffuseTexture = mDefaultDiffuseTexture; + currentSpecularTexture = mDefaultSpecularTexture; + currentIblScaleFactor = Dali::Scene3D::Loader::EnvironmentDefinition::GetDefaultIntensity(); + } - Dali::Scene3D::Loader::LoadSceneMetadata(metaDataUrl.c_str(), metaData); + for(auto&& actor : mRenderableActors) + { + Actor renderableActor = actor.GetHandle(); + if(renderableActor) + { + uint32_t rendererCount = renderableActor.GetRendererCount(); + for(uint32_t i = 0; i < rendererCount; ++i) + { + Dali::Renderer renderer = renderableActor.GetRendererAt(i); + if(renderer) + { + Dali::TextureSet textures = renderer.GetTextures(); + if(textures) + { + uint32_t textureCount = textures.GetTextureCount(); + // EnvMap requires at least 2 texture, diffuse and specular + if(textureCount > 2u) + { + textures.SetTexture(textureCount - OFFSET_FOR_DIFFUSE_CUBE_TEXTURE, currentDiffuseTexture); + textures.SetTexture(textureCount - OFFSET_FOR_SPECULAR_CUBE_TEXTURE, currentSpecularTexture); + } + } + } + } + renderableActor.RegisterProperty(Dali::Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName().data(), currentIblScaleFactor); + } + } +} - Dali::Scene3D::Loader::LoadResult output{resources, scene, metaData, animations, animGroups, cameraParameters, lights}; +void Model::UpdateImageBasedLightScaleFactor() +{ + if((!mDiffuseTexture || !mSpecularTexture) && + (!mSceneDiffuseTexture || !mSceneSpecularTexture)) + { + return; + } - if(extension == DLI_EXTENSION) + float currentIblScaleFactor = (mDiffuseTexture && mSpecularTexture) ? mIblScaleFactor : mSceneIblScaleFactor; + for(auto&& actor : mRenderableActors) { - Dali::Scene3D::Loader::DliLoader loader; - Dali::Scene3D::Loader::DliLoader::InputParams input{ - pathProvider(Dali::Scene3D::Loader::ResourceType::Mesh), - nullptr, - {}, - {}, - nullptr, - {}}; - Dali::Scene3D::Loader::DliLoader::LoadParams loadParams{input, output}; - if(!loader.LoadScene(mModelUrl, loadParams)) + Actor renderableActor = actor.GetHandle(); + if(renderableActor) { - Dali::Scene3D::Loader::ExceptionFlinger(ASSERT_LOCATION) << "Failed to load scene from '" << mModelUrl << "': " << loader.GetParseError(); + renderableActor.RegisterProperty(Dali::Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName().data(), currentIblScaleFactor); } } - else if(extension == GLTF_EXTENSION) - { - Dali::Scene3D::Loader::ShaderDefinitionFactory sdf; - sdf.SetResources(resources); - Dali::Scene3D::Loader::LoadGltfScene(mModelUrl, sdf, output); +} - resources.mEnvironmentMaps.push_back({}); +void Model::NotifyImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float scaleFactor) +{ + if(mSceneDiffuseTexture != diffuseTexture || mSceneSpecularTexture != specularTexture) + { + mSceneDiffuseTexture = diffuseTexture; + mSceneSpecularTexture = specularTexture; + mSceneIblScaleFactor = scaleFactor; + // If Model IBL is not set, use SceneView's IBL. + if(!mDiffuseTexture || !mSpecularTexture) + { + UpdateImageBasedLightTexture(); + } } - else +} + +void Model::NotifyImageBasedLightScaleFactor(float scaleFactor) +{ + mSceneIblScaleFactor = scaleFactor; + if(mSceneDiffuseTexture && mSceneSpecularTexture) { - DALI_LOG_ERROR("Unsupported model type.\n"); + UpdateImageBasedLightScaleFactor(); } +} - Dali::Scene3D::Loader::Transforms xforms{Dali::Scene3D::Loader::MatrixStack{}, Dali::Scene3D::Loader::ViewProjection{}}; - Dali::Scene3D::Loader::NodeDefinition::CreateParams nodeParams{resources, xforms, {}, {}, {}}; - Dali::Scene3D::Loader::Customization::Choices choices; +void Model::OnModelLoadComplete() +{ + if(!mModelLoadTask->HasSucceeded()) + { + ResetResourceTasks(); + return; + } mModelRoot = Actor::New(); mModelRoot.SetProperty(Actor::Property::COLOR_MODE, ColorMode::USE_OWN_MULTIPLY_PARENT_COLOR); - BoundingVolume AABB; - for(auto iRoot : scene.GetRoots()) + BoundingVolume AABB; + auto* resources = &(mModelLoadTask->mResources); + auto* scene = &(mModelLoadTask->mScene); + Dali::Scene3D::Loader::Transforms xforms{Dali::Scene3D::Loader::MatrixStack{}, Dali::Scene3D::Loader::ViewProjection{}}; + Dali::Scene3D::Loader::NodeDefinition::CreateParams nodeParams{*resources, xforms, {}, {}, {}}; + uint32_t rootCount = 0u; + for(auto iRoot : scene->GetRoots()) { - auto resourceRefs = resources.CreateRefCounter(); - scene.CountResourceRefs(iRoot, choices, resourceRefs); - resources.CountEnvironmentReferences(resourceRefs); - - resources.LoadResources(resourceRefs, pathProvider); + resources->GenerateResources(mModelLoadTask->mResourceRefCounts[rootCount]); - // glTF Mesh is defined in right hand coordinate system, with positive Y for Up direction. - // Because DALi uses left hand system, Y direciton will be flipped for environment map sampling. - for(auto&& env : resources.mEnvironmentMaps) + if(auto actor = scene->CreateNodes(iRoot, mModelLoadTask->mResourceChoices, nodeParams)) { - env.first.mYDirection = Y_DIRECTION; - } - - if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams)) - { - scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor); - scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables)); - ConfigureBlendShapeShaders(resources, scene, actor, std::move(nodeParams.mBlendshapeRequests)); + scene->ConfigureSkeletonJoints(iRoot, resources->mSkeletons, actor); + scene->ConfigureSkinningShaders(*resources, actor, std::move(nodeParams.mSkinnables)); + ConfigureBlendShapeShaders(*resources, *scene, actor, std::move(nodeParams.mBlendshapeRequests)); - scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables)); + scene->ApplyConstraints(actor, std::move(nodeParams.mConstrainables)); mModelRoot.Add(actor); } - AddModelTreeToAABB(AABB, scene, choices, iRoot, nodeParams, Matrix::IDENTITY); + AddModelTreeToAABB(AABB, *scene, mModelLoadTask->mResourceChoices, iRoot, nodeParams, Matrix::IDENTITY); + rootCount++; } - if(!resources.mEnvironmentMaps.empty()) + if(!resources->mEnvironmentMaps.empty()) { - mDefaultDiffuseTexture = resources.mEnvironmentMaps.front().second.mDiffuse; - mDefaultSpecularTexture = resources.mEnvironmentMaps.front().second.mSpecular; + mDefaultDiffuseTexture = resources->mEnvironmentMaps.front().second.mDiffuse; + mDefaultSpecularTexture = resources->mEnvironmentMaps.front().second.mSpecular; } - if(!animations.empty()) + if(!mModelLoadTask->mAnimations.empty()) { auto getActor = [&](const Scene3D::Loader::AnimatedProperty& property) { Dali::Actor actor; if(property.mNodeIndex != Scene3D::Loader::INVALID_INDEX) { - auto* node = scene.GetNode(property.mNodeIndex); + auto* node = scene->GetNode(property.mNodeIndex); if(node != nullptr) { actor = mModelRoot.FindChildById(node->mNodeId); @@ -528,7 +683,7 @@ void Model::LoadModel() }; mAnimations.clear(); - for(auto&& animation : animations) + for(auto&& animation : mModelLoadTask->mAnimations) { Dali::Animation anim = animation.ReAnimate(getActor); @@ -538,6 +693,7 @@ void Model::LoadModel() mRenderableActors.clear(); CollectRenderableActor(mModelRoot); + UpdateImageBasedLightTexture(); UpdateImageBasedLightScaleFactor(); @@ -563,129 +719,64 @@ void Model::LoadModel() mModelResourceReady = true; - Control::SetResourceReady(false); -} - -void Model::ScaleModel() -{ - if(mModelRoot) + if(IsResourceReady()) { - float scale = 1.0f; - Vector3 size = Self().GetProperty(Dali::Actor::Property::SIZE); - if(size.x > 0.0f && size.y > 0.0f) - { - scale = MAXFLOAT; - scale = std::min(size.x / mNaturalSize.x, scale); - scale = std::min(size.y / mNaturalSize.y, scale); - } - // Models in glTF and dli are defined as right hand coordinate system. - // DALi uses left hand coordinate system. Scaling negative is for change winding order. - mModelRoot.SetProperty(Dali::Actor::Property::SCALE, Y_DIRECTION * scale); + Control::SetResourceReady(false); } + mModelLoadTask.Reset(); } -void Model::FitModelPosition() +void Model::OnIblDiffuseLoadComplete() { - if(mModelRoot) + mDiffuseTexture = (mIblDiffuseLoadTask->HasSucceeded()) ? mIblDiffuseLoadTask->GetEnvironmentMap().CreateTexture() : Texture(); + mIblDiffuseResourceReady = true; + if(mIblDiffuseResourceReady && mIblSpecularResourceReady) { - // Loaded model pivot is not the model center. - mModelRoot.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); - mModelRoot.SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3::ONE - mModelPivot); + OnIblLoadComplete(); } + mIblDiffuseLoadTask.Reset(); } -void Model::CollectRenderableActor(Actor actor) +void Model::OnIblSpecularLoadComplete() { - uint32_t rendererCount = actor.GetRendererCount(); - if(rendererCount) + mSpecularTexture = (mIblSpecularLoadTask->HasSucceeded()) ? mIblSpecularLoadTask->GetEnvironmentMap().CreateTexture() : Texture(); + mIblSpecularResourceReady = true; + if(mIblDiffuseResourceReady && mIblSpecularResourceReady) { - mRenderableActors.push_back(actor); - } - - uint32_t childrenCount = actor.GetChildCount(); - for(uint32_t i = 0; i < childrenCount; ++i) - { - CollectRenderableActor(actor.GetChildAt(i)); + OnIblLoadComplete(); } + mIblSpecularLoadTask.Reset(); } -void Model::UpdateImageBasedLightTexture() +void Model::OnIblLoadComplete() { - Dali::Texture currentDiffuseTexture = (mDiffuseTexture) ? mDiffuseTexture : mSceneDiffuseTexture; - Dali::Texture currentSpecularTexture = (mSpecularTexture) ? mSpecularTexture : mSceneSpecularTexture; - float currentIBLScaleFactor = (mDiffuseTexture && mSpecularTexture) ? mIblScaleFactor : mSceneIblScaleFactor; - if(!currentDiffuseTexture || !currentSpecularTexture) - { - currentDiffuseTexture = mDefaultDiffuseTexture; - currentSpecularTexture = mDefaultSpecularTexture; - currentIBLScaleFactor = Dali::Scene3D::Loader::EnvironmentDefinition::GetDefaultIntensity(); - } + UpdateImageBasedLightTexture(); - for(auto&& actor : mRenderableActors) + if(IsResourceReady()) { - Actor renderableActor = actor.GetHandle(); - if(renderableActor) - { - uint32_t rendererCount = renderableActor.GetRendererCount(); - for(uint32_t i = 0; i < rendererCount; ++i) - { - Dali::Renderer renderer = renderableActor.GetRendererAt(i); - if(renderer) - { - Dali::TextureSet textures = renderer.GetTextures(); - if(textures) - { - uint32_t textureCount = textures.GetTextureCount(); - // EnvMap requires at least 2 texture, diffuse and specular - if(textureCount > 2u) - { - textures.SetTexture(textureCount - OFFSET_FOR_DIFFUSE_CUBE_TEXTURE, currentDiffuseTexture); - textures.SetTexture(textureCount - OFFSET_FOR_SPECULAR_CUBE_TEXTURE, currentSpecularTexture); - } - } - } - } - renderableActor.RegisterProperty(Dali::Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName().data(), currentIBLScaleFactor); - } + Control::SetResourceReady(false); } } -void Model::UpdateImageBasedLightScaleFactor() +void Model::ResetResourceTasks() { - if((!mDiffuseTexture || !mSpecularTexture) && - (!mSceneDiffuseTexture || !mSceneSpecularTexture)) + if(Dali::Adaptor::IsAvailable()) { - return; - } - - float currentIBLScaleFactor = (mDiffuseTexture && mSpecularTexture) ? mIblScaleFactor : mSceneIblScaleFactor; - for(auto&& actor : mRenderableActors) - { - Actor renderableActor = actor.GetHandle(); - if(renderableActor) + if(mModelLoadTask) { - renderableActor.RegisterProperty(Dali::Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName().data(), currentIBLScaleFactor); + Dali::AsyncTaskManager::Get().RemoveTask(mModelLoadTask); + mModelLoadTask.Reset(); + } + if(mIblDiffuseLoadTask) + { + Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask); + mIblDiffuseLoadTask.Reset(); + } + if(mIblSpecularLoadTask) + { + Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask); + mIblSpecularLoadTask.Reset(); } - } -} - -void Model::NotifyImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float scaleFactor) -{ - if(mSceneDiffuseTexture != diffuseTexture || mSceneSpecularTexture != specularTexture) - { - mSceneDiffuseTexture = diffuseTexture; - mSceneSpecularTexture = specularTexture; - mSceneIblScaleFactor = scaleFactor; - UpdateImageBasedLightTexture(); - } -} - -void Model::NotifyImageBasedLightScaleFactor(float scaleFactor) -{ - mSceneIblScaleFactor = scaleFactor; - if(mSceneDiffuseTexture && mSceneSpecularTexture) - { - UpdateImageBasedLightScaleFactor(); } } diff --git a/dali-scene3d/internal/controls/model/model-impl.h b/dali-scene3d/internal/controls/model/model-impl.h index 7bb4889..e4f1f08 100644 --- a/dali-scene3d/internal/controls/model/model-impl.h +++ b/dali-scene3d/internal/controls/model/model-impl.h @@ -26,7 +26,9 @@ #include // INTERNAL INCLUDES +#include #include +#include #include #include @@ -166,11 +168,6 @@ private: bool IsResourceReady() const override; /** - * @brief Loads a model from file - */ - void LoadModel(); - - /** * @brief Scales the model to fit the control or to return to original size. */ void ScaleModel(); @@ -207,6 +204,32 @@ public: // Overrides ImageBasedLightObserver Methods. void NotifyImageBasedLightScaleFactor(float scaleFactor) override; private: + /** + * @brief Asynchronously model loading finished. + */ + void OnModelLoadComplete(); + + /** + * @brief Asynchronously ibl diffusel image loading finished. + */ + void OnIblDiffuseLoadComplete(); + + /** + * @brief Asynchronously ibl specular image loading finished. + */ + void OnIblSpecularLoadComplete(); + + /** + * @brief Asynchronously ibl loading finished. + */ + void OnIblLoadComplete(); + + /** + * @brief Reset Resource loading tasks. + */ + void ResetResourceTasks(); + +private: std::string mModelUrl; std::string mResourceDirectoryUrl; Dali::Actor mModelRoot; @@ -214,6 +237,14 @@ private: std::vector> mRenderableActors; WeakHandle mParentSceneView; + // Asynchronous loading variable + ModelLoadTaskPtr mModelLoadTask; + EnvironmentMapLoadTaskPtr mIblDiffuseLoadTask; + EnvironmentMapLoadTaskPtr mIblSpecularLoadTask; + + std::string mDiffuseIblUrl; + std::string mSpecularIblUrl; + // TODO: This default texture can be removed after 3D Resource Cache is added. Dali::Texture mDefaultSpecularTexture; Dali::Texture mDefaultDiffuseTexture; @@ -228,7 +259,10 @@ private: bool mModelChildrenSensitive; bool mModelChildrenFocusable; bool mModelResourceReady; - bool mIBLResourceReady; + bool mIblDiffuseResourceReady; + bool mIblSpecularResourceReady; + bool mIblDiffuseDirty; + bool mIblSpecularDirty; }; } // namespace Internal diff --git a/dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp b/dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp index 28d0933..bb44ab7 100644 --- a/dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp +++ b/dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -34,6 +33,7 @@ #include #include #include +#include #include // INTERNAL INCLUDES @@ -67,7 +67,7 @@ constexpr uint8_t DEFAULT_FRAME_BUFFER_MULTI_SAMPLING_LEVEL = 4u; static constexpr std::string_view SKYBOX_INTENSITY_STRING = "uIntensity"; -Dali::Actor CreateSkybox(const std::string& skyboxUrl, Scene3D::SceneView::SkyboxType skyboxType) +Dali::Actor CreateSkybox() { struct Vertex { @@ -130,30 +130,9 @@ Dali::Actor CreateSkybox(const std::string& skyboxUrl, Scene3D::SceneView::Skybo skyboxGeometry.AddVertexBuffer(vertexBuffer); skyboxGeometry.SetType(Geometry::TRIANGLES); - Dali::Texture skyboxTexture; - Dali::Shader shaderSkybox; + Dali::Shader shaderSkybox = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data()); Dali::Renderer skyboxRenderer; - - if(skyboxType == Scene3D::SceneView::SkyboxType::CUBEMAP) - { - skyboxTexture = Dali::Scene3D::Loader::LoadCubeMap(skyboxUrl); - shaderSkybox = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data()); - } - else // Scene3D::SceneView::SkyboxType::EQUIRECTANGULAR - { - // Load image from file - PixelData pixels = Dali::Toolkit::SyncImageLoader::Load(skyboxUrl); - - skyboxTexture = Texture::New(TextureType::TEXTURE_2D, pixels.GetPixelFormat(), pixels.GetWidth(), pixels.GetHeight()); - skyboxTexture.Upload(pixels, 0, 0, 0, 0, pixels.GetWidth(), pixels.GetHeight()); - shaderSkybox = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_EQUIRECTANGULAR_SHADER_FRAG.data()); - } - - Dali::TextureSet skyboxTextures = TextureSet::New(); - skyboxTextures.SetTexture(0, skyboxTexture); - skyboxRenderer = Renderer::New(skyboxGeometry, shaderSkybox); - skyboxRenderer.SetTextures(skyboxTextures); skyboxRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, 2.0f); // Enables the depth test. skyboxRenderer.SetProperty(Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON); @@ -179,7 +158,27 @@ SceneView::SceneView() { } -SceneView::~SceneView() = default; +SceneView::~SceneView() +{ + if(Dali::Adaptor::IsAvailable()) + { + if(mIblDiffuseLoadTask) + { + Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask); + mIblDiffuseLoadTask.Reset(); + } + if(mIblSpecularLoadTask) + { + Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask); + mIblSpecularLoadTask.Reset(); + } + if(mSkyboxLoadTask) + { + Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask); + mSkyboxLoadTask.Reset(); + } + } +} Dali::Scene3D::SceneView SceneView::New() { @@ -303,23 +302,95 @@ void SceneView::UnregisterSceneItem(Scene3D::Internal::ImageBasedLightObserver* void SceneView::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor) { - mIBLResourceReady = false; + bool needIblReset = false; + bool isOnScene = Self().GetProperty(Dali::Actor::Property::CONNECTED_TO_SCENE); + if(mDiffuseIblUrl != diffuseUrl) + { + mDiffuseIblUrl = diffuseUrl; + if(mDiffuseIblUrl.empty()) + { + needIblReset = true; + } + else + { + mIblDiffuseDirty = true; + mIblDiffuseResourceReady = false; + } + } - // If url is empty or invalid, reset IBL. - mDiffuseTexture = (!diffuseUrl.empty()) ? Dali::Scene3D::Loader::LoadCubeMap(diffuseUrl) : Texture(); - mSpecularTexture = (!specularUrl.empty()) ? Dali::Scene3D::Loader::LoadCubeMap(specularUrl) : Texture(); + if(mSpecularIblUrl != specularUrl) + { + mSpecularIblUrl = specularUrl; + if(mSpecularIblUrl.empty()) + { + needIblReset = true; + } + else + { + mIblSpecularDirty = true; + mIblSpecularResourceReady = false; + } + } - mIblScaleFactor = scaleFactor; + // If one or both of diffuse url and specular url are empty, + // we don't need to request to load texture. + if(needIblReset) + { + if(mIblDiffuseLoadTask) + { + Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask); + mIblDiffuseLoadTask.Reset(); + } - for(auto&& item : mItems) + if(mIblSpecularLoadTask) + { + Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask); + mIblSpecularLoadTask.Reset(); + } + + mIblDiffuseDirty = false; + mIblSpecularDirty = false; + mIblDiffuseResourceReady = true; + mIblSpecularResourceReady = true; + + mDiffuseTexture.Reset(); + mSpecularTexture.Reset(); + + NotifyImageBasedLightTextureChange(); + } + else { - if(item) + if(isOnScene && mIblDiffuseDirty) { - item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor); + if(mIblDiffuseLoadTask) + { + Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask); + mIblDiffuseLoadTask.Reset(); + } + mIblDiffuseLoadTask = new EnvironmentMapLoadTask(mDiffuseIblUrl, MakeCallback(this, &SceneView::OnIblDiffuseLoadComplete)); + Dali::AsyncTaskManager::Get().AddTask(mIblDiffuseLoadTask); + mIblDiffuseDirty = false; } + + if(isOnScene && mIblSpecularDirty) + { + if(mIblSpecularLoadTask) + { + Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask); + mIblSpecularLoadTask.Reset(); + } + mIblSpecularLoadTask = new EnvironmentMapLoadTask(mSpecularIblUrl, MakeCallback(this, &SceneView::OnIblSpecularLoadComplete)); + Dali::AsyncTaskManager::Get().AddTask(mIblSpecularLoadTask); + mIblSpecularDirty = false; + } + } + + if(!Dali::Equals(mIblScaleFactor, scaleFactor)) + { + SetImageBasedLightScaleFactor(scaleFactor); } - mIBLResourceReady = true; + // If diffuse and specular textures are already loaded, emits resource ready signal here. if(IsResourceReady()) { Control::SetResourceReady(false); @@ -359,21 +430,57 @@ bool SceneView::IsUsingFramebuffer() const void SceneView::SetSkybox(const std::string& skyboxUrl, Scene3D::SceneView::SkyboxType skyboxType) { - mSkyboxResourceReady = false; - if(mSkybox) + mSkyboxEnvironmentMapType = skyboxType; + bool isOnScene = Self().GetProperty(Dali::Actor::Property::CONNECTED_TO_SCENE); + if(mSkyboxUrl != skyboxUrl) + { + mSkyboxDirty = true; + mSkyboxResourceReady = false; + mSkyboxUrl = skyboxUrl; + } + + if(mSkyboxUrl.empty()) { - mSkybox.Unparent(); - mSkybox.Reset(); + if(mSkyboxLoadTask) + { + Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask); + mSkyboxLoadTask.Reset(); + } + if(mSkyboxImageLoader) + { + mSkyboxImageLoader.Cancel(mSkyboxImageId); + } + mSkyboxDirty = false; + mSkyboxResourceReady = true; } - mSkybox = CreateSkybox(skyboxUrl, skyboxType); - SetSkyboxIntensity(mSkyboxIntensity); - SetSkyboxOrientation(mSkyboxOrientation); - if(mRootLayer) + else { - mRootLayer.Add(mSkybox); + if(isOnScene && mSkyboxDirty) + { + if(mSkyboxLoadTask) + { + Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask); + mSkyboxLoadTask.Reset(); + } + if(mSkyboxImageLoader) + { + mSkyboxImageLoader.Cancel(mSkyboxImageId); + } + if(mSkyboxEnvironmentMapType == Scene3D::SceneView::SkyboxType::CUBEMAP) + { + mSkyboxLoadTask = new EnvironmentMapLoadTask(mSkyboxUrl, MakeCallback(this, &SceneView::OnSkyboxLoadComplete)); + Dali::AsyncTaskManager::Get().AddTask(mSkyboxLoadTask); + } + else + { + mSkyboxImageLoader = Dali::Toolkit::AsyncImageLoader::New(); + mSkyboxImageLoader.ImageLoadedSignal().Connect(this, &SceneView::OnSkyboxEquirectangularLoadComplete); + mSkyboxImageId = mSkyboxImageLoader.Load(mSkyboxUrl); + } + mSkyboxDirty = false; + } } - mSkyboxResourceReady = true; if(IsResourceReady()) { Control::SetResourceReady(false); @@ -421,6 +528,17 @@ Quaternion SceneView::GetSkyboxOrientation() const void SceneView::OnSceneConnection(int depth) { + // If diffuse and specular url is not valid, IBL does not need to be loaded. + if(!mDiffuseIblUrl.empty() && !mSpecularIblUrl.empty()) + { + SetImageBasedLightSource(mDiffuseIblUrl, mSpecularIblUrl, mIblScaleFactor); + } + + if(!mSkyboxUrl.empty()) + { + SetSkybox(mSkyboxUrl, mSkyboxEnvironmentMapType); + } + Window window = DevelWindow::Get(Self()); if(window) { @@ -518,7 +636,7 @@ void SceneView::OnRelayout(const Vector2& size, RelayoutContainer& container) bool SceneView::IsResourceReady() const { - return mIBLResourceReady & mSkyboxResourceReady; + return mIblDiffuseResourceReady && mIblSpecularResourceReady && mSkyboxResourceReady; } void SceneView::UpdateCamera(CameraActor camera) @@ -630,6 +748,97 @@ void SceneView::RotateCamera() } } +void SceneView::OnSkyboxEquirectangularLoadComplete(uint32_t loadedTaskId, PixelData pixelData) +{ + mSkyboxTexture = Texture::New(TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight()); + mSkyboxTexture.Upload(pixelData, 0, 0, 0, 0, pixelData.GetWidth(), pixelData.GetHeight()); + OnSkyboxLoadComplete(); +} + +void SceneView::OnSkyboxLoadComplete() +{ + if(!mSkybox) + { + mSkybox = CreateSkybox(); + SetSkyboxIntensity(mSkyboxIntensity); + SetSkyboxOrientation(mSkyboxOrientation); + if(mRootLayer) + { + mRootLayer.Add(mSkybox); + } + } + + mSkyboxResourceReady = true; + if(IsResourceReady()) + { + Control::SetResourceReady(false); + } + + Shader skyboxShader; + if(mSkyboxEnvironmentMapType == Scene3D::SceneView::SkyboxType::CUBEMAP) + { + mSkyboxTexture = (mSkyboxLoadTask->HasSucceeded()) ? mSkyboxLoadTask->GetEnvironmentMap().CreateTexture() : Texture(); + skyboxShader = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data()); + Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask); + mSkyboxLoadTask.Reset(); + } + else + { + skyboxShader = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_EQUIRECTANGULAR_SHADER_FRAG.data()); + } + + Renderer skyboxRenderer = (mSkybox.GetRendererCount() > 0u) ? mSkybox.GetRendererAt(0u) : Renderer(); + if(skyboxRenderer) + { + Dali::TextureSet skyboxTextures = TextureSet::New(); + skyboxTextures.SetTexture(0, mSkyboxTexture); + skyboxRenderer.SetTextures(skyboxTextures); + skyboxRenderer.SetShader(skyboxShader); + } +} + +void SceneView::OnIblDiffuseLoadComplete() +{ + mDiffuseTexture = (mIblDiffuseLoadTask->HasSucceeded()) ? mIblDiffuseLoadTask->GetEnvironmentMap().CreateTexture() : Texture(); + mIblDiffuseResourceReady = true; + if(mIblDiffuseResourceReady && mIblSpecularResourceReady) + { + OnIblLoadComplete(); + } + mIblDiffuseLoadTask.Reset(); +} + +void SceneView::OnIblSpecularLoadComplete() +{ + mSpecularTexture = (mIblSpecularLoadTask->HasSucceeded()) ? mIblSpecularLoadTask->GetEnvironmentMap().CreateTexture() : Texture(); + mIblSpecularResourceReady = true; + if(mIblDiffuseResourceReady && mIblSpecularResourceReady) + { + OnIblLoadComplete(); + } + mIblSpecularLoadTask.Reset(); +} + +void SceneView::OnIblLoadComplete() +{ + NotifyImageBasedLightTextureChange(); + if(IsResourceReady()) + { + Control::SetResourceReady(false); + } +} + +void SceneView::NotifyImageBasedLightTextureChange() +{ + for(auto&& item : mItems) + { + if(item) + { + item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor); + } + } +} + } // namespace Internal } // namespace Scene3D } // namespace Dali diff --git a/dali-scene3d/internal/controls/scene-view/scene-view-impl.h b/dali-scene3d/internal/controls/scene-view/scene-view-impl.h index def2b83..4b026d5 100644 --- a/dali-scene3d/internal/controls/scene-view/scene-view-impl.h +++ b/dali-scene3d/internal/controls/scene-view/scene-view-impl.h @@ -21,6 +21,7 @@ // EXTERNAL INCLUDES #include #include +#include #include #include #include @@ -31,8 +32,9 @@ #include // INTERNAL INCLUDES -#include #include +#include +#include namespace Dali { @@ -241,6 +243,36 @@ private: */ void RotateCamera(); + /** + * @brief Asynchronously skybox (Equirectangular) loading finished. + */ + void OnSkyboxEquirectangularLoadComplete(uint32_t loadedTaskId, PixelData pixelData); + + /** + * @brief Asynchronously skybox loading finished. + */ + void OnSkyboxLoadComplete(); + + /** + * @brief Asynchronously ibl diffusel image loading finished. + */ + void OnIblDiffuseLoadComplete(); + + /** + * @brief Asynchronously ibl specular image loading finished. + */ + void OnIblSpecularLoadComplete(); + + /** + * @brief Asynchronously ibl loading finished. + */ + void OnIblLoadComplete(); + + /** + * @brief Notify the changes of Ibl textures to the child items. + */ + void NotifyImageBasedLightTextureChange(); + private: Toolkit::Visual::Base mVisual; @@ -260,12 +292,28 @@ private: Quaternion mSkyboxOrientation; float mSkyboxIntensity{1.0f}; - Dali::Texture mSpecularTexture; - Dali::Texture mDiffuseTexture; - float mIblScaleFactor{1.0f}; - bool mUseFrameBuffer{false}; - bool mIBLResourceReady{true}; - bool mSkyboxResourceReady{true}; + // Asynchronous Loading. + EnvironmentMapLoadTaskPtr mSkyboxLoadTask; + EnvironmentMapLoadTaskPtr mIblDiffuseLoadTask; + EnvironmentMapLoadTaskPtr mIblSpecularLoadTask; + std::string mSkyboxUrl; + std::string mDiffuseIblUrl; + std::string mSpecularIblUrl; + Dali::Toolkit::AsyncImageLoader mSkyboxImageLoader; + uint32_t mSkyboxImageId{0u}; + + Scene3D::SceneView::SkyboxType mSkyboxEnvironmentMapType; + Dali::Texture mSkyboxTexture; + Dali::Texture mDiffuseTexture; + Dali::Texture mSpecularTexture; + float mIblScaleFactor{1.0f}; + bool mUseFrameBuffer{false}; + bool mSkyboxResourceReady{true}; + bool mIblDiffuseResourceReady{true}; + bool mIblSpecularResourceReady{true}; + bool mSkyboxDirty{false}; + bool mIblDiffuseDirty{false}; + bool mIblSpecularDirty{false}; // TODO : Light Source }; diff --git a/dali-scene3d/internal/file.list b/dali-scene3d/internal/file.list index c4e735b..d264857 100644 --- a/dali-scene3d/internal/file.list +++ b/dali-scene3d/internal/file.list @@ -1,6 +1,8 @@ set(scene3d_internal_dir "${scene3d_dir}/internal") set(scene3d_src_files ${scene3d_src_files} + ${scene3d_internal_dir}/common/environment-map-load-task.cpp + ${scene3d_internal_dir}/common/model-load-task.cpp ${scene3d_internal_dir}/controls/model/model-impl.cpp ${scene3d_internal_dir}/controls/scene-view/scene-view-impl.cpp ${scene3d_internal_dir}/loader/gltf2-asset.cpp diff --git a/dali-scene3d/public-api/controls/scene-view/scene-view.h b/dali-scene3d/public-api/controls/scene-view/scene-view.h index 7c4f67b..e538d29 100644 --- a/dali-scene3d/public-api/controls/scene-view/scene-view.h +++ b/dali-scene3d/public-api/controls/scene-view/scene-view.h @@ -331,7 +331,7 @@ public: * * @SINCE_2_2.0 * @param[in] skyboxUrl image url for skybox. - * @param[in] skyboxType The skybox type (by default it is cubemap). + * @param[in] skyboxType The environment type of skymap (by default it is cubemap). */ void SetSkybox(const std::string& skyboxUrl, SkyboxType skyboxType = SkyboxType::CUBEMAP); diff --git a/dali-scene3d/public-api/loader/animation-definition.cpp b/dali-scene3d/public-api/loader/animation-definition.cpp index 6f24d9e..c201314 100644 --- a/dali-scene3d/public-api/loader/animation-definition.cpp +++ b/dali-scene3d/public-api/loader/animation-definition.cpp @@ -50,25 +50,25 @@ AnimationDefinition::AnimationDefinition(AnimationDefinition&& other) void AnimationDefinition::Animate(Animation& animation, AnimatedProperty::GetActor getActor) { DALI_ASSERT_ALWAYS(animation); - for(auto& ap : mProperties) + for(auto& property : mProperties) { - ap.Animate(animation, getActor); + property.Animate(animation, getActor); } } Animation AnimationDefinition::ReAnimate(AnimatedProperty::GetActor getActor) { // Create and configure new animation. - Animation a = Animation::New(mDuration); - a.SetLoopCount(mLoopCount); - a.SetDisconnectAction(mDisconnectAction); - a.SetEndAction(mEndAction); + Animation animation = Animation::New(mDuration); + animation.SetLoopCount(mLoopCount); + animation.SetDisconnectAction(mDisconnectAction); + animation.SetEndAction(mEndAction); - a.SetSpeedFactor(mSpeedFactor); - a.SetPlayRange(mPlayRange); + animation.SetSpeedFactor(mSpeedFactor); + animation.SetPlayRange(mPlayRange); - Animate(a, getActor); - return a; + Animate(animation, getActor); + return animation; } AnimationDefinition& AnimationDefinition::operator=(AnimationDefinition&& other) diff --git a/dali-scene3d/public-api/loader/cube-loader.cpp b/dali-scene3d/public-api/loader/cube-loader.cpp index 7573421..96cafcb 100644 --- a/dali-scene3d/public-api/loader/cube-loader.cpp +++ b/dali-scene3d/public-api/loader/cube-loader.cpp @@ -93,7 +93,6 @@ namespace Loader { bool LoadCubeData(const std::string& path, CubeData& cubedata) { - Texture cubeTexture; // Diffuse Cube Map if(path.empty()) { diff --git a/dali-scene3d/public-api/loader/environment-definition.cpp b/dali-scene3d/public-api/loader/environment-definition.cpp index a8bb7a2..0c76617 100644 --- a/dali-scene3d/public-api/loader/environment-definition.cpp +++ b/dali-scene3d/public-api/loader/environment-definition.cpp @@ -59,7 +59,7 @@ EnvironmentDefinition::LoadRaw(const std::string& environmentsPath) const face.push_back(PixelData::New(new uint8_t[3]{0xff, 0xff, 0xff}, 3, 1, 1, Pixel::RGB888, PixelData::DELETE_ARRAY)); } } - else if(!LoadCubeMapData(environmentsPath + path, cd)) + else if(!LoadCubeMapData(environmentsPath + path, cd)) // TODO: supporting EQUIRECTANGULAR { ExceptionFlinger(ASSERT_LOCATION) << "Failed to load cubemap texture from '" << path << "'."; } diff --git a/dali-scene3d/public-api/loader/environment-definition.h b/dali-scene3d/public-api/loader/environment-definition.h index d80982a..a6f1946 100644 --- a/dali-scene3d/public-api/loader/environment-definition.h +++ b/dali-scene3d/public-api/loader/environment-definition.h @@ -24,6 +24,7 @@ // EXTERNAL INCLUDES #include "dali/public-api/math/quaternion.h" #include "dali/public-api/rendering/texture.h" +#include namespace Dali { @@ -87,12 +88,13 @@ struct DALI_SCENE3D_API EnvironmentDefinition static float GetDefaultIntensity(); public: // DATA - std::string mDiffuseMapPath; - std::string mSpecularMapPath; - Quaternion mCubeOrientation = Quaternion::IDENTITY; - Vector3 mYDirection = Vector3::ONE; - float mIblIntensity = 1.0f; - bool mUseBrdfTexture = false; + std::string mDiffuseMapPath; + std::string mSpecularMapPath; + std::shared_ptr mRawData; + Quaternion mCubeOrientation = Quaternion::IDENTITY; + Vector3 mYDirection = Vector3::ONE; + float mIblIntensity = 1.0f; + bool mUseBrdfTexture = false; }; } // namespace Loader diff --git a/dali-scene3d/public-api/loader/gltf2-loader.cpp b/dali-scene3d/public-api/loader/gltf2-loader.cpp index 257ba32..6d209d2 100644 --- a/dali-scene3d/public-api/loader/gltf2-loader.cpp +++ b/dali-scene3d/public-api/loader/gltf2-loader.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include // INTERNAL INCLUDES @@ -43,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"); @@ -76,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) @@ -1230,6 +1231,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; @@ -1245,14 +1261,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); @@ -1272,8 +1280,11 @@ 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}; diff --git a/dali-scene3d/public-api/loader/gltf2-loader.h b/dali-scene3d/public-api/loader/gltf2-loader.h index 765cd40..dc7becf 100644 --- a/dali-scene3d/public-api/loader/gltf2-loader.h +++ b/dali-scene3d/public-api/loader/gltf2-loader.h @@ -34,9 +34,16 @@ struct LoadResult; class ShaderDefinitionFactory; /** + * @brief Initialize glTF Loader. + * @note This method should be called once before LoadGltfScene() is called. + */ +DALI_SCENE3D_API void InitializeGltfLoader(); + +/** * @brief Loads the scene from the glTF file located at @a url, storing the results in @a params. * @note Will throw std::runtime_error for JSON entities with types mismatching expectations, carrying * invalid values, or I/O errors. + * @note InitializeGltfLoader() should be called once before this function is called. */ DALI_SCENE3D_API void LoadGltfScene(const std::string& url, ShaderDefinitionFactory& shaderFactory, LoadResult& params); diff --git a/dali-scene3d/public-api/loader/material-definition.h b/dali-scene3d/public-api/loader/material-definition.h index b59c6aa..00c2a83 100644 --- a/dali-scene3d/public-api/loader/material-definition.h +++ b/dali-scene3d/public-api/loader/material-definition.h @@ -225,7 +225,8 @@ struct DALI_SCENE3D_API MaterialDefinition } public: // DATA - uint32_t mFlags = 0x0; + std::shared_ptr mRawData; + uint32_t mFlags = 0x0; Index mEnvironmentIdx = 0; Vector4 mColor = Color::WHITE; diff --git a/dali-scene3d/public-api/loader/mesh-definition.h b/dali-scene3d/public-api/loader/mesh-definition.h index 595d06e..1030c7c 100644 --- a/dali-scene3d/public-api/loader/mesh-definition.h +++ b/dali-scene3d/public-api/loader/mesh-definition.h @@ -268,18 +268,19 @@ struct DALI_SCENE3D_API MeshDefinition MeshGeometry Load(RawData&& raw) const; public: // DATA - uint32_t mFlags = 0x0; - Geometry::Type mPrimitiveType = Geometry::TRIANGLES; - std::string mUri; - Accessor mIndices; - Accessor mPositions; - Accessor mNormals; // data can be generated based on positions - Accessor mTexCoords; - Accessor mColors; - Accessor mTangents; // data can be generated based on normals and texCoords (the latter isn't mandatory; the results will be better if available) - Accessor mJoints0; - Accessor mWeights0; - Property::Type mTangentType{Property::VECTOR3}; + std::shared_ptr mRawData; + uint32_t mFlags = 0x0; + Geometry::Type mPrimitiveType = Geometry::TRIANGLES; + std::string mUri; + Accessor mIndices; + Accessor mPositions; + Accessor mNormals; // data can be generated based on positions + Accessor mTexCoords; + Accessor mColors; + Accessor mTangents; // data can be generated based on normals and texCoords (the latter isn't mandatory; the results will be better if available) + Accessor mJoints0; + Accessor mWeights0; + Property::Type mTangentType{Property::VECTOR3}; Blob mBlendShapeHeader; std::vector mBlendShapes; diff --git a/dali-scene3d/public-api/loader/resource-bundle.cpp b/dali-scene3d/public-api/loader/resource-bundle.cpp index 5df41e2..38f6bc9 100644 --- a/dali-scene3d/public-api/loader/resource-bundle.cpp +++ b/dali-scene3d/public-api/loader/resource-bundle.cpp @@ -148,6 +148,119 @@ void ResourceBundle::LoadResources(const ResourceRefCounts& refCounts, PathProvi } } +void ResourceBundle::LoadRawResources(const ResourceRefCounts& refCounts, PathProvider pathProvider, Options::Type options) +{ + const auto kForceLoad = MaskMatch(options, Options::ForceReload); + + const auto& refCountEnvMaps = refCounts[ResourceType::Environment]; + auto environmentsPath = pathProvider(ResourceType::Environment); + for(uint32_t i = 0, iEnd = refCountEnvMaps.Size(); i != iEnd; ++i) + { + auto refCount = refCountEnvMaps[i]; + auto& iEnvMap = mEnvironmentMaps[i]; + if(refCount > 0 && (kForceLoad || !iEnvMap.second.IsLoaded())) + { + iEnvMap.first.mRawData = std::make_shared(iEnvMap.first.LoadRaw(environmentsPath)); + } + } + + const auto& refCountShaders = refCounts[ResourceType::Shader]; + auto shadersPath = pathProvider(ResourceType::Shader); + for(uint32_t i = 0, iEnd = refCountShaders.Size(); i != iEnd; ++i) + { + auto refCount = refCountShaders[i]; + auto& iShader = mShaders[i]; + if(refCount > 0 && (kForceLoad || !iShader.second)) + { + iShader.first.mRawData = std::make_shared(iShader.first.LoadRaw(shadersPath)); + } + } + + const auto& refCountMeshes = refCounts[ResourceType::Mesh]; + auto modelsPath = pathProvider(ResourceType::Mesh); + for(uint32_t i = 0, iEnd = refCountMeshes.Size(); i != iEnd; ++i) + { + auto refCount = refCountMeshes[i]; + auto& iMesh = mMeshes[i]; + if(refCount > 0 && (kForceLoad || !iMesh.second.geometry)) + { + iMesh.first.mRawData = std::make_shared(iMesh.first.LoadRaw(modelsPath)); + } + } + + const auto& refCountMaterials = refCounts[ResourceType::Material]; + auto imagesPath = pathProvider(ResourceType::Material); + for(uint32_t i = 0, iEnd = refCountMaterials.Size(); i != iEnd; ++i) + { + auto refCount = refCountMaterials[i]; + auto& iMaterial = mMaterials[i]; + if(refCount > 0 && (kForceLoad || !iMaterial.second)) + { + iMaterial.first.mRawData = std::make_shared(iMaterial.first.LoadRaw(imagesPath)); + } + } +} + +void ResourceBundle::GenerateResources(const ResourceRefCounts& refCounts, Options::Type options) +{ + const auto& refCountEnvMaps = refCounts[ResourceType::Environment]; + for(uint32_t i = 0, iEnd = refCountEnvMaps.Size(); i != iEnd; ++i) + { + auto& iEnvMap = mEnvironmentMaps[i]; + if(iEnvMap.first.mRawData) + { + iEnvMap.second = iEnvMap.first.Load(std::move(*(iEnvMap.first.mRawData))); + } + else + { + iEnvMap.second.mDiffuse = Texture(); + iEnvMap.second.mSpecular = Texture(); + } + } + + const auto& refCountShaders = refCounts[ResourceType::Shader]; + for(uint32_t i = 0, iEnd = refCountShaders.Size(); i != iEnd; ++i) + { + auto& iShader = mShaders[i]; + if(iShader.first.mRawData) + { + iShader.second = iShader.first.Load(std::move(*(iShader.first.mRawData))); + } + else + { + iShader.second = Shader(); + } + } + + const auto& refCountMeshes = refCounts[ResourceType::Mesh]; + for(uint32_t i = 0, iEnd = refCountMeshes.Size(); i != iEnd; ++i) + { + auto& iMesh = mMeshes[i]; + if(iMesh.first.mRawData) + { + iMesh.second = iMesh.first.Load(std::move(*(iMesh.first.mRawData))); + } + else + { + iMesh.second.geometry = Geometry(); + } + } + + const auto& refCountMaterials = refCounts[ResourceType::Material]; + for(uint32_t i = 0, iEnd = refCountMaterials.Size(); i != iEnd; ++i) + { + auto& iMaterial = mMaterials[i]; + if(iMaterial.first.mRawData) + { + iMaterial.second = iMaterial.first.Load(mEnvironmentMaps, std::move(*(iMaterial.first.mRawData))); + } + else + { + iMaterial.second = TextureSet(); + } + } +} + } // namespace Loader } // namespace Scene3D } // namespace Dali diff --git a/dali-scene3d/public-api/loader/resource-bundle.h b/dali-scene3d/public-api/loader/resource-bundle.h index 1537f72..cea48c0 100644 --- a/dali-scene3d/public-api/loader/resource-bundle.h +++ b/dali-scene3d/public-api/loader/resource-bundle.h @@ -90,31 +90,64 @@ public: ResourceBundle(ResourceBundle&&) = default; ResourceBundle& operator=(ResourceBundle&&) = default; - /* + /** * @return A ResourceRefCounts object with the correct number of entries for * all resource types (based on the various resource definition vectors), * with all reference counts set to 0. */ ResourceRefCounts CreateRefCounter() const; - /* + /** * @brief Based on a ResourceRefCounts, and more specifically the reference * count of materials therein, it will calculate the reference count of * environment maps. */ void CountEnvironmentReferences(ResourceRefCounts& refCounts) const; - /* + /** * @brief Performs the loading of all resources based on their respective - * reference count in @a refCounts. Resources that had a non-zero ref count will be - * loaded unless we already have a handle to them (OR the ForceReload option was specified). - * Any handles we have to resources that come in with a zero ref count will be reset, - * UNLESS the KeepUnused option was specified. + * reference count in @a refCounts. Resources that had a non-zero ref count will be + * loaded unless we already have a handle to them (OR the ForceReload option was specified). + * Any handles we have to resources that come in with a zero ref count will be reset, + * UNLESS the KeepUnused option was specified. + * @param[in] refCounts Reference Count that denote how many the resource is used. + * @param[in] pathProvider path provider for resource data. + * @param[in] options Option to load resource + * @note This method creates DALi objects like Dali::Texture, Dali::Geometry, etc. */ void LoadResources(const ResourceRefCounts& refCounts, PathProvider pathProvider, Options::Type options = Options::None); + /** + * @brief Loads of all resources based on their respective + * reference count in @a refCounts. Resources that had a non-zero ref count will be + * loaded unless we already have a handle to them (OR the ForceReload option was specified). + * Any handles we have to resources that come in with a zero ref count will be reset, + * UNLESS the KeepUnused option was specified. + * @note This method don't create any of DALi objects. + * @param[in] refCounts Reference Count that denote how many the resource is used. + * @param[in] pathProvider path provider for resource data. + * @param[in] options Option to load resource + * @note This method only loads raw data from resource file, and + * doesn't create any of DALi objects. GenerateResources() method is required to be called + * after this method to create DALi objects. + */ + void LoadRawResources(const ResourceRefCounts& refCounts, + PathProvider pathProvider, + Options::Type options = Options::None); + + /** + * @brief Generates DALi objects from already loaded Raw Resources. + * @param[in] refCounts Reference Count that denote how many the resource is used. + * @param[in] options Option to load resource + * @note This method generates DALi objects from raw data that is already + * loaded by LoadRawResources method. Therefore, LoadRawResources should be called first + * before this method is called. + */ + void GenerateResources(const ResourceRefCounts& refCounts, + Options::Type options = Options::None); + public: // DATA EnvironmentDefinition::Vector mEnvironmentMaps; ShaderDefinition::Vector mShaders; diff --git a/dali-scene3d/public-api/loader/shader-definition.h b/dali-scene3d/public-api/loader/shader-definition.h index d381c57..3d3236b 100644 --- a/dali-scene3d/public-api/loader/shader-definition.h +++ b/dali-scene3d/public-api/loader/shader-definition.h @@ -56,7 +56,7 @@ struct DALI_SCENE3D_API ShaderDefinition ShaderDefinition(const ShaderDefinition& other); ShaderDefinition& operator=(const ShaderDefinition& other); - ShaderDefinition(ShaderDefinition&&) = default; + ShaderDefinition(ShaderDefinition&&) = default; ShaderDefinition& operator=(ShaderDefinition&&) = default; /* @@ -75,7 +75,8 @@ struct DALI_SCENE3D_API ShaderDefinition Shader Load(RawData&& raw) const; public: // DATA - RendererState::Type mRendererState = RendererState::NONE; + std::shared_ptr mRawData; + RendererState::Type mRendererState = RendererState::NONE; std::string mVertexShaderPath; std::string mFragmentShaderPath; @@ -89,4 +90,4 @@ public: // DATA } // namespace Scene3D } // namespace Dali -#endif //DALI_SCENE3D_LOADER_SHADER_DEFINITION_H +#endif // DALI_SCENE3D_LOADER_SHADER_DEFINITION_H