From d0ecd061af4a237b98a1bc3bdd4f8ffcbc5e9549 Mon Sep 17 00:00:00 2001 From: seungho Date: Mon, 18 Jul 2022 17:13:31 +0900 Subject: [PATCH] Add SceneView Change-Id: I383ae6bca7664c3d7cdb88d4f99fd6b8dc746da9 Signed-off-by: seungho --- automated-tests/src/dali-scene3d/CMakeLists.txt | 1 + .../src/dali-scene3d/utc-Dali-SceneView.cpp | 505 +++++++++++++++++++++ .../controls/model-view/model-view-impl.cpp | 125 +++-- .../internal/controls/model-view/model-view-impl.h | 31 +- .../controls/scene-view/scene-view-impl.cpp | 396 ++++++++++++++++ .../internal/controls/scene-view/scene-view-impl.h | 236 ++++++++++ dali-scene3d/internal/file.list | 1 + .../public-api/controls/model-view/model-view.cpp | 5 + .../public-api/controls/model-view/model-view.h | 12 + .../public-api/controls/scene-view/scene-view.cpp | 122 +++++ .../public-api/controls/scene-view/scene-view.h | 295 ++++++++++++ dali-scene3d/public-api/file.list | 1 + dali-scene3d/public-api/loader/cube-map-loader.cpp | 23 +- dali-scene3d/public-api/loader/cube-map-loader.h | 14 +- 14 files changed, 1705 insertions(+), 62 deletions(-) create mode 100644 automated-tests/src/dali-scene3d/utc-Dali-SceneView.cpp create mode 100644 dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp create mode 100644 dali-scene3d/internal/controls/scene-view/scene-view-impl.h create mode 100644 dali-scene3d/public-api/controls/scene-view/scene-view.cpp create mode 100644 dali-scene3d/public-api/controls/scene-view/scene-view.h diff --git a/automated-tests/src/dali-scene3d/CMakeLists.txt b/automated-tests/src/dali-scene3d/CMakeLists.txt index d86c377..6bc5e40 100755 --- a/automated-tests/src/dali-scene3d/CMakeLists.txt +++ b/automated-tests/src/dali-scene3d/CMakeLists.txt @@ -20,6 +20,7 @@ SET(TC_SOURCES utc-Dali-Gltf2Loader.cpp utc-Dali-KtxLoader.cpp utc-Dali-ModelView.cpp + utc-Dali-SceneView.cpp utc-Dali-MatrixStack.cpp utc-Dali-MeshDefinition.cpp utc-Dali-NodeDefinition.cpp diff --git a/automated-tests/src/dali-scene3d/utc-Dali-SceneView.cpp b/automated-tests/src/dali-scene3d/utc-Dali-SceneView.cpp new file mode 100644 index 0000000..7cabdcd --- /dev/null +++ b/automated-tests/src/dali-scene3d/utc-Dali-SceneView.cpp @@ -0,0 +1,505 @@ +/* + * 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. + * + */ + +#include +#include +#include +#include + +#include +#include + +using namespace Dali; +using namespace Dali::Toolkit; + +void scene_view_startup(void) +{ + test_return_value = TET_UNDEF; +} + +void scene_view_cleanup(void) +{ + test_return_value = TET_PASS; +} + +namespace +{ +/** + * For the AnimatedCube.gltf and its Assets + * Donated by Norbert Nopper for glTF testing. + * Take from https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/AnimatedCube + */ +const char* TEST_GLTF_FILE_NAME = TEST_RESOURCE_DIR "/AnimatedCube.gltf"; + +/** + * For the diffuse and specular cube map texture. + * These textures are based off version of Wave engine sample + * Take from https://github.com/WaveEngine/Samples + * + * Copyright (c) 2022 Wave Coorporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * 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"; + +Dali::Texture GetDiffuseTexture(Dali::Scene3D::ModelView modelView) +{ + Dali::Texture texture; + + Actor meshActor = modelView.FindChildByName("AnimatedCube"); + if(meshActor) + { + Renderer renderer = meshActor.GetRendererAt(0u); + if(renderer) + { + TextureSet textureSet = renderer.GetTextures(); + if(textureSet.GetTextureCount() == 7u) + { + texture = textureSet.GetTexture(5u); + } + } + } + + return texture; +} + +Dali::Texture GetSpecularTexture(Dali::Scene3D::ModelView modelView) +{ + Dali::Texture texture; + + Actor meshActor = modelView.FindChildByName("AnimatedCube"); + if(meshActor) + { + Renderer renderer = meshActor.GetRendererAt(0u); + if(renderer) + { + TextureSet textureSet = renderer.GetTextures(); + if(textureSet.GetTextureCount() == 7u) + { + texture = textureSet.GetTexture(6u); + } + } + } + + return texture; +} +} // namespace + +// Negative test case for a method +int UtcDaliSceneViewUninitialized(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliSceneViewUninitialized"); + + Scene3D::SceneView view; + + try + { + // New() must be called to create a ModelView or it wont be valid. + Actor a = Actor::New(); + view.Add(a); + DALI_TEST_CHECK(false); + } + catch(Dali::DaliException& e) + { + // Tests that a negative test of an assertion succeeds + DALI_TEST_PRINT_ASSERT(e); + DALI_TEST_CHECK(!view); + } + END_TEST; +} + +// Positive test case for a method +int UtcDaliSceneViewNew(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliSceneViewNew"); + + Scene3D::SceneView view = Scene3D::SceneView::New(); + DALI_TEST_CHECK(view); + END_TEST; +} + +// Positive test case for a method +int UtcDaliSceneViewDownCast(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliSceneViewDownCast"); + + Scene3D::SceneView view = Scene3D::SceneView::New(); + BaseHandle handle(view); + + Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(handle); + DALI_TEST_CHECK(view); + DALI_TEST_CHECK(sceneView); + DALI_TEST_CHECK(sceneView == view); + END_TEST; +} + +int UtcDaliSceneViewTypeRegistry(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliSceneViewTypeRegistry"); + + TypeRegistry typeRegistry = TypeRegistry::Get(); + DALI_TEST_CHECK(typeRegistry); + + TypeInfo typeInfo = typeRegistry.GetTypeInfo("SceneView"); + DALI_TEST_CHECK(typeInfo); + + BaseHandle handle = typeInfo.CreateInstance(); + DALI_TEST_CHECK(handle); + + Scene3D::SceneView modelView = Scene3D::SceneView::DownCast(handle); + DALI_TEST_CHECK(modelView); + + END_TEST; +} + +// Positive test case for a method +int UtcDaliSceneViewAddRemove(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliSceneViewAddRemove"); + + Scene3D::SceneView view = Scene3D::SceneView::New(); + DALI_TEST_CHECK(view); + DALI_TEST_EQUALS(1u, view.GetChildCount(), TEST_LOCATION); + + Actor actor = Actor::New(); + + view.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); + view.SetProperty(Actor::Property::SIZE, application.GetScene().GetSize()); + view.Add(actor); + + DALI_TEST_EQUALS(1u, view.GetChildCount(), TEST_LOCATION); + Actor layer = view.GetChildAt(0u); + + DALI_TEST_EQUALS(2u, layer.GetChildCount(), TEST_LOCATION); + DALI_TEST_EQUALS(actor, layer.GetChildAt(1u), TEST_LOCATION); // index 0u is default camera + + view.Remove(actor); + DALI_TEST_EQUALS(1u, layer.GetChildCount(), TEST_LOCATION); + END_TEST; +} + +int UtcDaliSceneViewCopyAndAssignment(void) +{ + ToolkitTestApplication application; + + Scene3D::SceneView view = Scene3D::SceneView::New(); + DALI_TEST_CHECK(view); + + Scene3D::SceneView copy(view); + DALI_TEST_CHECK(view == copy); + + Scene3D::SceneView assign; + DALI_TEST_CHECK(!assign); + + assign = copy; + DALI_TEST_CHECK(assign == view); + + END_TEST; +} + +int UtcDaliSceneViewMoveConstructor(void) +{ + ToolkitTestApplication application; + + Scene3D::SceneView view = Scene3D::SceneView::New(); + DALI_TEST_EQUALS(1, view.GetBaseObject().ReferenceCount(), TEST_LOCATION); + view.SetProperty(Actor::Property::SENSITIVE, false); + DALI_TEST_CHECK(false == view.GetProperty(Actor::Property::SENSITIVE)); + + Scene3D::SceneView moved = std::move(view); + DALI_TEST_CHECK(moved); + DALI_TEST_EQUALS(1, moved.GetBaseObject().ReferenceCount(), TEST_LOCATION); + DALI_TEST_CHECK(false == moved.GetProperty(Actor::Property::SENSITIVE)); + DALI_TEST_CHECK(!view); + + END_TEST; +} + +int UtcDaliSceneViewMoveAssignment(void) +{ + ToolkitTestApplication application; + + Scene3D::SceneView view = Scene3D::SceneView::New(); + DALI_TEST_EQUALS(1, view.GetBaseObject().ReferenceCount(), TEST_LOCATION); + view.SetProperty(Actor::Property::SENSITIVE, false); + DALI_TEST_CHECK(false == view.GetProperty(Actor::Property::SENSITIVE)); + + Scene3D::SceneView moved; + moved = std::move(view); + DALI_TEST_CHECK(moved); + DALI_TEST_EQUALS(1, moved.GetBaseObject().ReferenceCount(), TEST_LOCATION); + DALI_TEST_CHECK(false == moved.GetProperty(Actor::Property::SENSITIVE)); + DALI_TEST_CHECK(!view); + + END_TEST; +} + +int UtcDaliSceneViewOnScene01(void) +{ + ToolkitTestApplication application; + + Scene3D::SceneView view = Scene3D::SceneView::New(); + + DALI_TEST_EQUALS(1u, view.GetChildCount(), TEST_LOCATION); + Actor layer = view.GetChildAt(0u); + + DALI_TEST_EQUALS(1u, layer.GetChildCount(), TEST_LOCATION); + + application.GetScene().Add(view); + + application.SendNotification(); + application.Render(); + + // CameraActor is added on layer when on scene + DALI_TEST_EQUALS(1u, layer.GetChildCount(), TEST_LOCATION); + + END_TEST; +} + +int UtcDaliSceneViewOnScene02(void) +{ + ToolkitTestApplication application; + + uint32_t renderTaskCount = application.GetScene().GetRenderTaskList().GetTaskCount(); + DALI_TEST_EQUALS(1u, renderTaskCount, TEST_LOCATION); + + Scene3D::SceneView view = Scene3D::SceneView::New(); + + renderTaskCount = application.GetScene().GetRenderTaskList().GetTaskCount(); + DALI_TEST_EQUALS(2u, renderTaskCount, TEST_LOCATION); + + RenderTask renderTask = application.GetScene().GetRenderTaskList().GetTask(1u); + CameraActor camera = renderTask.GetCameraActor(); + + application.GetScene().Add(view); + + application.SendNotification(); + application.Render(); + + CameraActor defaultCamera = renderTask.GetCameraActor(); + DALI_TEST_CHECK(defaultCamera); + DALI_TEST_EQUALS(camera, defaultCamera, TEST_LOCATION); + DALI_TEST_EQUALS(defaultCamera, view.GetSelectedCamera(), TEST_LOCATION); + + END_TEST; +} + +int UtcDaliSceneViewUserCamera(void) +{ + ToolkitTestApplication application; + + Scene3D::SceneView view = Scene3D::SceneView::New(); + view.SetProperty(Dali::Actor::Property::SIZE, Vector2(100, 100)); + + application.GetScene().Add(view); + + application.SendNotification(); + application.Render(); + + CameraActor defaultCamera = view.GetSelectedCamera(); + CameraActor camera = Dali::CameraActor::New(); + camera.SetProperty(Dali::Actor::Property::NAME, "camera"); + view.AddCamera(camera); + view.SelectCamera("camera"); + + DALI_TEST_NOT_EQUALS(defaultCamera, view.GetSelectedCamera(), 0.0f, TEST_LOCATION); + DALI_TEST_EQUALS(camera, view.GetSelectedCamera(), TEST_LOCATION); + + camera.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); + camera.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER); + camera.SetFieldOfView(0.5f); + camera.SetNearClippingPlane(1.0f); + camera.SetFarClippingPlane(5000.0f); + camera.SetProperty(Dali::Actor::Property::POSITION, Vector3(20, 30, 40)); + + float fov = camera[Dali::CameraActor::Property::FIELD_OF_VIEW]; + float nearPlain = camera[Dali::CameraActor::Property::NEAR_PLANE_DISTANCE]; + float farPlain = camera[Dali::CameraActor::Property::FAR_PLANE_DISTANCE]; + Vector3 cameraPosition = camera[Dali::Actor::Property::POSITION]; + + view.SetProperty(Dali::Actor::Property::SIZE, Vector2(400, 300)); + + DALI_TEST_EQUALS(fov, camera.GetProperty(Dali::CameraActor::Property::FIELD_OF_VIEW), TEST_LOCATION); + DALI_TEST_EQUALS(nearPlain, camera.GetProperty(Dali::CameraActor::Property::NEAR_PLANE_DISTANCE), TEST_LOCATION); + DALI_TEST_EQUALS(farPlain, camera.GetProperty(Dali::CameraActor::Property::FAR_PLANE_DISTANCE), TEST_LOCATION); + DALI_TEST_EQUALS(cameraPosition, camera.GetProperty(Dali::Actor::Property::POSITION), TEST_LOCATION); + + END_TEST; +} + +int UtcDaliSceneViewAddRemoveCamera(void) +{ + ToolkitTestApplication application; + + Scene3D::SceneView view = Scene3D::SceneView::New(); + view.SetProperty(Dali::Actor::Property::SIZE, Vector2(100, 100)); + + application.GetScene().Add(view); + + application.SendNotification(); + application.Render(); + + CameraActor camera0 = view.GetSelectedCamera(); + camera0.SetProperty(Dali::Actor::Property::NAME, "camera0"); + CameraActor camera1 = Dali::CameraActor::New(); + camera1.SetProperty(Dali::Actor::Property::NAME, "camera1"); + + DALI_TEST_EQUALS(1u, view.GetCameraCount(), TEST_LOCATION); + view.AddCamera(camera1); + DALI_TEST_EQUALS(2u, view.GetCameraCount(), TEST_LOCATION); + + DALI_TEST_EQUALS(camera0, view.GetCamera(0), TEST_LOCATION); + DALI_TEST_EQUALS(camera0, view.GetCamera("camera0"), TEST_LOCATION); + DALI_TEST_EQUALS(camera1, view.GetCamera(1), TEST_LOCATION); + DALI_TEST_EQUALS(camera1, view.GetCamera("camera1"), TEST_LOCATION); + + DALI_TEST_EQUALS(camera0, view.GetSelectedCamera(), TEST_LOCATION); + view.SelectCamera(1); // 0 -> 1 + DALI_TEST_EQUALS(camera1, view.GetSelectedCamera(), TEST_LOCATION); + view.SelectCamera("camera0"); // 1 -> 0 + DALI_TEST_EQUALS(camera0, view.GetSelectedCamera(), TEST_LOCATION); + view.SelectCamera("camera1"); // 0 -> 1 + DALI_TEST_EQUALS(camera1, view.GetSelectedCamera(), TEST_LOCATION); + view.SelectCamera(0); // 1 -> 0 + DALI_TEST_EQUALS(camera0, view.GetSelectedCamera(), TEST_LOCATION); + + view.SelectCamera(1); // 0 -> 1 + DALI_TEST_EQUALS(camera1, view.GetSelectedCamera(), TEST_LOCATION); + DALI_TEST_EQUALS(2u, view.GetCameraCount(), TEST_LOCATION); + view.RemoveCamera(camera1); // 1 -> 0 + DALI_TEST_EQUALS(camera0, view.GetSelectedCamera(), TEST_LOCATION); + DALI_TEST_EQUALS(1u, view.GetCameraCount(), TEST_LOCATION); + + CameraActor defaultCamera = view.GetSelectedCamera(); + DALI_TEST_CHECK(defaultCamera); + DALI_TEST_EQUALS(camera0, defaultCamera, TEST_LOCATION); + DALI_TEST_NOT_EQUALS(camera1, defaultCamera, 0.0f, TEST_LOCATION); + END_TEST; +} + +int UtcDaliSceneViewImageBasedLight(void) +{ + ToolkitTestApplication application; + + Scene3D::SceneView view = Scene3D::SceneView::New(); + view.SetProperty(Dali::Actor::Property::SIZE, Vector2(100, 100)); + + application.GetScene().Add(view); + + application.SendNotification(); + application.Render(); + + Scene3D::ModelView modelView1 = Scene3D::ModelView::New(TEST_GLTF_FILE_NAME); + Scene3D::ModelView modelView2 = Scene3D::ModelView::New(TEST_GLTF_FILE_NAME); + Scene3D::ModelView modelView3 = Scene3D::ModelView::New(TEST_GLTF_FILE_NAME); + view.Add(modelView1); + view.Add(modelView2); + + 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); + + view.SetImageBasedLightSource(TEST_DIFFUSE_TEXTURE, TEST_SPECULAR_TEXTURE); + + 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); + + 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); + + 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); + DALI_TEST_EQUALS(GetDiffuseTexture(modelView2), GetDiffuseTexture(modelView3), TEST_LOCATION); + DALI_TEST_EQUALS(GetSpecularTexture(modelView2), GetSpecularTexture(modelView3), TEST_LOCATION); + + END_TEST; +} + +int UtcDaliSceneViewUseFramebuffer01(void) +{ + ToolkitTestApplication application; + + Scene3D::SceneView view = Scene3D::SceneView::New(); + view.SetProperty(Dali::Actor::Property::SIZE, Vector2(100, 100)); + + application.GetScene().Add(view); + + application.SendNotification(); + application.Render(); + + bool useFramebuffer = view.IsUsingFramebuffer(); + view.UseFramebuffer(true); + DALI_TEST_NOT_EQUALS(useFramebuffer, view.IsUsingFramebuffer(), 0.0f, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliSceneViewUseFramebuffer02(void) +{ + ToolkitTestApplication application; + + Scene3D::SceneView view = Scene3D::SceneView::New(); + view.SetProperty(Dali::Actor::Property::SIZE, Vector2(100, 100)); + + application.GetScene().Add(view); + + application.SendNotification(); + application.Render(); + + RenderTask renderTask = application.GetScene().GetRenderTaskList().GetTask(1u); + DALI_TEST_CHECK(!renderTask.GetFrameBuffer()); + + view.UseFramebuffer(true); + DALI_TEST_CHECK(renderTask.GetFrameBuffer()); + + view.UseFramebuffer(false); + DALI_TEST_CHECK(!renderTask.GetFrameBuffer()); + + END_TEST; +} diff --git a/dali-scene3d/internal/controls/model-view/model-view-impl.cpp b/dali-scene3d/internal/controls/model-view/model-view-impl.cpp index 568b899..35029f3 100644 --- a/dali-scene3d/internal/controls/model-view/model-view-impl.cpp +++ b/dali-scene3d/internal/controls/model-view/model-view-impl.cpp @@ -30,9 +30,9 @@ // INTERNAL INCLUDES #include +#include #include #include -#include #include #include #include @@ -113,22 +113,6 @@ struct BoundingVolume Vector3 pointMax; }; -Texture LoadCubeMap(const std::string& cubeMapPath) -{ - Texture cubeTexture; - Dali::Scene3D::Loader::CubeData cubeData; - if(Dali::Scene3D::Loader::LoadCubeMapData(cubeMapPath, cubeData)) - { - cubeTexture = cubeData.CreateTexture(); - } - else - { - DALI_LOG_ERROR("Fail to load cube map, %s\n", cubeMapPath.c_str()); - } - - return cubeTexture; -} - void ConfigureBlendShapeShaders( Dali::Scene3D::Loader::ResourceBundle& resources, const Dali::Scene3D::Loader::SceneDefinition& scene, Actor root, std::vector&& requests) { @@ -238,18 +222,20 @@ void ModelView::FitCenter(bool fit) void ModelView::SetImageBasedLightSource(const std::string& diffuse, const std::string& specular, float scaleFactor) { - Texture diffuseTexture = LoadCubeMap(diffuse); - if(diffuseTexture) + Texture diffuseTexture = Dali::Scene3D::Loader::LoadCubeMap(diffuse); + Texture specularTexture = Dali::Scene3D::Loader::LoadCubeMap(specular); + SetImageBasedLightTexture(diffuseTexture, specularTexture, scaleFactor); +} + +void ModelView::SetImageBasedLightTexture(Dali::Texture diffuse, Dali::Texture specular, float scaleFactor) +{ + if(diffuse && specular) { - Texture specularTexture = LoadCubeMap(specular); - if(specularTexture) - { - mDiffuseTexture = diffuseTexture; - mSpecularTexture = specularTexture; - mIblScaleFactor = scaleFactor; + mDiffuseTexture = diffuse; + mSpecularTexture = specular; + mIblScaleFactor = scaleFactor; - SetImageBasedLight(mModelRoot); - } + UpdateImageBasedLight(); } } @@ -297,9 +283,33 @@ void ModelView::OnSceneConnection(int depth) LoadModel(); } + Actor parent = Self().GetParent(); + while(parent) + { + Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(parent); + if(sceneView) + { + GetImpl(sceneView).RegisterModelView(Scene3D::ModelView::DownCast(Self())); + mParentSceneView = sceneView; + break; + } + parent = parent.GetParent(); + } + Control::OnSceneConnection(depth); } +void ModelView::OnSceneDisconnection() +{ + Scene3D::SceneView sceneView = mParentSceneView.GetHandle(); + if(sceneView) + { + GetImpl(sceneView).UnregisterModelView(Scene3D::ModelView::DownCast(Self())); + mParentSceneView.Reset(); + } + Control::OnSceneDisconnection(); +} + void ModelView::OnInitialize() { Actor self = Self(); @@ -452,7 +462,9 @@ void ModelView::LoadModel() } } - SetImageBasedLight(mModelRoot); + mRenderableActors.clear(); + CollectRenderableActor(mModelRoot); + UpdateImageBasedLight(); mNaturalSize = AABB.CalculateSize(); mModelPivot = AABB.CalculatePivot(); @@ -508,43 +520,56 @@ void ModelView::FitModelPosition() } } -void ModelView::SetImageBasedLight(Actor node) +void ModelView::CollectRenderableActor(Actor actor) { - if(!mDiffuseTexture || !mSpecularTexture || !node) + uint32_t rendererCount = actor.GetRendererCount(); + if(rendererCount) { - return; + mRenderableActors.push_back(actor); } - uint32_t rendererCount = node.GetRendererCount(); - if(rendererCount) + uint32_t childrenCount = actor.GetChildCount(); + for(uint32_t i = 0; i < childrenCount; ++i) { - node.RegisterProperty(Dali::Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName().data(), mIblScaleFactor); + CollectRenderableActor(actor.GetChildAt(i)); } +} - for(uint32_t i = 0; i < rendererCount; ++i) +void ModelView::UpdateImageBasedLight() +{ + if(!mDiffuseTexture || !mSpecularTexture) { - Dali::Renderer renderer = node.GetRendererAt(i); - if(renderer) + return; + } + + for(auto&& actor : mRenderableActors) + { + Actor renderableActor = actor.GetHandle(); + if(renderableActor) { - Dali::TextureSet textures = renderer.GetTextures(); - if(textures) + renderableActor.RegisterProperty(Dali::Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName().data(), mIblScaleFactor); + + uint32_t rendererCount = renderableActor.GetRendererCount(); + for(uint32_t i = 0; i < rendererCount; ++i) { - uint32_t textureCount = textures.GetTextureCount(); - // EnvMap requires at least 2 texture, diffuse and specular - if(textureCount > 2u) + Dali::Renderer renderer = renderableActor.GetRendererAt(i); + if(renderer) { - textures.SetTexture(textureCount - OFFSET_FOR_DIFFUSE_CUBE_TEXTURE, mDiffuseTexture); - textures.SetTexture(textureCount - OFFSET_FOR_SPECULAR_CUBE_TEXTURE, mSpecularTexture); + 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, mDiffuseTexture); + textures.SetTexture(textureCount - OFFSET_FOR_SPECULAR_CUBE_TEXTURE, mSpecularTexture); + } + } } } } } - - uint32_t childrenCount = node.GetChildCount(); - for(uint32_t i = 0; i < childrenCount; ++i) - { - SetImageBasedLight(node.GetChildAt(i)); - } } } // namespace Internal diff --git a/dali-scene3d/internal/controls/model-view/model-view-impl.h b/dali-scene3d/internal/controls/model-view/model-view-impl.h index 14b31f9..e17dde3 100644 --- a/dali-scene3d/internal/controls/model-view/model-view-impl.h +++ b/dali-scene3d/internal/controls/model-view/model-view-impl.h @@ -23,9 +23,11 @@ #include #include #include +#include // INTERNAL INCLUDES #include +#include namespace Dali { @@ -71,6 +73,11 @@ public: void SetImageBasedLightSource(const std::string& diffuse, const std::string& specular, float scaleFactor); /** + * @copydoc ModelView::SetImageBasedLightTexture() + */ + void SetImageBasedLightTexture(Dali::Texture diffuse, Dali::Texture specular, float scaleFactor); + + /** * @copydoc ModelView::GetAnimationCount() */ uint32_t GetAnimationCount(); @@ -103,6 +110,11 @@ private: void OnSceneConnection(int depth) override; /** + * @copydoc CustomActorImpl::OnSceneDisconnection() + */ + void OnSceneDisconnection() override; + + /** * @copydoc Toolkit::Control::OnInitialize() */ void OnInitialize() override; @@ -145,14 +157,21 @@ private: /** * @brief Changes IBL information of the input node. */ - void SetImageBasedLight(Actor node); + void CollectRenderableActor(Actor actor); + + /** + * @brief Changes IBL information of the input node. + */ + void UpdateImageBasedLight(); private: - std::string mModelPath; - std::string mResourcePath; - Dali::Layer mModelLayer; - Dali::Actor mModelRoot; - std::vector mAnimations; + std::string mModelPath; + std::string mResourcePath; + Dali::Layer mModelLayer; + Dali::Actor mModelRoot; + std::vector mAnimations; + std::vector> mRenderableActors; + WeakHandle mParentSceneView; Dali::Texture mSpecularTexture; Dali::Texture mDiffuseTexture; diff --git a/dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp b/dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp new file mode 100644 index 0000000..c43334e --- /dev/null +++ b/dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp @@ -0,0 +1,396 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include + +#include + +using namespace Dali; + +namespace Dali +{ +namespace Scene3D +{ +namespace Internal +{ +namespace +{ +BaseHandle Create() +{ + return Scene3D::SceneView::New(); +} + +// Setup properties, signals and actions using the type-registry. +DALI_TYPE_REGISTRATION_BEGIN(Scene3D::SceneView, Toolkit::Control, Create); +DALI_TYPE_REGISTRATION_END() + +Property::Index RENDERING_BUFFER = Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX + 1; + +} // anonymous namespace + +SceneView::SceneView() +: Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)) +{ +} + +SceneView::~SceneView() = default; + +Dali::Scene3D::SceneView SceneView::New() +{ + SceneView* impl = new SceneView(); + + Dali::Scene3D::SceneView handle = Dali::Scene3D::SceneView(*impl); + + // Second-phase init of the implementation + // This can only be done after the CustomActor connection has been made... + impl->Initialize(); + + return handle; +} + +void SceneView::AddCamera(CameraActor camera) +{ + if(camera) + { + if(mCameras.empty()) + { + UpdateCamera(camera); + } + mCameras.push_back(camera); + } +} + +void SceneView::RemoveCamera(CameraActor camera) +{ + if(camera == mDefaultCamera) + { + DALI_LOG_ERROR("Default Camera cannot removed.\n"); + return; + } + + if(camera) + { + for(uint32_t i = 0; i < mCameras.size(); ++i) + { + if(mCameras[i] == camera) + { + mCameras.erase(mCameras.begin() + i); + break; + } + } + + if(mSelectedCamera == camera) + { + CameraActor newCurrentCamera = *mCameras.begin(); + UpdateCamera(newCurrentCamera); + } + } +} + +uint32_t SceneView::GetCameraCount() +{ + return mCameras.size(); +} + +CameraActor SceneView::GetSelectedCamera() +{ + return mSelectedCamera; +} + +CameraActor SceneView::GetCamera(uint32_t index) +{ + if(index < mCameras.size()) + { + return mCameras[index]; + } + DALI_LOG_ERROR("Input index is out of bounds\n"); + return CameraActor(); +} + +CameraActor SceneView::GetCamera(const std::string& name) +{ + CameraActor returnCamera; + for(auto&& camera : mCameras) + { + if(camera.GetProperty(Actor::Property::NAME) == name) + { + returnCamera = camera; + break; + } + } + return returnCamera; +} + +void SceneView::SelectCamera(uint32_t index) +{ + UpdateCamera(GetCamera(index)); +} + +void SceneView::SelectCamera(const std::string& name) +{ + UpdateCamera(GetCamera(name)); +} + +void SceneView::RegisterModelView(Scene3D::ModelView modelView) +{ + if(modelView) + { + modelView.SetImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor); + mModels.push_back(modelView); + } +} + +void SceneView::UnregisterModelView(Scene3D::ModelView modelView) +{ + if(modelView) + { + for(uint32_t i = 0; i < mModels.size(); ++i) + { + if(mModels[i] == modelView) + { + mModels.erase(mModels.begin() + i); + break; + } + } + } +} + +void SceneView::SetImageBasedLightSource(const std::string& diffuse, const std::string& specular, float scaleFactor) +{ + Texture diffuseTexture = Dali::Scene3D::Loader::LoadCubeMap(diffuse); + if(diffuseTexture) + { + Texture specularTexture = Dali::Scene3D::Loader::LoadCubeMap(specular); + if(specularTexture) + { + mDiffuseTexture = diffuseTexture; + mSpecularTexture = specularTexture; + mIblScaleFactor = scaleFactor; + + for(auto&& model : mModels) + { + if(model) + { + model.SetImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor); + } + } + } + } +} + +void SceneView::UseFramebuffer(bool useFramebuffer) +{ + if(mUseFrameBuffer != useFramebuffer) + { + mUseFrameBuffer = useFramebuffer; + UpdateRenderTask(); + } +} + +bool SceneView::IsUsingFramebuffer() +{ + return mUseFrameBuffer; +} + +/////////////////////////////////////////////////////////// +// +// Private methods +// + +void SceneView::OnSceneConnection(int depth) +{ + UpdateRenderTask(); + + Control::OnSceneConnection(depth); +} + +void SceneView::OnSceneDisconnection() +{ + mModels.clear(); + Control::OnSceneDisconnection(); +} + +void SceneView::OnInitialize() +{ + Actor self = Self(); + mRootLayer = Layer::New(); + mRootLayer.SetProperty(Layer::Property::BEHAVIOR, Layer::LAYER_3D); + mRootLayer.SetProperty(Layer::Property::DEPTH_TEST, true); + // The models in the SceneView should be have independent coordinate with DALi default coordinate. + mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_POSITION, false); + mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_ORIENTATION, false); + mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_SCALE, false); + self.Add(mRootLayer); + + RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList(); + mRenderTask = taskList.CreateTask(); + mRenderTask.SetSourceActor(mRootLayer); + mRenderTask.SetExclusive(true); + mRenderTask.SetInputEnabled(true); + mRenderTask.SetScreenToFrameBufferMappingActor(Self()); + + mDefaultCamera = Dali::CameraActor::New(); + mDefaultCamera.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); + mDefaultCamera.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER); + mDefaultCamera.SetNearClippingPlane(1.0f); + AddCamera(mDefaultCamera); + UpdateCamera(mDefaultCamera); +} + +void SceneView::OnChildAdd(Actor& child) +{ + if(child != mRootLayer) + { + mRootLayer.Add(child); + } + Control::OnChildAdd(child); +} + +void SceneView::OnChildRemove(Actor& child) +{ + mRootLayer.Remove(child); + Control::OnChildRemove(child); +} + +float SceneView::GetHeightForWidth(float width) +{ + Extents padding; + padding = Self().GetProperty(Toolkit::Control::Property::PADDING); + return Control::GetHeightForWidth(width) + padding.top + padding.bottom; +} + +float SceneView::GetWidthForHeight(float height) +{ + Extents padding; + padding = Self().GetProperty(Toolkit::Control::Property::PADDING); + return Control::GetWidthForHeight(height) + padding.start + padding.end; +} + +void SceneView::OnRelayout(const Vector2& size, RelayoutContainer& container) +{ + Control::OnRelayout(size, container); + // Change canvas size of camera actor. + UpdateRenderTask(); +} + +void SceneView::UpdateCamera(CameraActor camera) +{ + if(camera) + { + if(mSelectedCamera && mSelectedCamera.GetParent()) + { + mSelectedCamera.Unparent(); + } + mRootLayer.Add(camera); + } + + mSelectedCamera = camera; + UpdateRenderTask(); +} + +void SceneView::UpdateRenderTask() +{ + if(mRenderTask) + { + if(mSelectedCamera != mRenderTask.GetCameraActor()) + { + mRenderTask.SetCameraActor(mSelectedCamera); + } + + Vector3 size = Self().GetProperty(Dali::Actor::Property::SIZE); + float fov = 0.0f; + Vector3 cameraPosition(Vector3::ZERO); + float nearPlain = 1.0f; + float farPlain = 1.0f; + + // Several properties such as fov, nearPlane, farPlane, and position should not be changed after SetPerspectiveProjection is called. + // In the 3D scene, the properties are not changed by the changes of canvas size. + fov = mSelectedCamera[Dali::CameraActor::Property::FIELD_OF_VIEW]; + nearPlain = mSelectedCamera[Dali::CameraActor::Property::NEAR_PLANE_DISTANCE]; + farPlain = mSelectedCamera[Dali::CameraActor::Property::FAR_PLANE_DISTANCE]; + cameraPosition = Vector3(mSelectedCamera[Dali::Actor::Property::POSITION]); + + mSelectedCamera.SetPerspectiveProjection(Dali::Size(size)); + + mSelectedCamera[Dali::CameraActor::Property::FIELD_OF_VIEW] = fov; + mSelectedCamera[Dali::CameraActor::Property::NEAR_PLANE_DISTANCE] = nearPlain; + mSelectedCamera[Dali::CameraActor::Property::FAR_PLANE_DISTANCE] = farPlain; + mSelectedCamera[Dali::Actor::Property::POSITION] = cameraPosition; + + if(mUseFrameBuffer) + { + Dali::FrameBuffer currentFrameBuffer = mRenderTask.GetFrameBuffer(); + if(!currentFrameBuffer || + currentFrameBuffer.GetColorTexture().GetWidth() != size.width || + currentFrameBuffer.GetColorTexture().GetHeight() != size.height) + { + mRenderTask.ResetViewportGuideActor(); + mRenderTask.SetViewport(Dali::Viewport(Vector4::ZERO)); + + // create offscreen buffer of new size to render our child actors to + mTexture = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, unsigned(size.width), unsigned(size.height)); + mRenderTarget = FrameBuffer::New(size.width, size.height, FrameBuffer::Attachment::DEPTH); + mRenderTarget.AttachColorTexture(mTexture); + Dali::Toolkit::ImageUrl imageUrl = Dali::Toolkit::Image::GenerateUrl(mRenderTarget, 0u); + + Property::Map imagePropertyMap; + imagePropertyMap.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE); + imagePropertyMap.Insert(Toolkit::ImageVisual::Property::URL, imageUrl.GetUrl()); + // To flip rendered scene without CameraActor::SetInvertYAxis() to avoid backface culling. + imagePropertyMap.Insert(Toolkit::ImageVisual::Property::PIXEL_AREA, Vector4(0.0f, 1.0f, 1.0f, -1.0f)); + mVisual = Toolkit::VisualFactory::Get().CreateVisual(imagePropertyMap); + + Toolkit::DevelControl::RegisterVisual(*this, RENDERING_BUFFER, mVisual); + + mRenderTask.SetFrameBuffer(mRenderTarget); + mRenderTask.SetClearEnabled(true); + mRenderTask.SetClearColor(Color::TRANSPARENT); + } + } + else + { + mRenderTask.SetViewportGuideActor(Self()); + if(mRenderTask.GetFrameBuffer()) + { + FrameBuffer framebuffer; + mRenderTask.SetFrameBuffer(framebuffer); + mRenderTask.SetClearEnabled(false); + } + } + } +} + +} // 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 new file mode 100644 index 0000000..724bc7d --- /dev/null +++ b/dali-scene3d/internal/controls/scene-view/scene-view-impl.h @@ -0,0 +1,236 @@ +#ifndef DALI_SCENE3D_INTERNAL_SCENE_VIEW_H +#define DALI_SCENE3D_INTERNAL_SCENE_VIEW_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 +#include +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include + +namespace Dali +{ +namespace Scene3D +{ +class SceneView; + +namespace Internal +{ +/** + * @brief Impl class for SceneView. + */ +class SceneView : public Dali::Toolkit::Internal::Control +{ +public: + /** + * @brief Creates a new SceneView. + * + * @return A public handle to the newly allocated SceneView. + */ + static Dali::Scene3D::SceneView New(); + + /** + * @copydoc SceneView::AddCamera() + */ + void AddCamera(Dali::CameraActor camera); + + /** + * @copydoc SceneView::RemoveCamera() + */ + void RemoveCamera(CameraActor camera); + + /** + * @copydoc SceneView::GetCameraCount() + */ + uint32_t GetCameraCount(); + + /** + * @copydoc SceneView::GetSelectedCamera() + */ + CameraActor GetSelectedCamera(); + + /** + * @copydoc SceneView::GetCamera() + */ + CameraActor GetCamera(uint32_t index); + + /** + * @copydoc SceneView::GetCamera() + */ + CameraActor GetCamera(const std::string& name); + + /** + * @copydoc SceneView::SelectCamera() + */ + void SelectCamera(uint32_t index); + + /** + * @copydoc SceneView::SelectCamera() + */ + void SelectCamera(const std::string& name); + + /** + * @brief Register a ModelView. + * Some works like ibl setting should be applied on the only ModelView not the all child actors. + * SceneView contains child ModelView list to apply the works effectively. + * + * @param[in] modelView ModelView to be registered. + */ + void RegisterModelView(Scene3D::ModelView modelView); + + /** + * @brief Unregister a ModelView + * + * @param[in] modelView ModelView to be unregistered. + */ + void UnregisterModelView(Scene3D::ModelView modelView); + + /** + * @copydoc SceneView::SetImageBasedLightSource() + */ + void SetImageBasedLightSource(const std::string& diffuse, const std::string& specular, float scaleFactor); + + /** + * @copydoc SceneView::UseFramebuffer() + */ + void UseFramebuffer(bool useFramebuffer); + + /** + * @copydoc SceneView::IsUsingFramebuffer() + */ + bool IsUsingFramebuffer(); + +protected: + /** + * @brief Constructs a new SceneView. + */ + SceneView(); + + /** + * A reference counted object may only be deleted by calling Unreference() + */ + virtual ~SceneView(); + +private: + /** + * @copydoc CustomActorImpl::OnSceneConnection() + */ + void OnSceneConnection(int depth) override; + + /** + * @copydoc CustomActorImpl::OnSceneDisconnection() + */ + void OnSceneDisconnection() override; + + /** + * @copydoc Toolkit::Control::OnInitialize() + */ + void OnInitialize() override; + + /** + * @copydoc Toolkit::Control::OnChildAdd() + */ + void OnChildAdd(Actor& child) override; + + /** + * @copydoc Toolkit::Control::OnChildRemove() + */ + void OnChildRemove(Actor& child) override; + + /** + * @copydoc Toolkit::Control::GetHeightForWidth() + */ + float GetHeightForWidth(float width) override; + + /** + * @copydoc Toolkit::Control::GetWidthForHeight() + */ + float GetWidthForHeight(float height) override; + + /** + * @copydoc Toolkit::Control::OnRelayout() + */ + void OnRelayout(const Vector2& size, RelayoutContainer& container) override; + + /** + * @brief Changes main camera as a input camera + * + * @param camera CameraActor that will be a main camera of the SceneView + */ + void UpdateCamera(CameraActor camera); + + /** + * @brief Updates RenderTask to use selected camera and to make framebuffer + */ + void UpdateRenderTask(); + +private: + Toolkit::Visual::Base mVisual; + + ///////////////////////////////////////////////////////////// + // FrameBuffer and Rendertask to render child objects as a 3D Scene + CameraActor mDefaultCamera; + CameraActor mSelectedCamera; + std::vector mCameras; + std::vector mModels; + Dali::FrameBuffer mRenderTarget; + Dali::Texture mTexture; + Dali::RenderTask mRenderTask; + + Layer mRootLayer; + + Dali::Texture mSpecularTexture; + Dali::Texture mDiffuseTexture; + float mIblScaleFactor{1.0f}; + bool mUseFrameBuffer{false}; + + // TODO : Light Source +}; + +} // namespace Internal + +// Helpers for public-api forwarding methods +inline Dali::Scene3D::Internal::SceneView& GetImpl(Dali::Scene3D::SceneView& obj) +{ + DALI_ASSERT_ALWAYS(obj); + Dali::RefObject& handle = obj.GetImplementation(); + return static_cast(handle); +} + +inline const Dali::Scene3D::Internal::SceneView& GetImpl(const Dali::Scene3D::SceneView& obj) +{ + DALI_ASSERT_ALWAYS(obj); + const Dali::RefObject& handle = obj.GetImplementation(); + return static_cast(handle); +} + +} // namespace Scene3D + +} // namespace Dali + +#endif // DALI_SCENE3D_INTERNAL_SCENE_VIEW_H diff --git a/dali-scene3d/internal/file.list b/dali-scene3d/internal/file.list index b236f3c..f1bcfd8 100644 --- a/dali-scene3d/internal/file.list +++ b/dali-scene3d/internal/file.list @@ -6,4 +6,5 @@ set(scene3d_src_files ${scene3d_src_files} ${scene3d_internal_dir}/loader/json-reader.cpp ${scene3d_internal_dir}/loader/json-util.cpp ${scene3d_internal_dir}/controls/model-view/model-view-impl.cpp + ${scene3d_internal_dir}/controls/scene-view/scene-view-impl.cpp ) diff --git a/dali-scene3d/public-api/controls/model-view/model-view.cpp b/dali-scene3d/public-api/controls/model-view/model-view.cpp index b21726e..a799377 100644 --- a/dali-scene3d/public-api/controls/model-view/model-view.cpp +++ b/dali-scene3d/public-api/controls/model-view/model-view.cpp @@ -82,6 +82,11 @@ void ModelView::SetImageBasedLightSource(const std::string& diffuse, const std:: GetImpl(*this).SetImageBasedLightSource(diffuse, specular, scaleFactor); } +void ModelView::SetImageBasedLightTexture(Texture diffuse, Texture specular, float scaleFactor) +{ + GetImpl(*this).SetImageBasedLightTexture(diffuse, specular, scaleFactor); +} + uint32_t ModelView::GetAnimationCount() { return GetImpl(*this).GetAnimationCount(); diff --git a/dali-scene3d/public-api/controls/model-view/model-view.h b/dali-scene3d/public-api/controls/model-view/model-view.h index 4c27f1a..ce5e249 100644 --- a/dali-scene3d/public-api/controls/model-view/model-view.h +++ b/dali-scene3d/public-api/controls/model-view/model-view.h @@ -23,6 +23,7 @@ // EXTERNAL INCLUDES #include +#include #include namespace Dali @@ -164,6 +165,17 @@ public: void SetImageBasedLightSource(const std::string& diffuse, const std::string& specular, float scaleFactor = 1.0f); /** + * @brief Set Image Based Light Texture. + * + * @param[in] diffuse cube map texture that can be used as a diffuse IBL source. + * @param[in] specular cube map texture that can be used as a specular IBL source. + * @param[in] scaleFactor scale factor that controls light source intensity in [0.0f, 1.0f]. Default value is 1.0f. + * + * @note Both of diffuse and specular should be available. If not, nothing applied. + */ + void SetImageBasedLightTexture(Texture diffuse, Texture specular, float scaleFactor = 1.0f); + + /** * @brief Gets number of animations those loaded from model file. * @return The number of loaded animations. * @note This method should be called after Model load finished. diff --git a/dali-scene3d/public-api/controls/scene-view/scene-view.cpp b/dali-scene3d/public-api/controls/scene-view/scene-view.cpp new file mode 100644 index 0000000..cb07590 --- /dev/null +++ b/dali-scene3d/public-api/controls/scene-view/scene-view.cpp @@ -0,0 +1,122 @@ +/* + * 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 +{ +SceneView::SceneView() +{ +} + +SceneView::SceneView(const SceneView& sceneView) = default; + +SceneView::SceneView(SceneView&& rhs) = default; + +SceneView& SceneView::operator=(const SceneView& sceneView) = default; + +SceneView& SceneView::operator=(SceneView&& rhs) = default; + +SceneView::~SceneView() +{ +} + +SceneView SceneView::New() +{ + return Internal::SceneView::New(); +} + +SceneView SceneView::DownCast(BaseHandle handle) +{ + return Control::DownCast(handle); +} + +SceneView::SceneView(Internal::SceneView& implementation) +: Control(implementation) +{ +} + +SceneView::SceneView(Dali::Internal::CustomActor* internal) +: Control(internal) +{ + VerifyCustomActorPointer(internal); +} + +void SceneView::AddCamera(Dali::CameraActor camera) +{ + GetImpl(*this).AddCamera(camera); +} + +void SceneView::RemoveCamera(CameraActor camera) +{ + GetImpl(*this).RemoveCamera(camera); +} + +uint32_t SceneView::GetCameraCount() +{ + return GetImpl(*this).GetCameraCount(); +} + +CameraActor SceneView::GetSelectedCamera() +{ + return GetImpl(*this).GetSelectedCamera(); +} + +CameraActor SceneView::GetCamera(uint32_t index) +{ + return GetImpl(*this).GetCamera(index); +} + +CameraActor SceneView::GetCamera(const std::string& name) +{ + return GetImpl(*this).GetCamera(name); +} + +void SceneView::SelectCamera(uint32_t index) +{ + GetImpl(*this).SelectCamera(index); +} + +void SceneView::SelectCamera(const std::string& name) +{ + GetImpl(*this).SelectCamera(name); +} + +void SceneView::SetImageBasedLightSource(const std::string& diffuse, const std::string& specular, float scaleFactor) +{ + GetImpl(*this).SetImageBasedLightSource(diffuse, specular, scaleFactor); +} + +void SceneView::UseFramebuffer(bool useFramebuffer) +{ + GetImpl(*this).UseFramebuffer(useFramebuffer); +} + +bool SceneView::IsUsingFramebuffer() +{ + return GetImpl(*this).IsUsingFramebuffer(); +} + +} // namespace Scene3D + +} // namespace Dali diff --git a/dali-scene3d/public-api/controls/scene-view/scene-view.h b/dali-scene3d/public-api/controls/scene-view/scene-view.h new file mode 100644 index 0000000..15a28d4 --- /dev/null +++ b/dali-scene3d/public-api/controls/scene-view/scene-view.h @@ -0,0 +1,295 @@ +#ifndef DALI_SCENE3D_SCENE_VIEW_H +#define DALI_SCENE3D_SCENE_VIEW_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. + * + */ + +// INTERNAL INCLUDES +#include + +// EXTERNAL INCLUDES +#include +#include +#include + +namespace Dali +{ +namespace Scene3D +{ +namespace Internal DALI_INTERNAL +{ +class SceneView; +} + +/** + * @addtogroup dali_toolkit_controls_scene_view + * @{ + */ + +/** + * @brief SceneView is a Dali::Toolkit::Control to show multiple 3D objects in a single 3D scene. + * Each SceneView has its own 3D space, and 3D objects added to SceneView are positioned in the space. + * SceneView has a 3D root layer internally to trigger the depth test in the rendering process. + * When an Actor is added to the SceneView with Add() method, + * the Actor and its children are actually become child of the 3D layer automatically. + * + * SceneView + * | + * Dali::Layer(Layer::LAYER_3D) + * | + * Actor + * + * The children of the 3D root layer will be rendered with the SceneView's own CameraActor. + * + * SceneView can have multiple CameraActor and one of them is used to render the multiple objects as a Scene. + * AddCamera(), RemoveCamera(), GetCamera(), and SelectCamera() are methods to manage CameraActors of the SceneView. + * Users can place multiple cameras in a scene, either to show the entire scene or to show individual objects. + * And the user can select the currently needed camera by using the SelectCamera() method. + * + * SceneView has one CameraActor built-in by default at the (0, 0, -z). + * The default CameraActor has index 0 and is not removed by using RemoveCamera() method. + * Therefore, the minimum value returned by GetCameraCount() method is 1. + * + * If the size of SceneView is changed, Some properties of CameraActor that depend on the size can be changed too. + * The changing properties are as follows: projectionMode, aspectRatio, leftPlaneDistance, rightPlaneDistance, topPlaneDistance, and bottomPlaneDistance. + * Position, near/farPlaneDistance, and FieldOfView are maintained even if the size of the SceneView is changed. + * The FieldOfView of Dali::CameraActor is for vertical fov. The horizontal fov is internally updated according to the SceneView size. + * + * The same light source is set for all Models added to SceneView, if SceneView has light source. + * The SetImageBasedLightSource() method sets the same IBL to all Models added to the SceneView. + * If any Model already has an IBL, it is replaced with the SceneView's IBL. + * + * SceneView provides an option to use FBO for rendering result with UseFramebuffer() method. + * If it is false, SceneView is always drawn in the form of a rectangle on the default window surface directly. + * It improves performance, but the SceneView is always drawn on top of other 2D objects regardless of Actor tree order. + * And it will show wrong result in case the window's default CameraActor is transformed. + * So, it is recommended not to change window's CameraActor. + * + * If FBO is used, the rendering result of SceneView is drawn on the FBO and it is mapped on the plane of the SceneView. + * It decreases performance, but it is useful to show SceneView according to the rendering order with other Actors. + * And it can be used in case window's CameraActor is transformed. + * + * And since SceneView is a Control, it can be placed together with other 2D UI components in the DALi window. + * + * @code + * + * Dali::Scene3D::SceneView sceneView = Dali::Scene3D::SceneView::New(); + * sceneView.SetProperty(Dali::Actor::Property::SIZE, Vector2(400, 400)); + * mWindow.Add(sceneView); + * + * Dali::Scene3D::ModelView model = Dali::Scene3D::ModelView::New(...); + * sceneView.Add(model); + * + * CameraActor cameraActor = CameraActor::New(); + * // Setting CameraActor. + * sceneView.AddCamera(cameraActor); + * + * @endcode + */ +class DALI_SCENE3D_API SceneView : public Dali::Toolkit::Control +{ +public: + /** + * @brief Create an initialized SceneView. + * @return A handle to a newly allocated Dali resource + */ + static SceneView New(); + + /** + * @brief Creates an uninitialized SceneView. + * + * Only derived versions can be instantiated. Calling member + * functions with an uninitialized Dali::Object is not allowed. + */ + SceneView(); + + /** + * @brief Destructor. + * + * This is non-virtual since derived Handle types must not contain data or virtual methods. + */ + ~SceneView(); + + /** + * @brief Copy constructor. + * @param[in] sceneView Handle to an object + */ + SceneView(const SceneView& sceneView); + + /** + * @brief Move constructor + * + * @param[in] rhs A reference to the moved handle + */ + SceneView(SceneView&& rhs); + + /** + * @brief Assignment operator. + * @param[in] sceneView Handle to an object + * @return reference to this + */ + SceneView& operator=(const SceneView& sceneView); + + /** + * @brief Move assignment + * + * @param[in] rhs A reference to the moved handle + * @return A reference to this + */ + SceneView& operator=(SceneView&& rhs); + + /** + * @brief Downcasts an Object handle to SceneView. + * + * If handle points to a SceneView, the downcast produces valid handle. + * If not, the returned handle is left uninitialized. + * + * @param[in] handle Handle to an object + * @return Handle to a SceneView or an uninitialized handle + */ + static SceneView DownCast(BaseHandle handle); + + /** + * @brief Adds a CameraActor to the SceneView + * The CameraActor can be used as a selected camera to render the scene by using SelectCamera(uint32_t) or SelectCamera(std::string) + * + * @note Some properties of the CameraActor will be change depending on the Size of this SceneView. + * Those properties are as follows: + * projectionMode, aspectRatio, nearPlaneDistance, farPlaneDistance, leftPlaneDistance, rightPlaneDistance, topPlaneDistance, and bottomPlaneDistance. + * + * The FieldOfView of Dali::CameraActor is for vertical fov. + * When the size of the SceneView is changed, the vertical fov is maintained + * and the horizontal fov is automatically calculated according to the SceneView's aspect ratio. + * + * @param[in] camera CameraActor added on this scene view. + */ + void AddCamera(Dali::CameraActor camera); + + /** + * @brief Removes a CameraActor from this SceneView. + * @note If removed CameraActor is selected CameraActor, + * first camera in the list is set to selected CameraActor. + * + * @param[in] camera CameraActor to be removed from this SceneView + */ + void RemoveCamera(CameraActor camera); + + /** + * @brief Retrieves the number of cameras. + * + * @return Number of cameras those currently the SceneView contains. + */ + uint32_t GetCameraCount(); + + /** + * @brief Retrieves selected CameraActor. + * + * @return CameraActor currently used in SceneView as a selected CameraActor + */ + CameraActor GetSelectedCamera(); + + /** + * @brief Retrieves a CameraActor of the index. + * + * @param[in] index Index of CameraActor to be retrieved. + * + * @return CameraActor of the index + */ + CameraActor GetCamera(uint32_t index); + + /** + * @brief Retrieves a CameraActor of the name. + * + * @param[in] name string keyword of CameraActor to be retrieved. + * + * @return CameraActor that has the name as a Dali::Actor::Property::NAME + */ + CameraActor GetCamera(const std::string& name); + + /** + * @brief Makes SceneView use a CameraActor of index as a selected camera. + * + * @param[in] index Index of CameraActor to be used as a selected camera. + */ + void SelectCamera(uint32_t index); + + /** + * @brief Makes SceneView use a CameraActor of a name as a selected camera. + * + * @param[in] name string keyword of CameraActor to be used as a selected camera. + */ + void SelectCamera(const std::string& name); + + /** + * @brief Sets Image Based Light Source to apply it on the all Models those added on this SceneView. + * + * @note If any Models already have IBL, they are batch-overridden with the SceneView's IBL. + * If SceneView has IBL, IBL of newly added Model is also overridden. + * To set indivisual IBL for each Model, the Model's IBL should be set after the SceneView's IBL. + * + * @param[in] diffuse cube map that can be used as a diffuse IBL source. + * @param[in] specular cube map that can be used as a specular IBL source. + * @param[in] scaleFactor scale factor that controls light source intensity in [0.0f, 1.0f]. Default value is 1.0f. + */ + void SetImageBasedLightSource(const std::string& diffuse, const std::string& specular, float scaleFactor = 1.0f); + + /** + * @brief Sets whether to use FBO or not for the SceneView. + * If useFramebuffer is true, rendering result of SceneView is drawn on FBO and it is mapping on this SceneView plane. + * If useFramebuffer is false, each item in SceneView is rendered on window directly. + * Default is false. + * + * @note If useFramebuffer is true, it could decrease performance but entire rendering order is satisfied. + * If useFramebuffer is false, performance is become better but SceneView is rendered on top of the other 2D Actors regardless tree order. + * + * @param[in] useFramebuffer True to use FBO for SceneView. + */ + void UseFramebuffer(bool useFramebuffer); + + /** + * @brief Gets whether this SceneView uses Framebuffer or not. + * + * @return bool True if this SceneView uses Framebuffer. + */ + bool IsUsingFramebuffer(); + +public: // Not intended for application developers + /// @cond internal + /** + * @brief Creates a handle using the Toolkit::Internal implementation. + * + * @param[in] implementation The Control implementation + */ + DALI_INTERNAL SceneView(Internal::SceneView& implementation); + + /** + * @brief Allows the creation of this Control from an Internal::CustomActor pointer. + * + * @param[in] internal A pointer to the internal CustomActor + */ + DALI_INTERNAL SceneView(Dali::Internal::CustomActor* internal); + /// @endcond +}; + +/** + * @} + */ +} // namespace Scene3D + +} // namespace Dali + +#endif // DALI_SCENE3D_SCENE_VIEW_H diff --git a/dali-scene3d/public-api/file.list b/dali-scene3d/public-api/file.list index 23d4702..c80e43f 100644 --- a/dali-scene3d/public-api/file.list +++ b/dali-scene3d/public-api/file.list @@ -2,6 +2,7 @@ set(scene3d_public_api_dir "${scene3d_dir}/public-api") set(scene3d_src_files ${scene3d_src_files} ${scene3d_public_api_dir}/controls/model-view/model-view.cpp + ${scene3d_public_api_dir}/controls/scene-view/scene-view.cpp ${scene3d_public_api_dir}/loader/alpha-function-helper.cpp ${scene3d_public_api_dir}/loader/animated-property.cpp ${scene3d_public_api_dir}/loader/animation-definition.cpp diff --git a/dali-scene3d/public-api/loader/cube-map-loader.cpp b/dali-scene3d/public-api/loader/cube-map-loader.cpp index c4aae09..f3a5aa0 100644 --- a/dali-scene3d/public-api/loader/cube-map-loader.cpp +++ b/dali-scene3d/public-api/loader/cube-map-loader.cpp @@ -23,6 +23,7 @@ #include // EXTERNAL INCLUDES +#include #include namespace Dali @@ -36,13 +37,29 @@ namespace Scene3D { namespace Loader { -bool LoadCubeMapData(const std::string& path, CubeData& cubedata) +bool LoadCubeMapData(const std::string& cubeMapUrl, CubeData& cubedata) { - std::filesystem::path modelPath(path); + std::filesystem::path modelPath(cubeMapUrl); std::string extension = modelPath.extension(); std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); - return (extension == KTX_EXTENSION) ? Dali::Scene3D::Loader::LoadKtxData(path, cubedata) : Dali::Scene3D::Loader::LoadCubeData(path, cubedata); + return (extension == KTX_EXTENSION) ? Dali::Scene3D::Loader::LoadKtxData(cubeMapUrl, cubedata) : Dali::Scene3D::Loader::LoadCubeData(cubeMapUrl, cubedata); +} + +Texture LoadCubeMap(const std::string& cubeMapUrl) +{ + Texture cubeTexture; + Dali::Scene3D::Loader::CubeData cubeData; + if(Dali::Scene3D::Loader::LoadCubeMapData(cubeMapUrl, cubeData)) + { + cubeTexture = cubeData.CreateTexture(); + } + else + { + DALI_LOG_ERROR("Fail to load cube map, %s\n", cubeMapUrl.c_str()); + } + + return cubeTexture; } } // namespace Loader diff --git a/dali-scene3d/public-api/loader/cube-map-loader.h b/dali-scene3d/public-api/loader/cube-map-loader.h index ec7fd24..0ead0a5 100644 --- a/dali-scene3d/public-api/loader/cube-map-loader.h +++ b/dali-scene3d/public-api/loader/cube-map-loader.h @@ -28,13 +28,21 @@ namespace Scene3D namespace Loader { /** - * @brief Loads cube map data texture from a cube map file. + * @brief Loads cube map data from a cube map file. * - * @param[in] path The file path. + * @param[in] cubeMapUrl The cube map file url. * @param[out] cubedata The data structure with all pixel data objects. * @return bool True if the loading is succeded. */ -bool LoadCubeMapData(const std::string& path, CubeData& cubedata); +bool LoadCubeMapData(const std::string& cubeMapUrl, CubeData& cubedata); + +/** + * @brief Loads cube map data from a cube map file and return texture. + * + * @param[in] cubeMapUrl The cube map file path. + * @return Texture the loaded cube map texture. + */ +Texture LoadCubeMap(const std::string& cubeMapUrl); } // namespace Loader } // namespace Scene3D -- 2.7.4