From: Joogab Yun Date: Mon, 17 Sep 2018 04:59:25 +0000 (+0900) Subject: [Tizen] Scene, Scene Loader, and glTF Loader X-Git-Tag: accepted/tizen/unified/20180918.062842~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7629483212dfefffcde862db694c2e0666b163e7;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git [Tizen] Scene, Scene Loader, and glTF Loader This reverts commit e89aa76860cca51c640c00fef0236db0f59c1a71. Change-Id: I8dddc5bc5e31f08c2c09b5a299fee43db2e68b77 --- diff --git a/automated-tests/resources/AnimatedCube.bin b/automated-tests/resources/AnimatedCube.bin new file mode 100644 index 0000000..72f7d2d Binary files /dev/null and b/automated-tests/resources/AnimatedCube.bin differ diff --git a/automated-tests/resources/AnimatedCube.gltf b/automated-tests/resources/AnimatedCube.gltf new file mode 100644 index 0000000..2f78e20 --- /dev/null +++ b/automated-tests/resources/AnimatedCube.gltf @@ -0,0 +1,401 @@ +{ + "accessors" : [ + { + "bufferView" : 0, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 3, + "max" : [ + 2.000000 + ], + "min" : [ + 0.000000 + ], + "type" : "SCALAR" + }, + { + "bufferView" : 1, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 3, + "max" : [ + 0.000000, + 1.000000, + 0.000000, + 1.000000 + ], + "min" : [ + 0.000000, + -8.742278e-008, + 0.000000, + -1.000000 + ], + "type" : "VEC4" + }, + { + "bufferView" : 2, + "byteOffset" : 0, + "componentType" : 5123, + "count" : 36, + "max" : [ + 35 + ], + "min" : [ + 0 + ], + "type" : "SCALAR" + }, + { + "bufferView" : 3, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + 1.000000, + 1.000001 + ], + "min" : [ + -1.000000, + -1.000000, + -1.000000 + ], + "type" : "VEC3" + }, + { + "bufferView" : 4, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + 1.000000, + 1.000000 + ], + "min" : [ + -1.000000, + -1.000000, + -1.000000 + ], + "type" : "VEC3" + }, + { + "bufferView" : 5, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + -0.000000, + -0.000000, + 1.000000 + ], + "min" : [ + 0.000000, + -0.000000, + -1.000000, + -1.000000 + ], + "type" : "VEC4" + }, + { + "bufferView" : 6, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + 1.000000 + ], + "min" : [ + -1.000000, + -1.000000 + ], + "type" : "VEC2" + } + ], + "animations" : [ + { + "channels" : [ + { + "sampler" : 0, + "target" : { + "node" : 0, + "path" : "rotation" + } + } + ], + "name" : "animation_AnimatedCube", + "samplers" : [ + { + "input" : 0, + "interpolation" : "LINEAR", + "output" : 1 + } + ] + } + ], + "asset" : { + "generator" : "VKTS glTF 2.0 exporter", + "version" : "2.0" + }, + "bufferViews" : [ + { + "buffer" : 0, + "byteLength" : 12, + "byteOffset" : 0 + }, + { + "buffer" : 0, + "byteLength" : 48, + "byteOffset" : 12 + }, + { + "buffer" : 0, + "byteLength" : 72, + "byteOffset" : 60, + "target" : 34963 + }, + { + "buffer" : 0, + "byteLength" : 432, + "byteOffset" : 132, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 432, + "byteOffset" : 564, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 576, + "byteOffset" : 996, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 288, + "byteOffset" : 1572, + "target" : 34962 + } + ], + "buffers" : [ + { + "byteLength" : 1860, + "uri" : "AnimatedCube.bin" + } + ], + "images" : [ + { + "uri" : "AnimatedCube_BaseColor.png" + }, + { + "uri" : "AnimatedCube_MetallicRoughness.png" + } + ], + "materials" : [ + { + "name" : "AnimatedCube", + "pbrMetallicRoughness" : { + "baseColorTexture" : { + "index" : 0 + }, + "metallicRoughnessTexture" : { + "index" : 1 + }, + "baseColorFactor": [ 1.000, 0.766, 0.336, 1.0 ], + "metallicFactor": 1.0, + "roughnessFactor": 0.0 + }, + "normalTexture": { + "scale": 1, + "index": 0 + }, + "occlusionTexture": { + "index": 0 + }, + "emissiveTexture": { + "index": 0 + }, + "emissiveFactor": [ 0.2, 0.1, 0.0 ], + "doubleSided": false, + "alphaMode": "MASK", + "alphaCutoff": 0.5 + }, + { + "name" : "AnimatedCube2", + "pbrMetallicRoughness" : { + "baseColorTexture" : { + "index" : 0 + }, + "metallicRoughnessTexture" : { + "index" : 1 + }, + "baseColorFactor": [ 1.000, 0.766, 0.336, 1.0 ], + "metallicFactor": 1.0, + "roughnessFactor": 0.0 + }, + "normalTexture": { + "scale": 1, + "index": 0 + }, + "occlusionTexture": { + "index": 0 + }, + "emissiveTexture": { + "index": 0 + }, + "emissiveFactor": [ 0.2, 0.1, 0.0 ], + "doubleSided": false, + "alphaMode": "OPAQUE" + } + ], + "meshes" : [ + { + "name" : "AnimatedCube", + "primitives" : [ + { + "attributes" : { + "NORMAL" : 4, + "POSITION" : 3, + "TANGENT" : 5, + "TEXCOORD_0" : 6, + "COLOR_0" : 3 + }, + "indices" : 2, + "material" : 0, + "mode" : 4 + } + ] + }, + { + "name" : "AnimatedCube2", + "primitives" : [ + { + "attributes" : { + "NORMAL" : 4, + "POSITION" : 3, + "TANGENT" : 5, + "TEXCOORD_0" : 6, + "COLOR_0" : 3 + }, + "indices" : 2, + "material" : 1, + "mode" : 4 + } + ] + } + ], + "nodes" : [ + { + "mesh" : 0, + "name" : "AnimatedCube", + "rotation" : [ + 0.000000, + -1.000000, + 0.000000, + 0.000000 + ] + }, + { + "mesh" : 1, + "name" : "AnimatedCube2" + }, + { + + "camera" : 0, + "scale" : [ 0.5, 0.5, 3.0 ] + }, + { + "camera" : 1, + "translation" : [ 0.5, 0.5, 3.0 ], + "children": [ + 4 + ] + }, + { + "camera" : 2, + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + -1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ] + } + ], + "scene" : 0, + "scenes" : [ + { + "nodes" : [ + 0, 1, 2, 3 + ] + } + ], + "textures" : [ + { + "sampler" : 0, + "source" : 0 + }, + { + "sampler" : 1, + "source" : 1 + } + ], + "cameras" : [ + { + "type": "perspective", + "perspective": { + "aspectRatio": 1.0, + "yfov": 0.7, + "zfar": 100.0, + "znear": 0.01 + } + }, + { + "type": "orthographic", + "orthographic": { + "xmag": 1.0, + "ymag": 1.0, + "zfar": 100.0, + "znear": 0.01 + } + }, + { + "type": "orthographic", + "orthographic": { + "xmag": 1.0, + "ymag": 1.0, + "zfar": 100.0, + "znear": 0.01 + } + } + ], + "samplers": [ + { + "magFilter": 9729, + "minFilter": 9987, + "wrapS": 33071, + "wrapT": 10497 + }, + { + "magFilter": 9728, + "minFilter": 9986, + "wrapS": 33071, + "wrapT": 33648 + } + ] +} \ No newline at end of file diff --git a/automated-tests/resources/AnimatedCube_BaseColor.png b/automated-tests/resources/AnimatedCube_BaseColor.png new file mode 100644 index 0000000..5e5cb20 Binary files /dev/null and b/automated-tests/resources/AnimatedCube_BaseColor.png differ diff --git a/automated-tests/resources/AnimatedCube_MetallicRoughness.png b/automated-tests/resources/AnimatedCube_MetallicRoughness.png new file mode 100644 index 0000000..efd2026 Binary files /dev/null and b/automated-tests/resources/AnimatedCube_MetallicRoughness.png differ diff --git a/automated-tests/resources/forest_diffuse_cubemap.png b/automated-tests/resources/forest_diffuse_cubemap.png new file mode 100644 index 0000000..ff3e237 Binary files /dev/null and b/automated-tests/resources/forest_diffuse_cubemap.png differ diff --git a/automated-tests/resources/forest_specular_cubemap.png b/automated-tests/resources/forest_specular_cubemap.png new file mode 100644 index 0000000..d5cb909 Binary files /dev/null and b/automated-tests/resources/forest_specular_cubemap.png differ diff --git a/automated-tests/src/dali-toolkit/CMakeLists.txt b/automated-tests/src/dali-toolkit/CMakeLists.txt index 1e4829b..0d990ab 100755 --- a/automated-tests/src/dali-toolkit/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit/CMakeLists.txt @@ -27,6 +27,7 @@ SET(TC_SOURCES utc-Dali-KeyInputFocusManager.cpp utc-Dali-Layouting.cpp utc-Dali-PageTurnView.cpp + utc-Dali-Scene.cpp utc-Dali-Script.cpp utc-Dali-ScrollBar.cpp utc-Dali-ScrollView.cpp diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Scene.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Scene.cpp new file mode 100644 index 0000000..5791403 --- /dev/null +++ b/automated-tests/src/dali-toolkit/utc-Dali-Scene.cpp @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2014 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 + +using namespace Dali; +using namespace Dali::Toolkit; + +void dali_scene_startup(void) +{ + test_return_value = TET_UNDEF; +} + +void dali_scene_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) 2016 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_diffuse_cubemap.png"; +const char* TEST_SPECULAR_TEXTURE = TEST_RESOURCE_DIR "/forest_specular_cubemap.png"; +} + +int UtcDaliSceneConstructorP(void) +{ + TestApplication application; + + Scene scene; + + DALI_TEST_CHECK( !scene ); + END_TEST; +} + +int UtcDaliSceneCopyConstructorP(void) +{ + TestApplication application; + + // Initialize an object, ref count == 1 + Scene scene = Scene::New( TEST_GLTF_FILE_NAME ); + + Scene copy( scene ); + DALI_TEST_CHECK( copy ); + END_TEST; +} + +int UtcDaliSceneCopyConstructor2P(void) +{ + TestApplication application; + + // Initialize an object, ref count == 1 + Toolkit::Scene scene = Toolkit::Scene::New( TEST_GLTF_FILE_NAME, TEST_DIFFUSE_TEXTURE, TEST_SPECULAR_TEXTURE ); + + Scene copy( scene ); + DALI_TEST_CHECK( copy ); + END_TEST; +} + +int UtcDaliSceneAssignmentOperatorP(void) +{ + TestApplication application; + + Scene scene = Scene::New( TEST_GLTF_FILE_NAME ); + + Scene copy( scene ); + DALI_TEST_CHECK( copy ); + + DALI_TEST_CHECK( scene == copy ); + END_TEST; +} + +int UtcDaliSceneNewP(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliSceneNewP"); + + // Create the Slider actor + Scene scene; + DALI_TEST_CHECK( !scene ); + + scene = Scene::New( TEST_GLTF_FILE_NAME ); + DALI_TEST_CHECK( scene ); + + END_TEST; +} + +int UtcDaliSceneDestructorP(void) +{ + ToolkitTestApplication application; + + Scene* scene = new Scene(); + delete scene; + + DALI_TEST_CHECK( true ); + END_TEST; +} + +int UtcDaliSceneDownCast(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliSceneDownCast"); + + Toolkit::Scene view = Toolkit::Scene::New( TEST_GLTF_FILE_NAME ); + BaseHandle handle(view); + + Toolkit::Scene scene = Toolkit::Scene::DownCast( handle ); + DALI_TEST_CHECK( view ); + DALI_TEST_CHECK( scene ); + DALI_TEST_CHECK( scene == view ); + END_TEST; +} + +int UtcDaliSceneSetLight(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliSceneSetLight"); + + Toolkit::Scene view = Toolkit::Scene::New( TEST_GLTF_FILE_NAME ); + + bool lightSet = view.SetLight( Scene::LightType::DIRECTIONAL_LIGHT, Vector3( 1.0, 1.0, -1.0 ), Vector3( 0.3, 0.3, 0.3 ) ); + DALI_TEST_CHECK( lightSet ); + bool lightSet2 = view.SetLight( Scene::LightType::POINT_LIGHT, Vector3( 1.0, 1.0, -1.0 ), Vector3( 0.3, 0.3, 0.3 ) ); + DALI_TEST_CHECK( lightSet2 ); + + END_TEST; +} + +int UtcDaliSceneGetCamera(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliSceneGetCamera"); + + Toolkit::Scene view = Toolkit::Scene::New( TEST_GLTF_FILE_NAME ); + + CameraActor camera = view.GetDefaultCamera(); + DALI_TEST_CHECK( camera ); + + CameraActor camera2 = view.GetCamera( -1 ); + DALI_TEST_CHECK( camera2 ); + + CameraActor camera3 = view.GetCamera( 0 ); + DALI_TEST_CHECK( camera3 ); + + END_TEST; +} + +int UtcDaliSceneAnimation(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliSceneAnimation"); + + Toolkit::Scene view = Toolkit::Scene::New( TEST_GLTF_FILE_NAME ); + + bool playAnimation = view.PlayAnimations(); + DALI_TEST_CHECK( playAnimation ); + + END_TEST; +} diff --git a/build/tizen/dali-toolkit/Makefile.am b/build/tizen/dali-toolkit/Makefile.am index 22425f2..3c3fa01 100644 --- a/build/tizen/dali-toolkit/Makefile.am +++ b/build/tizen/dali-toolkit/Makefile.am @@ -142,6 +142,7 @@ develapimagnifierdir = $(develapicontrolsdir)/magnifier develapinavigationviewdir = $(develapicontrolsdir)/navigation-view develapipageturnviewdir = $(develapicontrolsdir)/page-turn-view develapipopupdir = $(develapicontrolsdir)/popup +develapiscenedir = $(develapicontrolsdir)/scene develapishadowviewdir = $(develapicontrolsdir)/shadow-view develapisuperblurviewdir = $(develapicontrolsdir)/super-blur-view develapifocusmanagerdir = $(develapidir)/focus-manager @@ -180,6 +181,7 @@ develapipopup_HEADERS = $(devel_api_popup_header_files) develapivisualfactory_HEADERS = $(devel_api_visual_factory_header_files) develapivisuals_HEADERS = $(devel_api_visuals_header_files) develapiscripting_HEADERS = $(devel_api_scripting_header_files) +develapiscene_HEADERS = $(devel_api_scene_header_files) develapishadowview_HEADERS = $(devel_api_shadow_view_header_files) develapishadereffects_HEADERS = $(devel_api_shader_effects_header_files) develapistyling_HEADERS = $(devel_api_styling_header_files) diff --git a/dali-toolkit/devel-api/controls/scene/scene.cpp b/dali-toolkit/devel-api/controls/scene/scene.cpp new file mode 100644 index 0000000..30cfb97 --- /dev/null +++ b/dali-toolkit/devel-api/controls/scene/scene.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2018 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 Toolkit +{ + +Scene::Scene() +{ +} + +Scene::~Scene() +{ +} + +Scene::Scene( const Scene& handle ) + : Control( handle ) +{ +} + +Scene& Scene::operator=( const Scene& handle ) +{ + BaseHandle::operator=( handle ); + return *this; +} + +Scene Scene::New( const std::string& filePath ) +{ + return Internal::Scene::New( filePath ); +} + +Scene Scene::New( const std::string& filePath, const std::string& diffuseTexturePath, const std::string& specularTexturePath, Vector4 ScaleFactor ) +{ + return Internal::Scene::New( filePath, diffuseTexturePath, specularTexturePath, ScaleFactor ); +} + +Scene::Scene( Internal::Scene& implementation ) + : Control( implementation ) +{ +} + +Scene::Scene( Dali::Internal::CustomActor* internal ) + : Control( internal ) +{ + VerifyCustomActorPointer( internal ); +} + +Scene Scene::DownCast( BaseHandle handle ) +{ + return Control::DownCast( handle ); +} + +uint32_t Scene::GetAnimationCount() +{ + return GetImpl( *this ).GetAnimationCount(); +} + +bool Scene::PlayAnimation( uint32_t index ) +{ + return GetImpl( *this ).PlayAnimation( index ); +} + +bool Scene::PlayAnimations() +{ + return GetImpl( *this ).PlayAnimations(); +} + +bool Scene::SetLight( LightType type, Vector3 lightVector, Vector3 lightColor ) +{ + return GetImpl( *this ).SetLight( type, lightVector, lightColor ); +} + +CameraActor Scene::GetDefaultCamera() +{ + return GetImpl( *this ).GetDefaultCamera(); +} + +CameraActor Scene::GetCamera( const int cameraIndex ) +{ + return GetImpl( *this ).GetCamera( cameraIndex ); +} + +}//namespace Toolkit + +}//namespace Dali + diff --git a/dali-toolkit/devel-api/controls/scene/scene.h b/dali-toolkit/devel-api/controls/scene/scene.h new file mode 100644 index 0000000..634622a --- /dev/null +++ b/dali-toolkit/devel-api/controls/scene/scene.h @@ -0,0 +1,202 @@ +#ifndef DALI_TOOLKIT_SCENE_H +#define DALI_TOOLKIT_SCENE_H + +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// INTERNAL INCLUDES +#include +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal DALI_INTERNAL +{ + +/** + * Scene implementation class + */ +class Scene; + +} + +/** + * + * Scene is a class for containing scene elements loaded from scene format file(e.g., glTF). Scene elements mean scene graph, cameras, and animations. + * + * Basic idea:- + * + * 1) The Scene is initialized with diffuse and specular cube map for the Image Based Lighting.\n + * If the Scene initialized without cube map, the objects of the Scene cannot be rendered with IBL.\n + * 2) The Scene is loaded from each scene format file(e.g., glTF).\n + * 3) The Scene can have a point light or a directional light.(optional)\n + * 4) The Scene playes each actor's animation.\n + * + * + * Usage example: - + * + * @code + * + * void SceneExample::Create( Application& application ) + * { + * // Use 'Scene::New( URL_SCENE_FILE )', if you don't want to render with IBL. + * Scene scene = Scene::New( URL_SCENE_FILE, URL_DIFFUSE_TEXTURE, URL_SPECULAR_TEXTURE ); + * + * Stage::GetCurrent().Add( scene ); + * scene.PlayAnimations(); + * + * scene.SetLight( Scene::LightType::DIRECTIONAL_LIGHT, Vector3( 1.0, 1.0, -1.0 ), Vector3( 0.3, 0.3, 0.3 ) ); + * } + * + * @endcode + * + * @remarks This control makes 3D Layer internally. Therefore, if any 2D UI + * control is added as a child of this Scene, the functionality of the 2D UI + * may not work well. + */ + +class DALI_TOOLKIT_API Scene : public Control +{ +public: + + enum LightType + { + // Scene doesn't use both of point and directional light + NONE = 0, + // Scene use point light + POINT_LIGHT, + // Scene use directional light + DIRECTIONAL_LIGHT, + // Scene use Image Based Lighting + IMAGE_BASED_LIGHT, + // Scene use Image Based Lighting and point light + IMAGE_BASED_LIGHT_AND_POINT_LIGHT, + // Scene use Image Based Lighting and directional light + IMAGE_BASED_LIGHT_AND_DIRECTIONAL_LIGHT + }; + + /** + * @brief Create an uninitialized Scene; this can be initialized with Scene::New() + * Calling member functions with an uninitialized Dali::Object is not allowed. + */ + Scene(); + + /** + * @brief Copy constructor. Creates another handle that points to the same real object + */ + Scene( const Scene& handle ); + + /** + * @brief Assignment operator. Changes this handle to point to another real object + */ + Scene& operator=( const Scene& handle ); + + /** + * @brief Destructor + * This is non-virtual since derived Handle types must not contain data or virtual methods. + */ + ~Scene(); + + /** + * @brief Downcast an Object handle to Scene. If handle points to a Scene the + * downcast produces valid handle. If not the returned handle is left uninitialized. + * @param[in] handle Handle to an object + * @return handle to a Scene or an uninitialized handle + */ + static Scene DownCast( BaseHandle handle ); + + /** + * @brief Create an initialized Scene. + * @param[in] filePath File path of scene format file (e.g., glTF). + * @return A handle to a newly allocated Dali resource + */ + static Scene New( const std::string& filePath ); + + /** + * @brief Create an initialized Scene. + * @param[in] filePath File path of scene format file (e.g., glTF). + * @param[in] diffuseTexturePath The texture path of diffuse cube map that used to render with Image Based Lighting. + * @param[in] specularTexturePath The texture path of specular cube map that used to render with Image Based Lighting. + * @param[in] ScaleFactor Scaling factor for the Image Based Lighting. Default value is initialized with Vector4( 1.0, 1.0, 1.0, 1.0 ). + * @return A handle to a newly allocated Dali resource + */ + static Scene New( const std::string& filePath, const std::string& diffuseTexturePath, const std::string& specularTexturePath, Vector4 ScaleFactor = Vector4( 1.0, 1.0, 1.0, 1.0 ) ); + + /** + * @brief Get animation count. + * @return number of animations. + */ + uint32_t GetAnimationCount(); + + /** + * @brief Play an animations. + * @param[in] index Animation index + * @return true if animation is played. + */ + bool PlayAnimation( uint32_t index ); + + /** + * @brief Play all animations. + * @return true if animations are played. + */ + bool PlayAnimations(); + + /** + * @brief Set point light or directional light. If SetLight is not called, this scene doesn't use these kind of light. + * @param[in] type The light type. If the light is point light set this LightType::POINT_LIGHT, + * or if the light is directional light set this LightType::DIRECTIONAL_LIGHT. + * @param[in] lightVector The point light position when light type is LightType::POINT_LIGHT. + * The light direction when light type is LightType::DIRECTIONAL_LIGHT. + * @param[in] lightColor Vector3 value that denotes the light color of point light or directional light. Since this is the light color, we don't need to use alpha value. + * @return true if point light or directional light is set. + */ + bool SetLight( LightType type, Vector3 lightVector, Vector3 lightColor = Vector3( 1.0, 1.0, 1.0 ) ); + + /** + * @brief Get default CameraActor. Dali::Camera::Type = Dali::Camera::LOOK_AT_TARGET , near clipping plane = 0.1, and camera position = Vector3( 0.0, 0.0, 0.0 ). + * @return CameraActor. + */ + CameraActor GetDefaultCamera(); + + /** + * @brief Get CameraActor. If there is no CameraActor in the list, then returns default CameraActor. + * @return CameraActor. + */ + CameraActor GetCamera( int cameraIndex = -1 ); + + // Not intended for developer use +public: + + /** + * @brief Creates a handle using the Toolkit::Internal implementation. + * @param[in] implementation The UI Control implementation. + */ + DALI_INTERNAL Scene( Toolkit::Internal::Scene& implementation ); + + explicit DALI_INTERNAL Scene( Dali::Internal::CustomActor* internal ); +}; + +} // namespace Toolkit + +} // namespace Dali + +#endif // DALI_TOOLKIT_SCENE_H diff --git a/dali-toolkit/devel-api/file.list b/dali-toolkit/devel-api/file.list index 988c48a..718b536 100755 --- a/dali-toolkit/devel-api/file.list +++ b/dali-toolkit/devel-api/file.list @@ -19,6 +19,7 @@ devel_api_src_files = \ $(devel_api_src_dir)/controls/page-turn-view/page-turn-view.cpp \ $(devel_api_src_dir)/controls/popup/confirmation-popup.cpp \ $(devel_api_src_dir)/controls/popup/popup.cpp \ + $(devel_api_src_dir)/controls/scene/scene.cpp \ $(devel_api_src_dir)/controls/shadow-view/shadow-view.cpp \ $(devel_api_src_dir)/controls/super-blur-view/super-blur-view.cpp \ $(devel_api_src_dir)/controls/text-controls/text-editor-devel.cpp \ @@ -132,6 +133,9 @@ devel_api_visuals_header_files = \ $(devel_api_src_dir)/visuals/text-visual-properties-devel.h \ $(devel_api_src_dir)/visuals/visual-properties-devel.h +devel_api_scene_header_files = \ + $(devel_api_src_dir)/controls/scene/scene.h + devel_api_shadow_view_header_files = \ $(devel_api_src_dir)/controls/shadow-view/shadow-view.h diff --git a/dali-toolkit/internal/controls/scene/gltf-loader.cpp b/dali-toolkit/internal/controls/scene/gltf-loader.cpp new file mode 100644 index 0000000..f376939 --- /dev/null +++ b/dali-toolkit/internal/controls/scene/gltf-loader.cpp @@ -0,0 +1,1884 @@ +/* + * Copyright (c) 2018 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 +#include + +// EXTERNAL INCLUDES +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include + +using namespace Dali::Toolkit::Internal::GLTF; + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +GltfLoader::GltfLoader() + : mNodes( NULL ), + mRoot( NULL ) +{ +} + +GltfLoader::~GltfLoader() +{ +} + +bool GltfLoader::LoadScene( const std::string& filePath, Internal::Scene& scene ) +{ + // Extracting directory path from full path to load resources. + if( std::string::npos != filePath.rfind('/') ) + { + mPath = filePath.substr( 0, filePath.rfind('/') ) + "/"; + } + + if( !ParseGltf( filePath ) ) + { + DALI_LOG_ERROR( "Fail to parse json file\n" ); + return false; + } + + mRoot = mParser.GetRoot(); + if( !mRoot ) + { + return false; + } + + if( !LoadAssets() ) + { + return false; + } + + if( !CreateScene( scene ) ) + { + return false; + } + return true; +} + +bool GltfLoader::ParseGltf( const std::string& filePath ) +{ + std::ifstream fileStream( filePath.c_str() ); + std::string fileBuffer( ( std::istreambuf_iterator( fileStream ) ), + ( std::istreambuf_iterator() ) ); + mParser = Dali::Toolkit::JsonParser::New(); + + return mParser.Parse( fileBuffer ); +} + +bool GltfLoader::LoadAssets() +{ + if( LoadBinaryData( mRoot ) && // pass a reference + LoadTextureArray( mRoot ) && // pass a reference + LoadMaterialSetArray( mRoot ) && // pass a reference + LoadMeshArray( mRoot ) // pass a reference + ) + { + return true; + } + return false; +} + +bool GltfLoader::LoadBinaryData( const TreeNode* root ) +{ + const TreeNode* buffersNode = root->GetChild( "buffers" ); + if( !buffersNode ) + { + return false; + } + for( TreeNode::ConstIterator bufferIter = ( *buffersNode ).CBegin(); bufferIter != ( *buffersNode ).CEnd(); ++bufferIter ) + { + LoadBuffer( ( *bufferIter ).second ); + } + + const TreeNode* bufferViewsNode = root->GetChild( "bufferViews" ); + if( !bufferViewsNode ) + { + return false; + } + for( TreeNode::ConstIterator bufferViewIter = ( *bufferViewsNode ).CBegin(); bufferViewIter != ( *bufferViewsNode ).CEnd(); ++bufferViewIter ) + { + LoadBufferView( ( *bufferViewIter ).second ); + } + + const TreeNode* accessorsNode = root->GetChild( "accessors" ); + if( !accessorsNode ) + { + return false; + } + for( TreeNode::ConstIterator accesorIter = ( *accessorsNode ).CBegin(); accesorIter != ( *accessorsNode ).CEnd(); ++accesorIter ) + { + LoadAccessor( ( *accesorIter ).second ); + } + + return true; +} + +bool GltfLoader::LoadBuffer( const TreeNode& buffer ) +{ + BufferInfo bufferInfo; + + const TreeNode* uriNode = buffer.GetChild( "uri" ); + if( uriNode ) + { + ReadString( uriNode, bufferInfo.uri ); + } + + const TreeNode* byteLengthNode = buffer.GetChild( "byteLength" ); + if( byteLengthNode ) + { + ReadInt( byteLengthNode, bufferInfo.byteLength ); + if( bufferInfo.byteLength < 0 ) + { + return false; + } + } + + const TreeNode* nameNode = buffer.GetChild( "name" ); + if( nameNode ) + { + ReadString( nameNode, bufferInfo.name ); + } + + mBufferArray.push_back( bufferInfo ); + + return true; +} + +bool GltfLoader::LoadBufferView( const TreeNode& buffer ) +{ + BufferViewInfo bufferViewInfo; + + const TreeNode* bufferNode = buffer.GetChild( "buffer" ); + if( bufferNode ) + { + ReadInt( bufferNode, bufferViewInfo.buffer ); + if( bufferViewInfo.buffer < 0 ) + { + return false; + } + } + + const TreeNode* byteOffsetNode = buffer.GetChild( "byteOffset" ); + if( byteOffsetNode ) + { + ReadInt( byteOffsetNode, bufferViewInfo.byteOffset ); + } + + const TreeNode* byteLengthNode = buffer.GetChild( "byteLength" ); + if( byteLengthNode ) + { + ReadInt( byteLengthNode, bufferViewInfo.byteLength ); + if( bufferViewInfo.byteLength < 0 ) + { + return false; + } + } + + const TreeNode* byteStrideNode = buffer.GetChild( "byteStride" ); + if( byteStrideNode ) + { + ReadInt( byteStrideNode, bufferViewInfo.byteStride ); + } + + const TreeNode* targetNode = buffer.GetChild( "target" ); + if( targetNode ) + { + ReadInt( targetNode, bufferViewInfo.target ); + } + + const TreeNode* nameNode = buffer.GetChild( "name" ); + if( nameNode ) + { + ReadString( nameNode, bufferViewInfo.name ); + } + + mBufferViewArray.push_back( bufferViewInfo ); + + return true; +} + +bool GltfLoader::LoadAccessor( const TreeNode& buffer ) +{ + AccessorInfo accessorInfo; + + const TreeNode* bufferViewNode = buffer.GetChild( "bufferView" ); + if( bufferViewNode ) + { + ReadInt( bufferViewNode, accessorInfo.bufferView ); + } + + const TreeNode* byteOffsetNode = buffer.GetChild( "byteOffset" ); + if( byteOffsetNode ) + { + ReadInt( byteOffsetNode, accessorInfo.byteOffset ); + } + + const TreeNode* componentTypeNode = buffer.GetChild( "componentType" ); + if( componentTypeNode ) + { + ReadInt( componentTypeNode, accessorInfo.componentType ); + if( accessorInfo.componentType < 0 ) + { + return false; + } + } + + const TreeNode* normalizedNode = buffer.GetChild( "normalized" ); + if( normalizedNode ) + { + ReadBool( normalizedNode, accessorInfo.normalized ); + } + + const TreeNode* countNode = buffer.GetChild( "count" ); + if( countNode ) + { + ReadInt( countNode, accessorInfo.count ); + if( accessorInfo.count < 0 ) + { + return false; + } + } + + const TreeNode* typeNode = buffer.GetChild( "type" ); + if( typeNode ) + { + ReadString( typeNode, accessorInfo.type ); + if( accessorInfo.type == "" ) + { + return false; + } + } + + const TreeNode* maxNode = buffer.GetChild( "max" ); + if( maxNode ) + { + ReadInt( maxNode, accessorInfo.max ); + } + + const TreeNode* minNode = buffer.GetChild( "min" ); + if( minNode ) + { + ReadInt( minNode, accessorInfo.min ); + } + + const TreeNode* nameNode = buffer.GetChild( "name" ); + if( nameNode ) + { + ReadString( nameNode, accessorInfo.name ); + } + + mAccessorArray.push_back( accessorInfo ); + + return true; +} + +bool GltfLoader::LoadTextureArray( const TreeNode* root ) +{ + const TreeNode* imagesNode = root->GetChild( "images" ); + if( imagesNode ) + { + for( TreeNode::ConstIterator imageIter = imagesNode->CBegin(); imageIter != imagesNode->CEnd(); ++imageIter ) + { + std::string imageUrl; + const TreeNode* uriNode = ( &( ( *imageIter ).second ) )->GetChild( "uri" ); + if( uriNode ) + { + std::string uri; + ReadString( uriNode, uri ); + imageUrl = mPath + uri; + } + + mSourceArray.push_back( LoadTexture( imageUrl.c_str(), true ) ); + } + } + + const TreeNode* samplersNode = root->GetChild( "samplers" ); + if( samplersNode ) + { + for( TreeNode::ConstIterator samplerIter = samplersNode->CBegin(); samplerIter != samplersNode->CEnd(); ++samplerIter ) + { + mSamplerArray.push_back( LoadSampler( ( ( *samplerIter ).second ) ) ); + } + } + + const TreeNode* texturesNode = root->GetChild( "textures" ); + if( texturesNode ) + { + for( TreeNode::ConstIterator textureIter = texturesNode->CBegin(); textureIter != texturesNode->CEnd(); ++textureIter ) + { + const TreeNode* TextureNode = &( ( *textureIter ).second ); + + TextureInfo texture; + const TreeNode* sourceNode = TextureNode->GetChild( "source" ); + if( sourceNode ) + { + ReadInt( sourceNode, texture.sourceIdx ); + } + + const TreeNode* samplerNode = TextureNode->GetChild( "sampler" ); + if( samplerNode ) + { + ReadInt( samplerNode, texture.samplerIdx ); + } + + mTextureArray.push_back( texture ); + } + } + return true; +} + +Texture GltfLoader::LoadTexture( const char* imageUrl, bool generateMipmaps ) +{ + Texture texture; + Devel::PixelBuffer pixelBuffer = LoadImageFromFile( imageUrl ); + if( pixelBuffer ) + { + texture = Texture::New( TextureType::TEXTURE_2D, pixelBuffer.GetPixelFormat(), pixelBuffer.GetWidth(), pixelBuffer.GetHeight() ); + PixelData pixelData = Devel::PixelBuffer::Convert( pixelBuffer ); + texture.Upload( pixelData ); + + if( generateMipmaps ) + { + texture.GenerateMipmaps(); + } + } + + return texture; +} + +Sampler GltfLoader::LoadSampler( const TreeNode& samplerNode ) +{ + Sampler sampler = Sampler::New(); + + FilterMode::Type minFilter = FilterMode::DEFAULT; + FilterMode::Type magFilter = FilterMode::DEFAULT; + const TreeNode* magFilterNode = samplerNode.GetChild( "magFilter" ); + if( magFilterNode ) + { + int magFilter_integer = 0; + ReadInt( magFilterNode, magFilter_integer ); + magFilter = GetFilterMode( magFilter_integer ); + } + + const TreeNode* minFilterNode = samplerNode.GetChild( "minFilter" ); + if( minFilterNode ) + { + int minFilter_integer = 0; + ReadInt( minFilterNode, minFilter_integer ); + minFilter = GetFilterMode( minFilter_integer ); + } + + WrapMode::Type wrapR = WrapMode::REPEAT; + WrapMode::Type wrapS = WrapMode::REPEAT; + WrapMode::Type wrapT = WrapMode::REPEAT; + const TreeNode* wrapNode = samplerNode.GetChild( "wrapS" ); + if( wrapNode ) + { + wrapS = GetWrapMode( wrapNode->GetInteger() ); + } + + wrapNode = samplerNode.GetChild( "wrapT" ); + if( wrapNode ) + { + wrapT = GetWrapMode( wrapNode->GetInteger() ); + } + + sampler.SetFilterMode( minFilter, magFilter ); + sampler.SetWrapMode( wrapR, wrapS, wrapT ); + + return sampler; +} + +FilterMode::Type GltfLoader::GetFilterMode( int mode ) +{ + FilterMode::Type retValue = FilterMode::DEFAULT; + /** + * glTF 2.0 Specification + * Filter Code + * 9728 : NEAREST + * 9729 : LINEAR + * 9984 : NEAREST_MIPMAP_NEAREST + * 9985 : LINEAR_MIPMAP_NEAREST + * 9986 : NEAREST_MIPMAP_LINEAR + * 9987 : LINEAR_MIPMAP_LINEAR + */ + switch( mode ) + { + case 9728: + { + retValue = FilterMode::NEAREST; + break; + } + case 9729: + { + retValue = FilterMode::LINEAR; + break; + } + case 9984: + { + retValue = FilterMode::NEAREST_MIPMAP_NEAREST; + break; + } + case 9985: + { + retValue = FilterMode::LINEAR_MIPMAP_NEAREST; + break; + } + case 9986: + { + retValue = FilterMode::NEAREST_MIPMAP_LINEAR; + break; + } + case 9987: + { + retValue = FilterMode::LINEAR_MIPMAP_LINEAR; + break; + } + } + + return retValue; +} + +WrapMode::Type GltfLoader::GetWrapMode( int mode ) +{ + WrapMode::Type retValue = WrapMode::REPEAT; + /** + * glTF 2.0 Specification + * Wrapping mode Code + * 33071 : CLAMP_TO_EDGE + * 33648 : MIRRORED_REPEAT + * 10497 : REPEAT + */ + switch( mode ) + { + case 33071: + { + retValue = WrapMode::CLAMP_TO_EDGE; + break; + } + case 33648: + { + retValue = WrapMode::MIRRORED_REPEAT; + break; + } + case 10497: + { + retValue = WrapMode::REPEAT; + break; + } + } + + return retValue; +} + +bool GltfLoader::LoadMaterialSetArray( const TreeNode* root ) +{ + const TreeNode* materialsNode = root->GetChild( "materials" ); + if( !materialsNode ) + { + return false; + } + + for( TreeNode::ConstIterator materialIter = materialsNode->CBegin(); materialIter != materialsNode->CEnd(); ++materialIter ) + { + GLTF::MaterialInfo materialInfo; + LoadPbrMetallicRoughness( ( ( *materialIter ).second ), materialInfo ); + + const TreeNode* materialNode = &( ( *materialIter ).second ); + const TreeNode* tempNode = materialNode->GetChild( "name" ); + if( tempNode ) + { + ReadString( tempNode, materialInfo.name ); + } + + materialInfo.alphaMode = "OPAQUE"; + tempNode = materialNode->GetChild( "alphaMode" ); + if( tempNode ) + { + ReadString( tempNode, materialInfo.alphaMode ); + } + + materialInfo.alphaCutoff = 1.0; + tempNode = materialNode->GetChild( "alphaCutoff" ); + if( tempNode ) + { + ReadFloat( tempNode, materialInfo.alphaCutoff ); + } + + materialInfo.doubleSided = false; + tempNode = materialNode->GetChild( "doubleSided" ); + if( tempNode ) + { + ReadBool( tempNode, materialInfo.doubleSided ); + } + + float floatVec[3]; + tempNode = materialNode->GetChild( "emissiveFactor" ); + if( tempNode && ReadVector( tempNode, floatVec, 3 ) ) + { + materialInfo.emissiveFactor = Vector3( floatVec[0], floatVec[1], floatVec[2] ); + } + + const TreeNode* texture = materialNode->GetChild( "normalTexture" ); + if( texture ) + { + tempNode = texture->GetChild( "index" ); + if( tempNode ) + { + materialInfo.normalTexture.index = tempNode->GetInteger(); + } + + tempNode = texture->GetChild( "texCoord" ); + if( tempNode ) + { + materialInfo.normalTexture.texCoord = tempNode->GetInteger(); + } + + materialInfo.normalTexture.value = 1.0; + tempNode = texture->GetChild( "scale" ); + if( tempNode ) + { + ReadFloat( tempNode, materialInfo.normalTexture.value ); + } + } + + texture = materialNode->GetChild( "occlusionTexture" ); + if( texture ) + { + tempNode = texture->GetChild( "index" ); + if( tempNode ) + { + materialInfo.occlusionTexture.index = tempNode->GetInteger(); + } + + tempNode = texture->GetChild( "texCoord" ); + if( tempNode ) + { + materialInfo.occlusionTexture.texCoord = tempNode->GetInteger(); + } + + + tempNode = texture->GetChild( "strength" ); + if( tempNode ) + { + ReadFloat( tempNode, materialInfo.occlusionTexture.value ); + } + } + + texture = materialNode->GetChild( "emissiveTexture" ); + if( texture ) + { + tempNode = texture->GetChild( "index" ); + if( tempNode ) + { + materialInfo.emissiveTexture.index = tempNode->GetInteger(); + } + + tempNode = texture->GetChild( "texCoord" ); + if( tempNode ) + { + materialInfo.emissiveTexture.texCoord = tempNode->GetInteger(); + } + } + mMaterialArray.push_back( materialInfo ); + } + return true; +} + +bool GltfLoader::LoadPbrMetallicRoughness( const TreeNode& material, MaterialInfo& materialInfo ) +{ + float floatVec[4]; + const TreeNode* pbrMetallicRoughnessNode = material.GetChild( "pbrMetallicRoughness" ); + if( !pbrMetallicRoughnessNode ) + { + return true; + } + + const TreeNode* tempNode; + tempNode = pbrMetallicRoughnessNode->GetChild( "metallicFactor" ); + if( tempNode ) + { + ReadFloat( tempNode, materialInfo.metallicFactor ); + } + + tempNode = pbrMetallicRoughnessNode->GetChild( "roughnessFactor" ); + if( tempNode ) + { + ReadFloat( tempNode, materialInfo.roughnessFactor ); + } + + tempNode = pbrMetallicRoughnessNode->GetChild( "baseColorFactor" ); + if( tempNode && ReadVector( tempNode, floatVec, 4 ) ) + { + materialInfo.baseColorFactor = Vector4( floatVec[0], floatVec[1], floatVec[2], floatVec[3] ); + } + + const TreeNode* baseColorTextureNode = pbrMetallicRoughnessNode->GetChild( "baseColorTexture" ); + if( baseColorTextureNode ) + { + tempNode = baseColorTextureNode->GetChild( "index" ); + if( tempNode ) + { + materialInfo.baseColorTexture.index = tempNode->GetInteger(); + } + + tempNode = baseColorTextureNode->GetChild( "texCoord" ); + if( tempNode ) + { + materialInfo.baseColorTexture.texCoord = tempNode->GetInteger(); + } + } + + const TreeNode* metallicRoughnessTextureNode = pbrMetallicRoughnessNode->GetChild( "metallicRoughnessTexture" ); + if( metallicRoughnessTextureNode ) + { + tempNode = metallicRoughnessTextureNode->GetChild( "index" ); + if( tempNode ) + { + materialInfo.metallicRoughnessTexture.index = tempNode->GetInteger(); + } + + tempNode = metallicRoughnessTextureNode->GetChild( "texCoord" ); + if( tempNode ) + { + materialInfo.metallicRoughnessTexture.texCoord = tempNode->GetInteger(); + } + } + + return true; +} + +bool GltfLoader::LoadMeshArray( const TreeNode* root ) +{ + const TreeNode* meshesNode = root->GetChild( "meshes" ); + if( !meshesNode ) + { + return false; + } + + for( TreeNode::ConstIterator meshIter = ( *meshesNode ).CBegin(); meshIter != ( *meshesNode ).CEnd(); ++meshIter ) + { + MeshInfo meshInfo; + const TreeNode* nameNode = ( &( *meshIter ).second )->GetChild( "name" ); + if( nameNode ) + { + ReadString( nameNode, meshInfo.name ); + } + meshInfo.geometry = Geometry::New(); + + //Need to add weights for Morph targets. + LoadPrimitive( ( *meshIter ).second, meshInfo ); + SetGeometry( meshInfo ); + mMeshArray.push_back( meshInfo ); + } + + return true; +} + +bool GltfLoader::LoadPrimitive( const TreeNode& mesh, MeshInfo& meshInfo ) +{ + const TreeNode* primitivesNode = mesh.GetChild( "primitives" ); + if( !primitivesNode ) + { + return false; + } + + for( TreeNode::ConstIterator primitiveIter = ( *primitivesNode ).CBegin(); primitiveIter != ( *primitivesNode ).CEnd(); ++primitiveIter ) + { + const TreeNode* primitiveNode = ( &( *primitiveIter ).second ); + const TreeNode* tempNode; + + tempNode = primitiveNode->GetChild( "indices" ); + if( tempNode ) + { + meshInfo.indicesIdx = tempNode->GetInteger(); + } + + tempNode = primitiveNode->GetChild( "material" ); + if( tempNode ) + { + meshInfo.materialsIdx = tempNode->GetInteger(); + } + + tempNode = primitiveNode->GetChild( "mode" ); + if( tempNode ) + { + meshInfo.mode = tempNode->GetInteger(); + } + + LoadAttribute( primitiveNode, meshInfo ); + } + + return true; +} + +bool GltfLoader::LoadAttribute( const TreeNode* primitive, MeshInfo& meshInfo ) +{ + const TreeNode* attrbuteNode = primitive->GetChild( "attributes" ); + if( !attrbuteNode ) + { + return false; + } + + const TreeNode* tempNode; + tempNode = attrbuteNode->GetChild( "POSITION" ); + if( tempNode ) + { + meshInfo.attribute.POSITION = tempNode->GetInteger(); + } + + tempNode = attrbuteNode->GetChild( "NORMAL" ); + if( tempNode ) + { + meshInfo.attribute.NORMAL = tempNode->GetInteger(); + } + + tempNode = attrbuteNode->GetChild( "TANGENT" ); + if( tempNode ) + { + meshInfo.attribute.TANGENT = tempNode->GetInteger(); + } + + int index = 0; + meshInfo.attribute.TEXCOORD.clear(); + tempNode = attrbuteNode->GetChild( "TEXCOORD_" + std::to_string( index ) ); + while( tempNode ) + { + int value = tempNode->GetInteger(); + meshInfo.attribute.TEXCOORD.push_back( value ); + tempNode = attrbuteNode->GetChild( "TEXCOORD_" + std::to_string( ++index ) ); + } + + index = 0; + meshInfo.attribute.COLOR.clear(); + tempNode = attrbuteNode->GetChild( "COLOR_" + std::to_string( index ) ); + while( tempNode ) + { + int value = tempNode->GetInteger(); + meshInfo.attribute.COLOR.push_back( value ); + tempNode = attrbuteNode->GetChild( "COLOR" + std::to_string( ++index ) ); + } + + return true; +} + +bool GltfLoader::SetGeometry( MeshInfo& meshInfo ) +{ + int indicesIdx = meshInfo.indicesIdx; + + if( meshInfo.mode != 0 ) + { + meshInfo.geometry.SetType( ( Dali::Geometry::Type )meshInfo.mode ); + } + + if( indicesIdx >= 0 ) + { + SetIndexBuffersData( meshInfo, indicesIdx ); + } + + SetVertexBufferData( meshInfo, meshInfo.attribute.POSITION, "aPosition", Property::VECTOR3 ); + SetAttributeBufferData( meshInfo, meshInfo.attribute.NORMAL, "aNormal", Property::VECTOR3 ); + SetAttributeBufferData( meshInfo, meshInfo.attribute.TANGENT, "aTangent", Property::VECTOR4 ); + + for( unsigned int i = 0; i < meshInfo.attribute.TEXCOORD.size(); ++i ) + { + int accessorIdx = meshInfo.attribute.TEXCOORD[i]; + std::ostringstream texCoordString; + texCoordString << "aTexCoord" << i; + SetAttributeBufferData( meshInfo, accessorIdx, texCoordString.str(), Property::VECTOR2 ); + } + + for( unsigned int i = 0; i < meshInfo.attribute.COLOR.size(); ++i ) + { + int accessorIdx = meshInfo.attribute.COLOR[i]; + if( accessorIdx < 0 ) + { + break; + } + + if( mAccessorArray[accessorIdx].type == "VEC3" ) + { + Dali::Vector inputBufferData; + LoadDataFromAccessor( accessorIdx, inputBufferData ); + + Dali::Vector bufferData; + bufferData.Resize( inputBufferData.Size() ); + for( unsigned int i = 0; i( bufferData, "aVertexColor", Property::VECTOR4 ); + meshInfo.geometry.AddVertexBuffer( propertyBuffer ); + } + else if( mAccessorArray[accessorIdx].type == "VEC4" ) + { + SetAttributeBufferData( meshInfo, accessorIdx, "aVertexColor", Property::VECTOR4 ); + } + } + return true; +} + +void GltfLoader::SetMeshInfoAndCanonize( MeshInfo& meshInfo, Dali::Vector &vertexBufferData ) +{ + Vector3 pointMin( std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max() ); + Vector3 pointMax( std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::min() ); + unsigned int vertexSize = vertexBufferData.Size(); + for( unsigned int i = 0; iGetChild( "cameras" ); + if( !camerasNode ) + { + return; + } + + for( TreeNode::ConstIterator cameraIter = ( *camerasNode ).CBegin(); cameraIter != ( *camerasNode ).CEnd(); ++cameraIter ) + { + const TreeNode* tempNode = ( &( *cameraIter ).second )->GetChild( "name" ); + CameraInfo cameraInfo; + if( tempNode ) + { + ReadString( tempNode, cameraInfo.name ); + } + + tempNode = ( &( *cameraIter ).second )->GetChild( "type" ); + if( tempNode ) + { + ReadString( tempNode, cameraInfo.type ); + } + + CameraActor cameraActor = CameraActor::New(); + cameraActor.SetParentOrigin( ParentOrigin::CENTER ); + cameraActor.SetAnchorPoint( AnchorPoint::CENTER ); + + if( cameraInfo.type == "orthographic" ) + { + LoadOrthoGraphic( ( *cameraIter ).second, cameraInfo ); + float xMag_2 = cameraInfo.orthographic.xmag / 2.0; + float yMag_2 = cameraInfo.orthographic.ymag / 2.0; + cameraActor.SetOrthographicProjection( -xMag_2, xMag_2, yMag_2, -yMag_2, + cameraInfo.orthographic.znear, cameraInfo.orthographic.zfar ); + } + else if( cameraInfo.type == "perspective" ) + { + if( !LoadPerspective( ( *cameraIter ).second, cameraInfo ) ) + { + return; + } + cameraActor.SetProjectionMode( Dali::Camera::PERSPECTIVE_PROJECTION ); + cameraActor.SetFieldOfView( cameraInfo.perspective.yfov ); + cameraActor.SetNearClippingPlane( cameraInfo.perspective.znear ); + + if( cameraInfo.perspective.zfar > 0.0 ) + { + cameraActor.SetFarClippingPlane( cameraInfo.perspective.zfar ); + } + if( cameraInfo.perspective.aspectRatio > 0.0 ) + { + cameraActor.SetAspectRatio( cameraInfo.perspective.aspectRatio ); + } + } + + scene.AddCamera( cameraActor ); + } +} + +bool GltfLoader::LoadOrthoGraphic( const TreeNode& camera, CameraInfo& cameraInfo ) +{ + const TreeNode* orthographicNode = camera.GetChild( "orthographic" ); + if( !orthographicNode ) + { + return false; + } + + const TreeNode* tempNode; + tempNode = orthographicNode->GetChild( "xmag" ); + if( tempNode ) + { + ReadFloat( tempNode, cameraInfo.orthographic.xmag ); + } + + tempNode = orthographicNode->GetChild( "ymag" ); + if( tempNode ) + { + ReadFloat( tempNode, cameraInfo.orthographic.ymag ); + } + + tempNode = orthographicNode->GetChild( "zfar" ); + if( tempNode ) + { + ReadFloat( tempNode, cameraInfo.orthographic.zfar ); + } + + tempNode = orthographicNode->GetChild( "znear" ); + if( tempNode ) + { + ReadFloat( tempNode, cameraInfo.orthographic.znear ); + } + + return true; +} + +bool GltfLoader::LoadPerspective( const TreeNode& camera, CameraInfo& cameraInfo ) +{ + const TreeNode* perspectiveNode = camera.GetChild( "perspective" ); + if( !perspectiveNode ) + { + return false; + } + + const TreeNode* tempNode; + tempNode = perspectiveNode->GetChild( "aspectRatio" ); + if( tempNode ) + { + ReadFloat( tempNode, cameraInfo.perspective.aspectRatio ); + } + + tempNode = perspectiveNode->GetChild( "yfov" ); + if( tempNode ) + { + ReadFloat( tempNode, cameraInfo.perspective.yfov ); + } + + tempNode = perspectiveNode->GetChild( "zfar" ); + if( tempNode ) + { + ReadFloat( tempNode, cameraInfo.perspective.zfar ); + } + + tempNode = perspectiveNode->GetChild( "znear" ); + if( tempNode ) + { + ReadFloat( tempNode, cameraInfo.perspective.znear ); + } + + return true; +} + +bool GltfLoader::LoadSceneNodes( Scene& scene ) +{ + const TreeNode* sceneNode = mRoot->GetChild( "scene" ); + int sceneNum = 0; + if( sceneNode ) + { + sceneNum = sceneNode->GetInteger(); + } + + const TreeNode* scenesNode = mRoot->GetChild( "scenes" ); + if( !( scenesNode && ( mNodes = mRoot->GetChild( "nodes" ) ) ) ) + { + return false; + } + + const TreeNode* tempNode = Tidx( scenesNode, sceneNum ); + if( !tempNode ) + { + return false; + } + + tempNode = tempNode->GetChild( "nodes" ); + if( !tempNode ) + { + return false; + } + + for( TreeNode::ConstIterator nodeIter = ( *tempNode ).CBegin(); nodeIter != ( *tempNode ).CEnd(); ++nodeIter ) + { + Actor actor = AddNode( scene, ( ( *nodeIter ).second ).GetInteger() ); + actor.SetParentOrigin( ParentOrigin::CENTER ); + scene.GetRoot().Add( actor ); + } + + return true; +} + +Actor GltfLoader::AddNode( Scene& scene, int index ) +{ + const TreeNode* node = Tidx( mNodes, index ); + Actor actor = Actor::New(); + Vector3 actorSize( Vector3::ONE ); + + Vector3 translation = Vector3( 0.0, 0.0, 0.0 ); + Vector3 scale = Vector3( 1.0, 1.0, 1.0 ); + Quaternion orientation( Vector4( 0.0, 0.0, 0.0, 1.0 ) ); + + Vector3 anchorPoint = AnchorPoint::CENTER; + + const TreeNode* tempNode = NULL; + if( ( tempNode = node->GetChild( "translation" ) ) ) + { + float floatVec[3] = { 0.0, 0.0, 0.0 }; + if( tempNode && ReadVector( tempNode, floatVec, 3 ) ) + { + translation = Vector3( floatVec[0], floatVec[1], floatVec[2] ); + } + } + + if( ( tempNode = node->GetChild( "scale" ) ) ) + { + float floatVec[3] = { 1.0, 1.0, 1.0 }; + if( tempNode && ReadVector( tempNode, floatVec, 3 ) ) + { + scale = Vector3( floatVec[0], floatVec[1], floatVec[2] ); + } + } + + if( ( tempNode = node->GetChild( "rotation" ) ) ) + { + float floatVec[4] = { 0.0, 0.0, 0.0, 1.0 }; + if( tempNode && ReadVector( tempNode, floatVec, 4 ) ) + { + orientation = Quaternion( Vector4( floatVec[0], floatVec[1], floatVec[2], floatVec[3] ) ); + } + } + + if( ( tempNode = node->GetChild( "matrix" ) ) ) + { + float floatVec[16] = { 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 }; + if( tempNode && ReadVector( tempNode, floatVec, 16 ) ) + { + Matrix nodeMatrix = Matrix( floatVec ); + nodeMatrix.GetTransformComponents( translation, orientation, scale ); + } + } + + if( ( tempNode = node->GetChild( "mesh" ) ) ) + { + MeshInfo meshInfo = mMeshArray[tempNode->GetInteger()]; + GLTF::MaterialInfo materialInfo = mMaterialArray[meshInfo.materialsIdx]; + bool isMaterial = ( meshInfo.materialsIdx >= 0 ); + + TextureSet textureSet; + textureSet = TextureSet::New(); + + int addIdx = 0; + int shaderTypeIndex = 0; + int maxMipmapLevel = 0; + bool isBaseColorTexture = false; + bool isMetallicRoughnessTexture = false; + bool isNormalTexture = false; + bool isOcclusionTexture = false; + bool isEmissiveTexture = false; + + std::string VERTEX_SHADER, FRAGMENT_SHADER; + VERTEX_SHADER = GLES_VERSION_300; + VERTEX_SHADER += PHYSICALLY_BASED_VERTEX_SHADER; + FRAGMENT_SHADER = GLES_VERSION_300; + + bool useIBL = ( scene.GetLightType() >= Toolkit::Scene::LightType::IMAGE_BASED_LIGHT ); + if( isMaterial ) + { + if( SetTextureAndSampler( textureSet, materialInfo.baseColorTexture.index, FRAGMENT_SHADER, DEFINE_BASECOLOR_TEXTURE, addIdx ) ) + { + shaderTypeIndex += static_cast( ShaderType::BASECOLOR_SHADER ); + isBaseColorTexture = true; + } + if( SetTextureAndSampler( textureSet, materialInfo.metallicRoughnessTexture.index, FRAGMENT_SHADER, DEFINE_METALLICROUGHNESS_TEXTURE, addIdx ) ) + { + shaderTypeIndex += static_cast( ShaderType::METALLICROUGHNESS_SHADER ); + isMetallicRoughnessTexture = true; + } + if( SetTextureAndSampler( textureSet, materialInfo.normalTexture.index, FRAGMENT_SHADER, DEFINE_NORMAL_TEXTURE, addIdx ) ) + { + shaderTypeIndex += static_cast( ShaderType::NORMAL_SHADER ); + isNormalTexture = true; + } + if( SetTextureAndSampler( textureSet, materialInfo.occlusionTexture.index, FRAGMENT_SHADER, DEFINE_OCCLUSION_TEXTURE, addIdx ) ) + { + shaderTypeIndex += static_cast( ShaderType::OCCLUSION_SHADER ); + isOcclusionTexture = true; + } + if( SetTextureAndSampler( textureSet, materialInfo.emissiveTexture.index, FRAGMENT_SHADER, DEFINE_EMIT_TEXTURE, addIdx ) ) + { + shaderTypeIndex += static_cast( ShaderType::EMIT_SHADER ); + isEmissiveTexture = true; + } + + if( useIBL ) + { + shaderTypeIndex += static_cast( ShaderType::IBL_SHADER ); + FRAGMENT_SHADER += DEFINE_IBL_TEXTURE; + + Sampler sampler = Sampler::New(); + sampler.SetFilterMode( FilterMode::DEFAULT, FilterMode::DEFAULT ); + sampler.SetWrapMode( WrapMode::REPEAT, WrapMode::REPEAT, WrapMode::REPEAT ); + + textureSet.SetTexture( addIdx, scene.GetBRDFTexture() ); + textureSet.SetSampler( addIdx++, sampler ); + Sampler samplerIBL = Sampler::New(); + samplerIBL.SetFilterMode( FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR ); + samplerIBL.SetWrapMode( WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE ); + textureSet.SetTexture( addIdx, scene.GetDiffuseTexture() ); + textureSet.SetSampler( addIdx++, samplerIBL ); + Texture specularTexture = scene.GetSpecularTexture(); + textureSet.SetTexture( addIdx, specularTexture ); + textureSet.SetSampler( addIdx++, samplerIBL ); + + int textureSize = std::min( specularTexture.GetWidth(), specularTexture.GetHeight() ); + maxMipmapLevel = 0; + while( textureSize >= 1 ) + { + maxMipmapLevel++; + textureSize /= 2; + } + } + } + + FRAGMENT_SHADER += PHYSICALLY_BASED_FRAGMENT_SHADER; + if( !mShaderCache[shaderTypeIndex] ) + { + mShaderCache[shaderTypeIndex] = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER ); + scene.AddShader( mShaderCache[shaderTypeIndex] ); + } + Shader shader = mShaderCache[shaderTypeIndex]; + + Renderer renderer = Renderer::New( meshInfo.geometry, shader ); + renderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::ON ); + renderer.SetProperty( Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON ); + renderer.SetTextures( textureSet ); + + anchorPoint = meshInfo.pivot; + actor.SetAnchorPoint( anchorPoint ); + + actor.SetSize( Vector3( meshInfo.size.x, meshInfo.size.y, meshInfo.size.z ) ); + actor.AddRenderer( renderer ); + + actor.SetScale( scale ); + actor.RotateBy( orientation ); + actor.SetPosition( translation ); + + shader.RegisterProperty( "uLightType", ( scene.GetLightType() & ~Toolkit::Scene::LightType::IMAGE_BASED_LIGHT ) ); + shader.RegisterProperty( "uLightVector", scene.GetLightVector() ); + shader.RegisterProperty( "uLightColor", scene.GetLightColor() ); + + actor.RegisterProperty( "uIsColor", meshInfo.attribute.COLOR.size() > 0 ); + if( isMaterial ) + { + actor.RegisterProperty( "uBaseColorFactor", materialInfo.baseColorFactor ); + actor.RegisterProperty( "uMetallicRoughnessFactors", Vector2( materialInfo.metallicFactor, materialInfo.roughnessFactor ) ); + + if( materialInfo.alphaMode == "OPAQUE" ) + { + actor.RegisterProperty( "alphaMode", 0 ); + } + else if( materialInfo.alphaMode == "MASK" ) + { + actor.RegisterProperty( "alphaMode", 1 ); + } + else + { + actor.RegisterProperty( "alphaMode", 2 ); + } + actor.RegisterProperty( "alphaCutoff", materialInfo.alphaCutoff ); + + if( isBaseColorTexture ) + { + actor.RegisterProperty( "uBaseColorTexCoordIndex", materialInfo.baseColorTexture.texCoord ); + } + if( isMetallicRoughnessTexture ) + { + actor.RegisterProperty( "uMetallicRoughnessTexCoordIndex", materialInfo.metallicRoughnessTexture.texCoord ); + } + if( isNormalTexture ) + { + actor.RegisterProperty( "uNormalScale", materialInfo.normalTexture.value ); + actor.RegisterProperty( "uNormalTexCoordIndex", materialInfo.normalTexture.texCoord ); + } + if( isOcclusionTexture ) + { + actor.RegisterProperty( "uOcclusionTexCoordIndex", materialInfo.occlusionTexture.texCoord ); + actor.RegisterProperty( "uOcclusionStrength", materialInfo.occlusionTexture.value ); + } + if( isEmissiveTexture ) + { + actor.RegisterProperty( "uEmissiveTexCoordIndex", materialInfo.emissiveTexture.texCoord ); + actor.RegisterProperty( "uEmissiveFactor", materialInfo.emissiveFactor ); + } + } + + if( isMaterial && useIBL ) + { + actor.RegisterProperty( "uScaleIBLAmbient", scene.GetIBLScaleFactor() ); + actor.RegisterProperty( "uMipmapLevel", static_cast( maxMipmapLevel ) ); + } + } + else + { + actor.SetAnchorPoint( AnchorPoint::CENTER ); + actor.SetPosition( translation ); + actor.RotateBy( orientation ); + actor.SetSize( actorSize ); + } + + tempNode = node->GetChild( "camera" ); + if( tempNode ) + { + int cameraNum = tempNode->GetInteger(); + actor.Add( scene.GetCamera( cameraNum ) ); + } + + tempNode = node->GetChild( "name" ); + if( tempNode ) + { + std::string nameString; + ReadString( tempNode, nameString ); + actor.SetName( nameString ); + } + + SetActorCache( actor, index ); + if( ( tempNode = node->GetChild( "children" ) ) ) + { + for( TreeNode::ConstIterator childIter = ( *tempNode ).CBegin(); childIter != ( *tempNode ).CEnd(); ++childIter ) + { + Actor childActor = AddNode( scene, ( ( *childIter ).second ).GetInteger() ); + childActor.SetParentOrigin( anchorPoint ); + actor.Add( childActor ); + } + } + + return actor; +} + +void GltfLoader::SetActorCache( Actor& actor, const int index ) +{ + if( mActorCache.size() < static_cast( index + 1 ) ) + { + mActorCache.resize( index + 1 ); + } + mActorCache[index] = actor; +} + +bool GltfLoader::SetTextureAndSampler( TextureSet& textureSet, int textureIdx, std::string& toShader, std::string shader, int& addIdx ) +{ + if( textureIdx >= 0 ) + { + toShader += shader; + TextureInfo textureInfo = mTextureArray[textureIdx]; + if( textureInfo.sourceIdx >= 0 ) + { + textureSet.SetTexture( addIdx, mSourceArray[textureInfo.sourceIdx] ); + } + if( textureInfo.samplerIdx >= 0 ) + { + textureSet.SetSampler( addIdx, mSamplerArray[textureInfo.samplerIdx] ); + } + else + { + Sampler sampler = Sampler::New(); + sampler.SetFilterMode( FilterMode::DEFAULT, FilterMode::DEFAULT ); + sampler.SetWrapMode( WrapMode::REPEAT, WrapMode::REPEAT, WrapMode::REPEAT ); + textureSet.SetSampler( addIdx, sampler ); + } + addIdx++; + return true; + } + return false; +} + +bool GltfLoader::LoadAnimation( Scene& scene ) +{ + const TreeNode* animationsNode = mRoot->GetChild( "animations" ); + if( !animationsNode ) + { + return true; + } + + for( TreeNode::ConstIterator animationIter = ( *animationsNode ).CBegin(); animationIter != ( *animationsNode ).CEnd(); ++animationIter ) + { + const TreeNode* nameNode = ( &( *animationIter ).second )->GetChild( "name" ); + AnimationInfo animationInfo; + if( nameNode ) + { + ReadString( nameNode, animationInfo.name ); + } + + Property::Index propIndex = Property::INVALID_INDEX; + LoadAnimationChannels( ( *animationIter ).second, animationInfo ); + if( animationInfo.channelArray.size() == 0 ) + { + continue; + } + + LoadAnimationSamplers( ( *animationIter ).second, animationInfo ); + + int channelNum = animationInfo.channelArray.size(); + for( int i = 0; i < channelNum; i++ ) + { + AnimationChannelInfo currentChannel = animationInfo.channelArray[i]; + + if( currentChannel.path == "rotation" ) + { + propIndex = Dali::Actor::Property::ORIENTATION; + } + else if( currentChannel.path == "translation" ) + { + propIndex = Dali::Actor::Property::POSITION; + } + else if( currentChannel.path == "scale" ) + { + propIndex = Dali::Actor::Property::SCALE; + } + + float duration = 0.0f; + KeyFrames keyframes = KeyFrames::New(); + if( propIndex == Dali::Actor::Property::ORIENTATION ) + { + duration = LoadKeyFrames( animationInfo.samplerArray[currentChannel.sampler], propIndex, keyframes ); + } + else + { + duration = LoadKeyFrames( animationInfo.samplerArray[currentChannel.sampler], propIndex, keyframes ); + } + + Animation animation = Animation::New( duration ); + Animation::Interpolation interpolation = Animation::Interpolation::Linear; + if( animationInfo.samplerArray[currentChannel.sampler].interpolation == "CUBICSPLINE" ) + { + interpolation = Animation::Interpolation::Cubic; + } + if( animationInfo.samplerArray[currentChannel.sampler].interpolation == "STEP" ) + { + } + + animation.AnimateBetween( Property( mActorCache[currentChannel.targetNode], propIndex ), keyframes, interpolation ); + + animation.SetLooping( false ); + scene.AddAnimation( animation ); + } + } + + return true; +} + +bool GltfLoader::LoadAnimationChannels( const TreeNode& animation, AnimationInfo& animationInfo ) +{ + const TreeNode* channelsNode = animation.GetChild( "channels" ); + if( !channelsNode ) + { + return false; + } + + for( TreeNode::ConstIterator channelIter = ( *channelsNode ).CBegin(); channelIter != ( *channelsNode ).CEnd(); ++channelIter ) + { + AnimationChannelInfo animationChannelInfo; + const TreeNode* channelNode = ( &( *channelIter ).second ); + const TreeNode* samplerNode = channelNode->GetChild( "sampler" ); + if( samplerNode ) + { + animationChannelInfo.sampler = samplerNode->GetInteger(); + } + + const TreeNode* targetNode = channelNode->GetChild( "target" ); + if( targetNode ) + { + const TreeNode* tempNode = targetNode->GetChild( "node" ); + if( tempNode ) + { + animationChannelInfo.targetNode = tempNode->GetInteger(); + } + else + { + continue; + } + + tempNode = targetNode->GetChild( "path" ); + if( tempNode ) + { + ReadString( tempNode, animationChannelInfo.path ); + } + } + + animationInfo.channelArray.push_back( animationChannelInfo ); + } + return true; +} + +bool GltfLoader::LoadAnimationSamplers( const TreeNode& animation, AnimationInfo& animationInfo ) +{ + const TreeNode* samplersNode = animation.GetChild( "samplers" ); + if( !samplersNode ) + { + return false; + } + + for( TreeNode::ConstIterator sampler = ( *samplersNode ).CBegin(); sampler != ( *samplersNode ).CEnd(); ++sampler ) + { + AnimationSamplerInfo animationSamplerInfo; + const TreeNode* samplerNode = ( &( *sampler ).second ); + const TreeNode* tempNode = samplerNode->GetChild( "input" ); + if( tempNode ) + { + animationSamplerInfo.input = tempNode->GetInteger(); + } + + tempNode = samplerNode->GetChild( "output" ); + if( tempNode ) + { + animationSamplerInfo.output = tempNode->GetInteger(); + } + + tempNode = samplerNode->GetChild( "interpolation" ); + if( tempNode ) + { + ReadString( tempNode, animationSamplerInfo.interpolation ); + } + + animationInfo.samplerArray.push_back( animationSamplerInfo ); + } + + return true; +} + +// Template functions +template +bool GltfLoader::ReadBinFile( Vector &dataBuffer, std::string url, int offset, int count ) +{ + dataBuffer.Resize( count ); + FILE* fp = fopen( url.c_str(), "rb" ); + if( NULL == fp ) + { + return false; + } + fseek( fp, offset, SEEK_SET ); + ssize_t result = fread( &dataBuffer[0], sizeof( T ), count, fp ); + fclose( fp ); + + return ( result >= 0 ); +} + +template +float GltfLoader::IntToFloat( T element, bool normalize ) +{ + if( !normalize ) + { + return static_cast( element ); + } + + if( std::is_same::value ) + { + return std::max( static_cast( element ) / 127.0, -1.0 ); + } + if( std::is_same::value ) + { + return static_cast( element ) / 255.0; + } + if( std::is_same::value ) + { + return std::max( static_cast( element ) / 32767.0, -1.0 ); + } + if( std::is_same::value ) + { + return static_cast( element ) / 65535.0; + } + return -1.0; +} + +template +void GltfLoader::FitBuffer( Dali::Vector& bufferDestiny, Dali::Vector& bufferSource, int bufferSize, int elementNumOfByteStride, bool normalize ) +{ + bufferDestiny.Resize( bufferSize ); + int count = bufferSource.Size() / elementNumOfByteStride; + for( int i = 0; i( bufferSource[i * elementNumOfByteStride] ); + } +} + +template +void GltfLoader::FitBuffer( Dali::Vector& bufferDestiny, Dali::Vector& bufferSource, int bufferSize, int elementNumOfByteStride, bool normalize ) +{ + bufferDestiny.Resize( bufferSize ); + int count = bufferSource.Size() / elementNumOfByteStride; + for( int i = 0; i +void GltfLoader::FitBuffer( Dali::Vector& bufferDestiny, Dali::Vector& bufferSource, int bufferSize, int elementNumOfByteStride, bool normalize ) +{ + bufferDestiny.Resize( bufferSize ); + int count = bufferSource.Size() / elementNumOfByteStride; + for( int i = 0; i +void GltfLoader::FitBuffer( Dali::Vector& bufferDestiny, Dali::Vector& bufferSource, int bufferSize, int elementNumOfByteStride, bool normalize ) +{ + bufferDestiny.Resize( bufferSize ); + int count = bufferSource.Size() / elementNumOfByteStride; + for( int i = 0; i +void GltfLoader::LoadDataFromAccessor( int accessorIdx, Dali::Vector& bufferData ) +{ + AccessorInfo accessor = mAccessorArray[accessorIdx]; + BufferViewInfo bufferView = mBufferViewArray[accessor.bufferView]; + BufferInfo buffer = mBufferArray[bufferView.buffer]; + std::string load_uri = buffer.uri; + + // In the glTF 2.0 Specification, 5121 is UNSIGNED BYTE, 5123 is UNSIGNED SHORT + int elementByteSize = ( accessor.componentType <= 5121 ) ? 1 : + ( ( accessor.componentType <= 5123 ) ? 2 : 4 ); + int elementNum = 1; + if( accessor.type == "VEC2" ) + { + elementNum = 2; + } + else if( accessor.type == "VEC3" ) + { + elementNum = 3; + } + else if( accessor.type == "VEC4" || accessor.type == "MAT2" ) + { + elementNum = 4; + } + else if( accessor.type == "MAT3" ) + { + elementNum = 9; + } + else if( accessor.type == "MAT4" ) + { + elementNum = 16; + } + else + { + elementNum = 1; + } + int elementNumOfByteStride = elementNum; + if( bufferView.byteStride > 0 ) + { + elementNumOfByteStride = bufferView.byteStride / elementByteSize; + } + + /** + * glTF 2.0 Specification + * Component Type + * 5120 : BYTE + * 5121 : UNSIGNED_BYTE + * 5122 : SHORT + * 5123 : UNSIGNED_SHORT + * 5125 : UNSIGNED_INT + * 5126 : FLOAT + */ + if( accessor.componentType == 5120 ) + { + Dali::Vector inputBufferData; + ReadBinFile( inputBufferData, mPath + load_uri, bufferView.byteOffset + accessor.byteOffset, elementNumOfByteStride * accessor.count ); + FitBuffer( bufferData, inputBufferData, accessor.count, elementNumOfByteStride, accessor.normalized ); + } + else if( accessor.componentType == 5121 ) + { + Dali::Vector inputBufferData; + ReadBinFile( inputBufferData, mPath + load_uri, bufferView.byteOffset + accessor.byteOffset, elementNumOfByteStride * accessor.count ); + FitBuffer( bufferData, inputBufferData, accessor.count, elementNumOfByteStride, accessor.normalized ); + } + else if( accessor.componentType == 5122 ) + { + Dali::Vector inputBufferData; + ReadBinFile( inputBufferData, mPath + load_uri, bufferView.byteOffset + accessor.byteOffset, elementNumOfByteStride * accessor.count ); + FitBuffer( bufferData, inputBufferData, accessor.count, elementNumOfByteStride, accessor.normalized ); + } + else if( accessor.componentType == 5123 ) + { + Dali::Vector inputBufferData; + ReadBinFile( inputBufferData, mPath + load_uri, bufferView.byteOffset + accessor.byteOffset, elementNumOfByteStride * accessor.count ); + FitBuffer( bufferData, inputBufferData, accessor.count, elementNumOfByteStride, accessor.normalized ); + } + else if( accessor.componentType == 5125 ) + { + Dali::Vector inputBufferData; + ReadBinFile( inputBufferData, mPath + load_uri, bufferView.byteOffset + accessor.byteOffset, elementNumOfByteStride * accessor.count ); + FitBuffer( bufferData, inputBufferData, accessor.count, elementNumOfByteStride, accessor.normalized ); + } + else if( accessor.componentType == 5126 ) + { + Dali::Vector inputBufferData; + ReadBinFile( inputBufferData, mPath + load_uri, bufferView.byteOffset + accessor.byteOffset, elementNumOfByteStride * accessor.count ); + FitBuffer( bufferData, inputBufferData, accessor.count, elementNumOfByteStride, accessor.normalized ); + } +} + +template +PropertyBuffer GltfLoader::CreatePropertyBuffer( Vector bufferData, std::string map, int type ) +{ + Property::Map positionMap; + positionMap[map] = type; + + PropertyBuffer propertyBuffer = PropertyBuffer::New( positionMap ); + propertyBuffer.SetData( bufferData.Begin(), bufferData.Count() ); + return propertyBuffer; +} + + +void GltfLoader::SetVertexBufferData( MeshInfo& meshInfo, int accessorIdx, std::string map, int type ) +{ + if( accessorIdx >= 0 ) + { + Dali::Vector bufferData; + LoadDataFromAccessor( accessorIdx, bufferData ); + SetMeshInfoAndCanonize( meshInfo, bufferData ); + + PropertyBuffer propertyBuffer = CreatePropertyBuffer( bufferData, map, type ); + meshInfo.geometry.AddVertexBuffer( propertyBuffer ); + } +} + +template +void GltfLoader::SetAttributeBufferData( MeshInfo& meshInfo, int accessorIdx, std::string map, int type ) +{ + if( accessorIdx >= 0 ) + { + Dali::Vector bufferData; + LoadDataFromAccessor( accessorIdx, bufferData ); + + PropertyBuffer propertyBuffer = CreatePropertyBuffer( bufferData, map, type ); + meshInfo.geometry.AddVertexBuffer( propertyBuffer ); + } +} + +void GltfLoader::SetIndexBuffersData( MeshInfo& meshInfo, int indexIdx ) +{ + Dali::Vector indexBufferData; + LoadDataFromAccessor( indexIdx, indexBufferData ); + meshInfo.geometry.SetIndexBuffer( &indexBufferData[0], indexBufferData.Size() ); +} + +template +float GltfLoader::LoadKeyFrames( const AnimationSamplerInfo& currentSampler, const Property::Index propIndex, KeyFrames& keyframes ) +{ + Dali::Vector inputBufferData; + Dali::Vector outputBufferData; + + LoadDataFromAccessor( currentSampler.input, inputBufferData ); + LoadDataFromAccessor( currentSampler.output, outputBufferData ); + + int keyframeNum = inputBufferData.Size(); + float lengthAnimation = inputBufferData[keyframeNum - 1]; + for( int i = 0; i < keyframeNum; i++ ) + { + if( propIndex == Dali::Actor::Property::ORIENTATION ) + { + Vector4 vectorOrientation( outputBufferData[i] ); + float vW = vectorOrientation.w; + vW = ( vW < 0.0f ) ? std::max( vW, -1.0f ) : std::min( vW, 1.0f ); + vectorOrientation.w = vW; + keyframes.Add( inputBufferData[i] / lengthAnimation, Quaternion( Vector4( vectorOrientation ) ) ); + } + else if( propIndex == Dali::Actor::Property::POSITION ) + { + keyframes.Add( inputBufferData[i] / lengthAnimation, Vector3( outputBufferData[i] ) ); + } + else if( propIndex == Dali::Actor::Property::SCALE ) + { + keyframes.Add( inputBufferData[i] / lengthAnimation, Vector3( outputBufferData[i] ) ); + } + } + return lengthAnimation; +} + +// Utility functions +const TreeNode* GltfLoader::Tidx( const TreeNode *node, int index ) +{ + int i = 0; + for( TreeNode::ConstIterator it = ( *node ).CBegin(); it != ( *node ).CEnd(); ++it, ++i ) + { + if( i == index ) + { + return &( ( *it ).second ); + } + } + return NULL; +} + +bool GltfLoader::ReadBool( const TreeNode* node, bool& num ) +{ + if( !node ) + { + return false; + } + bool returnValue = false; + + if( node->GetType() == TreeNode::BOOLEAN ) + { + num = node->GetBoolean(); + returnValue = true; + } + + return returnValue; +} + +bool GltfLoader::ReadInt( const TreeNode* node, int& num ) +{ + if( !node ) + { + return false; + } + bool returnValue = false; + if( node->GetType() == TreeNode::INTEGER ) + { + num = node->GetInteger(); + returnValue = true; + } + else if( node->GetType() == TreeNode::FLOAT ) + { + num = node->GetFloat(); + returnValue = true; + } + + return returnValue; +} + +bool GltfLoader::ReadFloat( const TreeNode* node, float& num ) +{ + if( !node ) + { + return false; + } + bool returnValue = false; + + if( node->GetType() == TreeNode::FLOAT ) + { + num = node->GetFloat(); + returnValue = true; + } + else if( node->GetType() == TreeNode::INTEGER ) + { + int tempNum; + ReadInt( node, tempNum ); + num = static_cast( tempNum ); + returnValue = true; + } + + return returnValue; +} + +bool GltfLoader::ReadVector( const TreeNode* node, float* num, unsigned int size ) +{ + if( !node ) + { + return false; + } + bool returnValue = false; + + if( ( node->Size() >= size ) && ( node->GetType() == TreeNode::ARRAY ) ) + { + unsigned int offset = 0u; + for( TreeNode::ConstIterator it = node->CBegin(); offset < size; ++it, ++offset ) + { + const TreeNode& coord = ( *it ).second; + if( !ReadFloat( &coord, *( num + offset ) ) ) + { + return false; + } + } + returnValue = true; + } + + return returnValue; +} + +bool GltfLoader::ReadString( const TreeNode* node, std::string& strValue ) +{ + if( !node ) + { + return false; + } + bool returnValue = false; + if( node->GetType() == TreeNode::STRING ) + { + strValue = node->GetString(); + returnValue = true; + } + return returnValue; +} + +}//namespace Internal + +}//namespace Toolkit + +}//namespace Dali \ No newline at end of file diff --git a/dali-toolkit/internal/controls/scene/gltf-loader.h b/dali-toolkit/internal/controls/scene/gltf-loader.h new file mode 100644 index 0000000..2625e3d --- /dev/null +++ b/dali-toolkit/internal/controls/scene/gltf-loader.h @@ -0,0 +1,547 @@ +#ifndef DALI_TOOLKIT_INTERNAL_GLTF_LOADER_H +#define DALI_TOOLKIT_INTERNAL_GLTF_LOADER_H + +/* + * Copyright (c) 2018 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 + +using namespace Dali; +using namespace Dali::Toolkit; + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +namespace GLTF +{ + +enum ShaderType +{ + NO_TEXTURE_SHADER, + BASECOLOR_SHADER, + METALLICROUGHNESS_SHADER, + BASECOLOR_METALLICROUGHNESS_SHADER, + NORMAL_SHADER, + BASECOLOR_NORMAL_SHADER, + METALLICROUGHNESS_NORMAL_SHADER, + BASECOLOR_METALLICROUGHNESS_NORMAL_SHADER, + OCCLUSION_SHADER, + BASECOLOR_OCCLUSION_SHADER, + METALLICROUGHNESS_OCCLUSION_SHADER, + BASECOLOR_METALLICROUGHNESS_OCCLUSION_SHADER, + NORMAL_OCCLUSION_SHADER, + BASECOLOR_NORMAL_OCCLUSION_SHADER, + METALLICROUGHNESS_NORMAL_OCCLUSION_SHADER, + BASECOLOR_METALLICROUGHNESS_NORMAL_OCCLUSION_SHADER, + EMIT_SHADER, + BASECOLOR_EMIT_SHADER, + METALLICROUGHNESS_EMIT_SHADER, + BASECOLOR_METALLICROUGHNESS_EMIT_SHADER, + NORMAL_EMIT_SHADER, + BASECOLOR_NORMAL_EMIT_SHADER, + METALLICROUGHNESS_NORMAL_EMIT_SHADER, + BASECOLOR_METALLICROUGHNESS_NORMAL_EMIT_SHADER, + OCCLUSION_EMIT_SHADER, + BASECOLOR_OCCLUSION_EMIT_SHADER, + METALLICROUGHNESS_OCCLUSION_EMIT_SHADER, + BASECOLOR_METALLICROUGHNESS_OCCLUSION_EMIT_SHADER, + NORMAL_OCCLUSION_EMIT_SHADER, + BASECOLOR_NORMAL_OCCLUSION_EMIT_SHADER, + METALLICROUGHNESS_NORMAL_OCCLUSION_EMIT_SHADER, + BASECOLOR_METALLICROUGHNESS_NORMAL_OCCLUSION_EMIT_SHADER, + IBL_SHADER, + IBL_BASECOLOR_SHADER, + IBL_METALLICROUGHNESS_SHADER, + IBL_BASECOLOR_METALLICROUGHNESS_SHADER, + IBL_NORMAL_SHADER, + IBL_BASECOLOR_NORMAL_SHADER, + IBL_METALLICROUGHNESS_NORMAL_SHADER, + IBL_BASECOLOR_METALLICROUGHNESS_NORMAL_SHADER, + IBL_OCCLUSION_SHADER, + IBL_BASECOLOR_OCCLUSION_SHADER, + IBL_METALLICROUGHNESS_OCCLUSION_SHADER, + IBL_BASECOLOR_METALLICROUGHNESS_OCCLUSION_SHADER, + IBL_NORMAL_OCCLUSION_SHADER, + IBL_BASECOLOR_NORMAL_OCCLUSION_SHADER, + IBL_METALLICROUGHNESS_NORMAL_OCCLUSION_SHADER, + IBL_BASECOLOR_METALLICROUGHNESS_NORMAL_OCCLUSION_SHADER, + IBL_EMIT_SHADER, + IBL_BASECOLOR_EMIT_SHADER, + IBL_METALLICROUGHNESS_EMIT_SHADER, + IBL_BASECOLOR_METALLICROUGHNESS_EMIT_SHADER, + IBL_NORMAL_EMIT_SHADER, + IBL_BASECOLOR_NORMAL_EMIT_SHADER, + IBL_METALLICROUGHNESS_NORMAL_EMIT_SHADER, + IBL_BASECOLOR_METALLICROUGHNESS_NORMAL_EMIT_SHADER, + IBL_OCCLUSION_EMIT_SHADER, + IBL_BASECOLOR_OCCLUSION_EMIT_SHADER, + IBL_METALLICROUGHNESS_OCCLUSION_EMIT_SHADER, + IBL_BASECOLOR_METALLICROUGHNESS_OCCLUSION_EMIT_SHADER, + IBL_NORMAL_OCCLUSION_EMIT_SHADER, + IBL_BASECOLOR_NORMAL_OCCLUSION_EMIT_SHADER, + IBL_METALLICROUGHNESS_NORMAL_OCCLUSION_EMIT_SHADER, + IBL_BASECOLOR_METALLICROUGHNESS_NORMAL_OCCLUSION_EMIT_SHADER, + SHADER_TYPE_MAX = IBL_BASECOLOR_METALLICROUGHNESS_NORMAL_OCCLUSION_EMIT_SHADER +}; + +struct BufferInfo +{ + BufferInfo() + : byteLength( -1 ), + uri( "" ), + name( "" ) + { + } + + ~BufferInfo() + { + } + + int byteLength; + std::string uri; + std::string name; +}; + +struct BufferViewInfo +{ + BufferViewInfo() + : buffer( -1 ), + byteOffset( 0 ), + byteLength( 0 ), + byteStride( 0 ), + target( 0 ), + name( "" ) + { + } + + ~BufferViewInfo() + { + } + + int buffer; + int byteOffset; + int byteLength; + int byteStride; + int target; + std::string name; +}; + +struct TextureInfo +{ + TextureInfo() + : sourceIdx( -1 ), + samplerIdx( -1 ) + { + } + + ~TextureInfo() + { + } + int sourceIdx; + int samplerIdx; +}; + +struct PbrTextureInfo +{ + PbrTextureInfo() + : index( -1 ), + texCoord( 0 ), + value( 0.0 ) + { + } + ~PbrTextureInfo() + { + } + + int index; + int texCoord; + float value; +}; + +struct MaterialInfo +{ + MaterialInfo() + : baseColorFactor( 1, 1, 1, 1 ), + metallicFactor( 1.0 ), + roughnessFactor( 1.0 ), + emissiveFactor( 0.0, 0.0, 0.0 ), + alphaMode( "OPAQUE" ), + alphaCutoff( 0.5 ), + doubleSided( false ), + name( "" ) + { + } + + ~MaterialInfo() + { + } + + Vector4 baseColorFactor; + float metallicFactor; + float roughnessFactor; + Vector3 emissiveFactor; + std::string alphaMode; + float alphaCutoff; + bool doubleSided; + + PbrTextureInfo baseColorTexture; + PbrTextureInfo metallicRoughnessTexture; + PbrTextureInfo normalTexture; + PbrTextureInfo occlusionTexture; + PbrTextureInfo emissiveTexture; + + std::string name; + //need to add max, min +}; + +struct AccessorInfo +{ + AccessorInfo() + : bufferView( -1 ), + byteOffset( 0 ), + componentType( -1 ), + normalized( false ), + count( 0 ), + type( "" ), + max( 0 ), + min( 0 ), + name( "" ) + { + } + + ~AccessorInfo() + { + } + + int bufferView; + int byteOffset; + int componentType; + bool normalized; + int count; + std::string type; + int max; + int min; + std::string name; + //need to add max, min +}; + +struct Attribute +{ + Attribute() + : POSITION( -1 ), + NORMAL( -1 ), + TANGENT( -1 ) + { + } + + ~Attribute() + { + } + + int POSITION; + int NORMAL; + int TANGENT; + + std::vector TEXCOORD; + std::vector COLOR; +}; + +struct MeshInfo +{ + MeshInfo() + : indicesIdx( -1 ), + materialsIdx( -1 ), + mode( 4 ) + { + } + + ~MeshInfo() + { + } + Geometry geometry; + std::string name; + + int indicesIdx; + int materialsIdx; + int mode; + + Vector3 size; + Vector3 pivot; + + Attribute attribute; + //need to add max, min +}; + +struct AnimationChannelInfo +{ + AnimationChannelInfo() + : sampler( -1 ), + targetNode( -1 ), + path( "" ) + { + } + + ~AnimationChannelInfo() + { + } + + int sampler; + int targetNode; + std::string path; + +}; + +struct AnimationSamplerInfo +{ + AnimationSamplerInfo() + : input( -1 ), + output( -1 ), + interpolation( "" ) + { + } + + ~AnimationSamplerInfo() + { + } + + int input; + int output; + std::string interpolation; +}; + +struct AnimationInfo +{ + AnimationInfo() + : name( "" ) + { + } + + ~AnimationInfo() + { + } + + std::string name; + std::vector channelArray; + std::vector samplerArray; +}; + +struct OrthographicInfo +{ + OrthographicInfo() + : xmag( 0.0f ), + ymag( 0.0f ), + zfar( 0.0f ), + znear( 0.0f ) + { + } + + ~OrthographicInfo() + { + } + + float xmag; + float ymag; + float zfar; + float znear; +}; + +struct PerspectiveInfo +{ + PerspectiveInfo() + : aspectRatio( 0.0f ), + yfov( 0.0f ), + zfar( 0.0f ), + znear( 0.0f ) + { + } + + ~PerspectiveInfo() + { + } + + float aspectRatio; + float yfov; + float zfar; + float znear; +}; + +struct CameraInfo +{ + CameraInfo() + : name( "" ), + type( "" ) + { + } + + ~CameraInfo() + { + } + + std::string name; + std::string type; + OrthographicInfo orthographic; + PerspectiveInfo perspective; +}; + +} // namespace GLTF + +/** + * + * GltfLoader is a class to parse glTf, to load data from file, and to generate Scene. + * This glTF loader supports glTF 2.0 features. + * + * @remarks glTF loader didn't support such features. + * - Sparse accessor + * - Morphing + * - Skeletal Animation + * These features will be supported soon. + * + */ +class GltfLoader +{ +public: + + /** + * @brief Create an uninitialized GltfLoader. + */ + GltfLoader(); + + /** + * @brief Destructor + */ + ~GltfLoader(); + + /** + * @brief Load Scene from scene format file(e.g., glTF). + * @param[in] filePath Path of scene format file. + * @param[in] scene Scene data loaded from file. + * @return true if scene is successfully loaded + */ + bool LoadScene( const std::string& filePath, Internal::Scene& scene ); + +private: + bool ParseGltf( const std::string& filePath ); + bool LoadAssets(); + + bool LoadBinaryData( const TreeNode* root ); + bool LoadBuffer( const TreeNode& buffer ); + bool LoadBufferView( const TreeNode& buffer ); + bool LoadAccessor( const TreeNode& buffer ); + + bool LoadTextureArray( const TreeNode* root ); + Texture LoadTexture( const char* imageUrl, bool generateMipmaps ); + Sampler LoadSampler( const TreeNode& samplerNode ); + FilterMode::Type GetFilterMode( int mode ); + WrapMode::Type GetWrapMode( int mode ); + + bool LoadMaterialSetArray( const TreeNode* root ); + bool LoadPbrMetallicRoughness( const TreeNode& material, GLTF::MaterialInfo& materialInfo ); + + bool LoadMeshArray( const TreeNode* root ); + bool LoadPrimitive( const TreeNode& mesh, GLTF::MeshInfo& meshInfo ); + bool LoadAttribute( const TreeNode* attribute, GLTF::MeshInfo& meshInfo ); + bool SetGeometry( GLTF::MeshInfo& meshInfo ); + void SetMeshInfoAndCanonize( GLTF::MeshInfo& meshInfo, Dali::Vector &vertexBufferData ); + + bool CreateScene( Internal::Scene& scene ); + + void LoadCamera( Scene& scene ); + bool LoadOrthoGraphic( const TreeNode& camera, GLTF::CameraInfo& cameraInfo ); + bool LoadPerspective( const TreeNode& camera, GLTF::CameraInfo& cameraInfo ); + + bool LoadSceneNodes( Scene& scene ); + Actor AddNode( Scene& scene, int index ); + void SetActorCache( Actor& actor, const int index ); + bool SetTextureAndSampler( TextureSet& textureSet, int textureIdx, std::string& toShader, std::string shader, int& addIdx ); + + bool LoadAnimation( Scene& scene ); + bool LoadAnimationChannels( const TreeNode& animation, GLTF::AnimationInfo& animationInfo ); + bool LoadAnimationSamplers( const TreeNode& animation, GLTF::AnimationInfo& animationInfo ); + + // template functions + template + bool ReadBinFile( Vector &dataBuffer, std::string url, int offset, int count ); + template + float IntToFloat( T element, bool normalize ); + template + void FitBuffer( Dali::Vector& bufferDestiny, Dali::Vector& bufferSource, int bufferSize, int elementNumOfByteStride, bool normalize ); + template + void FitBuffer( Dali::Vector& bufferDestiny, Dali::Vector& bufferSource, int bufferSize, int elementNumOfByteStride, bool normalize ); + template + void FitBuffer( Dali::Vector& bufferDestiny, Dali::Vector& bufferSource, int bufferSize, int elementNumOfByteStride, bool normalize ); + template + void FitBuffer( Dali::Vector& bufferDestiny, Dali::Vector& bufferSource, int bufferSize, int elementNumOfByteStride, bool normalize ); + template + void LoadDataFromAccessor( int accessorIdx, Dali::Vector& bufferData ); + template + PropertyBuffer CreatePropertyBuffer( Vector bufferData, std::string map, int type ); + template + void SetAttributeBufferData( GLTF::MeshInfo& meshInfo, int accessorIdx, std::string map, int type ); + template + float LoadKeyFrames( const GLTF::AnimationSamplerInfo& currentSampler, const Property::Index propIndex, KeyFrames& keyframes ); + + void SetIndexBuffersData( GLTF::MeshInfo& meshInfo, int indexIdx ); + void SetVertexBufferData( GLTF::MeshInfo& meshInfo, int accessorIdx, std::string map, int type ); + + // utility functions + const TreeNode* Tidx( const TreeNode *node, int index ); + bool ReadBool( const TreeNode* node, bool& num ); + bool ReadInt( const TreeNode* node, int& num ); + bool ReadFloat( const TreeNode* node, float& num ); + bool ReadVector( const TreeNode* node, float* num, unsigned int size ); + bool ReadString( const TreeNode* node, std::string& strValue ); + +public: + void InitGltf(); + +private: + Dali::Toolkit::JsonParser mParser; + const TreeNode* mNodes; + const TreeNode* mRoot; + + std::string mPath; + + std::vector mActorCache; + Shader mShaderCache[GLTF::ShaderType::SHADER_TYPE_MAX + 1]; + + std::vector mBufferArray; + std::vector mBufferViewArray; + std::vector mAccessorArray; + + std::vector mMeshArray; + std::vector mMaterialArray; + std::vector mTextureArray; + + std::vector mSourceArray; + std::vector mSamplerArray; +}; + +}//namespace Internal + +}//namespace Toolkit + +}//namespace Dali + +#endif // DALI_TOOLKIT_INTERNAL_GLTF_LOADER_H diff --git a/dali-toolkit/internal/controls/scene/gltf-shader.h b/dali-toolkit/internal/controls/scene/gltf-shader.h new file mode 100644 index 0000000..3eaa2b1 --- /dev/null +++ b/dali-toolkit/internal/controls/scene/gltf-shader.h @@ -0,0 +1,360 @@ +#ifndef DALI_TOOLKIT_INTERNAL_GLTF_SHADER_H +#define DALI_TOOLKIT_INTERNAL_GLTF_SHADER_H + +/* + * Belows Vertex Shader and Fragment Shader code are based off glTF WebGL PBR. + * https://github.com/KhronosGroup/glTF-WebGL-PBR/ + * + * Copyright (c) 2016-2017 Mohamad Moneimne and Contributors + * + * 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. + */ + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +const char* GLES_VERSION_300 = { + "#version 300 es\n\n" + "precision highp float;\n\n" +}; + +const char* DEFINE_BASECOLOR_TEXTURE = { + "#define TEXTURE_BASECOLOR\n\n" + "uniform sampler2D uBaseColorSampler;\n" + "uniform int uBaseColorTexCoordIndex;\n\n" +}; + +const char* DEFINE_METALLICROUGHNESS_TEXTURE = { + "#define TEXTURE_METALLICROUGHNESS\n\n" + "uniform sampler2D uMetallicRoughnessSampler;\n" + "uniform int uMetallicRoughnessTexCoordIndex;\n\n" +}; + +const char* DEFINE_NORMAL_TEXTURE = { + "#define TEXTURE_NORMAL\n\n" + "uniform sampler2D uNormalSampler;\n" + "uniform float uNormalScale;\n" + "uniform int uNormalTexCoordIndex;\n\n" +}; + +const char* DEFINE_OCCLUSION_TEXTURE = { + "#define TEXTURE_OCCLUSION\n\n" + "uniform sampler2D uOcclusionSampler;\n" + "uniform int uOcclusionTexCoordIndex;\n" + "uniform float uOcclusionStrength;\n\n" +}; + +const char* DEFINE_EMIT_TEXTURE = { + "#define TEXTURE_EMIT\n\n" + "uniform sampler2D uEmissiveSampler;\n" + "uniform int uEmissiveTexCoordIndex;\n" + "uniform vec3 uEmissiveFactor;\n\n" +}; + +const char* DEFINE_IBL_TEXTURE = { + "#define TEXTURE_IBL\n\n" + "uniform sampler2D ubrdfLUT;\n" + "uniform samplerCube uDiffuseEnvSampler;\n" + "uniform samplerCube uSpecularEnvSampler;\n" + "uniform vec4 uScaleIBLAmbient;\n" + "uniform highp float uMipmapLevel;\n" +}; + +const char* PHYSICALLY_BASED_VERTEX_SHADER = { + "in highp vec3 aPosition;\n" + "in highp vec2 aTexCoord0;\n" + "in highp vec2 aTexCoord1;\n" + "in highp vec3 aNormal;\n" + "in highp vec4 aTangent;\n" + "in highp vec4 aVertexColor;\n" + + "uniform mediump vec3 uSize;\n" + "uniform mediump mat4 uModelMatrix;\n" + "uniform mediump mat4 uViewMatrix;\n" + "uniform mediump mat4 uProjection;\n" + "uniform mediump mat4 uMvpMatrix;\n" + "uniform mediump mat3 uNormalMatrix;\n" + "uniform mediump int uLightType;\n" + "uniform mediump vec3 uLightVector;\n" + "uniform mediump int uIsColor;\n" + + "out vec2 vUV[2];\n" + "out mat3 vTBN;\n" + "out vec4 vColor;\n" + "flat out int visLight;\n" + "out vec3 vLightDirection;\n" + "out vec3 vPositionToCamera;\n" + + "void main()\n" + "{\n" + " vec4 invY = vec4(1.0, -1.0, 1.0, 1.0);\n" + " vec4 positionW = uModelMatrix * vec4( aPosition * uSize, 1.0 );\n" + " vec4 positionV = uViewMatrix * ( invY * positionW );\n" + + " vPositionToCamera = transpose( mat3( uViewMatrix ) ) * ( -vec3( positionV.xyz / positionV.w ) );\n" + " vPositionToCamera *= vec3( invY );\n" + + " vec3 bitangent = cross(aNormal, aTangent.xyz) * aTangent.w;\n" + " vTBN = mat3( uModelMatrix ) * mat3(aTangent.xyz, bitangent, aNormal);\n" + + " vUV[0] = aTexCoord0;\n" + " vUV[1] = aTexCoord1;\n" + + " visLight = 0;\n" + " if( uLightType == 1 )\n" + " {\n" + " vLightDirection = ( invY.xyz * uLightVector ) - ( positionW.xyz / positionW.w );\n" + " }\n" + " else if( uLightType == 2 )\n" + " {\n" + " vLightDirection = -( invY.xyz * uLightVector );\n" + " }\n" + " else\n" + " {\n" + " visLight = 0;\n" + " }\n" + + " vColor = vec4( 1.0 );\n" + " if( uIsColor == 1 )\n" + " {\n" + " vColor = aVertexColor;\n" + " }\n" + + " gl_Position = uProjection * positionV;\n" // needs w for proper perspective correction + " gl_Position = gl_Position/gl_Position.w;\n" + "}\n" +}; + +const char* PHYSICALLY_BASED_FRAGMENT_SHADER = { + "uniform vec3 uLightColor;\n" + "uniform vec4 uBaseColorFactor;\n" + "uniform vec2 uMetallicRoughnessFactors;\n" + "uniform int alphaMode;\n" + "uniform float alphaCutoff;\n" + + "in vec2 vUV[2];\n" + "in mat3 vTBN;\n" + "in vec4 vColor;\n" + "flat in int visLight;\n" + "in vec3 vLightDirection;\n" + "in vec3 vPositionToCamera;\n" + + "out vec4 FragColor;" + + "struct PBRInfo\n" + "{\n" + " float NdotL;\n" // cos angle between normal and light direction + " float NdotV;\n" // cos angle between normal and view direction + " float NdotH;\n" // cos angle between normal and half vector + " float LdotH;\n" // cos angle between light direction and half vector + " float VdotH;\n" // cos angle between view direction and half vector + " float perceptualRoughness;\n" // roughness value, as authored by the model creator (input to shader) + " float metalness;\n" // metallic value at the surface + " vec3 reflectance0;\n" // full reflectance color (normal incidence angle) + " vec3 reflectance90;\n" // reflectance color at grazing angle + " float alphaRoughness;\n" // roughness mapped to a more linear change in the roughness (proposed by [2]) + " vec3 diffuseColor;\n" // color contribution from diffuse lighting + " vec3 specularColor;\n" // color contribution from specular lighting + "};\n" + + "const float M_PI = 3.141592653589793;\n" + "const float c_MinRoughness = 0.04;\n" + + "vec3 getNormal()\n" + "{\n" + "#ifdef TEXTURE_NORMAL\n" + " vec3 n = texture( uNormalSampler, vUV[uNormalTexCoordIndex] ).rgb;\n" + " n = normalize( vTBN * ( ( 2.0 * n - 1.0 ) * vec3( uNormalScale, uNormalScale, 1.0 ) ) );\n" + "#else\n" + " vec3 n = normalize( vTBN[2].xyz );\n" + "#endif\n" + " return n;\n" + "}\n" + + "vec3 specularReflection( PBRInfo pbrInputs )\n" + "{\n" + " return pbrInputs.reflectance0 + ( pbrInputs.reflectance90 - pbrInputs.reflectance0 ) * pow( clamp( 1.0 - pbrInputs.VdotH, 0.0, 1.0 ), 5.0 );\n" + "}\n" + + "float geometricOcclusion( PBRInfo pbrInputs )\n" + "{\n" + " float NdotL = pbrInputs.NdotL;\n" + " float NdotV = pbrInputs.NdotV;\n" + " float r = pbrInputs.alphaRoughness;\n" + + " float attenuationL = 2.0 * NdotL / (NdotL + sqrt(r * r + (1.0 - r * r) * (NdotL * NdotL)));\n" + " float attenuationV = 2.0 * NdotV / (NdotV + sqrt(r * r + (1.0 - r * r) * (NdotV * NdotV)));\n" + " return attenuationL * attenuationV;\n" + "}\n" + + "float microfacetDistribution(PBRInfo pbrInputs)\n" + "{\n" + " float roughnessSq = pbrInputs.alphaRoughness * pbrInputs.alphaRoughness;\n" + " float f = (pbrInputs.NdotH * roughnessSq - pbrInputs.NdotH) * pbrInputs.NdotH + 1.0;\n" + " return roughnessSq / (M_PI * f * f);\n" + "}\n" + + "vec3 linear( vec3 color )\n" + "{\n" + " return pow(color,vec3(2.2));\n" + "}\n" + + "void main()\n" + "{\n" + // Metallic and Roughness material properties are packed together + // In glTF, these factors can be specified by fixed scalar values + // or from a metallic-roughness map + " float metallic = uMetallicRoughnessFactors.x;\n" + " float perceptualRoughness = uMetallicRoughnessFactors.y;\n" + + // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel. + // This layout intentionally reserves the 'r' channel for (optional) occlusion map data + "#ifdef TEXTURE_METALLICROUGHNESS\n" + " vec4 metrou = texture(uMetallicRoughnessSampler, vUV[uMetallicRoughnessTexCoordIndex]);\n" + " metallic = metrou.b * metallic;\n" + " perceptualRoughness = metrou.g * perceptualRoughness;\n" + "#endif\n" + + " metallic = clamp(metallic, 0.0, 1.0);\n" + " perceptualRoughness = clamp(perceptualRoughness, c_MinRoughness, 1.0);\n" + // Roughness is authored as perceptual roughness; as is convention, + // convert to material roughness by squaring the perceptual roughness [2]. + " float alphaRoughness = perceptualRoughness * perceptualRoughness;\n" + + "#ifdef TEXTURE_BASECOLOR\n" + // The albedo may be defined from a base texture or a flat color + " vec4 baseColor = texture(uBaseColorSampler, vUV[uBaseColorTexCoordIndex]) * uBaseColorFactor;\n" + " baseColor = vec4(linear(baseColor.rgb), baseColor.w);\n" + "#else\n" + " vec4 baseColor = vColor * uBaseColorFactor;\n" + "#endif\n" + + " if( alphaMode == 0 )\n" + " {\n" + " baseColor.w = 1.0;\n" + " }\n" + " else if( alphaMode == 1 )\n" + " {\n" + " if( baseColor.w >= alphaCutoff )" + " {\n" + " baseColor.w = 1.0;\n" + " }\n" + " else\n" + " {\n" + " baseColor.w = 0.0;\n" + " }\n" + " }\n" + + " vec3 f0 = vec3(0.04);\n" + " vec3 diffuseColor = baseColor.rgb * (vec3(1.0) - f0);\n" + " diffuseColor *= ( 1.0 - metallic );\n" + " vec3 specularColor = mix(f0, baseColor.rgb, metallic);\n" + + // Compute reflectance. + " float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);\n" + + // For typical incident reflectance range (between 4% to 100%) set the grazing reflectance to 100% for typical fresnel effect. + // For very low reflectance range on highly diffuse objects (below 4%), incrementally reduce grazing reflecance to 0%. + " float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);\n" + " vec3 specularEnvironmentR0 = specularColor.rgb;\n" + " vec3 specularEnvironmentR90 = vec3(1.0, 1.0, 1.0) * reflectance90;\n" + + " vec3 n = getNormal();\n" // normal at surface point + " vec3 v = normalize(vPositionToCamera);\n" // Vector from surface point to camera + " vec3 l = normalize(vLightDirection);\n" // Vector from light to surface point + " vec3 h = normalize(l+v);\n" // Half vector between both l and v + " vec3 reflection = -normalize(reflect(v, n));\n" + + " float NdotL = clamp(dot(n, l), 0.001, 1.0);\n" + " float NdotV = clamp(abs(dot(n, v)), 0.001, 1.0);\n" + " float NdotH = clamp(dot(n, h), 0.0, 1.0);\n" + " float LdotH = clamp(dot(l, h), 0.0, 1.0);\n" + " float VdotH = clamp(dot(v, h), 0.0, 1.0);\n" + + " PBRInfo pbrInputs = PBRInfo(\n" + " NdotL,\n" + " NdotV,\n" + " NdotH,\n" + " LdotH,\n" + " VdotH,\n" + " perceptualRoughness,\n" + " metallic,\n" + " specularEnvironmentR0,\n" + " specularEnvironmentR90,\n" + " alphaRoughness,\n" + " diffuseColor,\n" + " specularColor\n" + " );\n" + + // Calculate the shading terms for the microfacet specular shading model + " vec3 color = vec3(0.0);\n" + " if( visLight == 1 )\n" + " {\n" + " vec3 F = specularReflection(pbrInputs);\n" + " float G = geometricOcclusion(pbrInputs);\n" + " float D = microfacetDistribution(pbrInputs);\n" + + // Calculation of analytical lighting contribution + " vec3 diffuseContrib = (1.0 - F) * ( pbrInputs.diffuseColor / M_PI );\n" + " vec3 specContrib = F * G * D / (4.0 * NdotL * NdotV);\n" + // Obtain final intensity as reflectance (BRDF) scaled by the energy of the light (cosine law) + " color = NdotL * uLightColor * (diffuseContrib + specContrib);\n" + " }\n" + + "#ifdef TEXTURE_IBL\n" + " float lod = (pbrInputs.perceptualRoughness * uMipmapLevel);\n" + // retrieve a scale and bias to F0. See [1], Figure 3 + " vec3 brdf = linear(texture(ubrdfLUT, vec2(pbrInputs.NdotV, 1.0 - pbrInputs.perceptualRoughness)).rgb);\n" + " vec3 diffuseLight = linear(texture(uDiffuseEnvSampler, n).rgb);\n" + " vec3 specularLight = linear(textureLod(uSpecularEnvSampler, reflection, lod).rgb);\n" + + " vec3 diffuse = diffuseLight * pbrInputs.diffuseColor;\n" + " vec3 specular = specularLight * (pbrInputs.specularColor * brdf.x + brdf.y);\n" + " diffuse *= uScaleIBLAmbient.x;\n" + " specular *= uScaleIBLAmbient.y;\n" + " color += (diffuse+specular);\n" + "#endif\n" + + "#ifdef TEXTURE_OCCLUSION\n" + " float ao = texture(uOcclusionSampler, vUV[uOcclusionTexCoordIndex]).r;\n" + " color = mix(color, color * ao, uOcclusionStrength);\n" + "#endif\n" + + "#ifdef TEXTURE_EMIT\n" + " vec3 emissive = linear(texture(uEmissiveSampler, vUV[uEmissiveTexCoordIndex]).rgb) * uEmissiveFactor;\n" + " color += emissive;\n" + "#endif\n" + + " FragColor = vec4(pow(color,vec3(1.0/2.2)), baseColor.a);\n" + "}\n" +}; + +} // namespace internal + +} // namespace Toolkit + +} // namespace Dali + +#endif // DALI_TOOLKIT_INTERNAL_GLTF_SHADER_H \ No newline at end of file diff --git a/dali-toolkit/internal/controls/scene/scene-impl.cpp b/dali-toolkit/internal/controls/scene/scene-impl.cpp new file mode 100644 index 0000000..2c70685 --- /dev/null +++ b/dali-toolkit/internal/controls/scene/scene-impl.cpp @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2018 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 "scene-impl.h" + +// EXTERNAL INCLUDES +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +Scene::Scene() + : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ), + mRoot( Actor::New() ), + mDefaultCamera( CameraActor::New() ), + mLightType( Toolkit::Scene::LightType::NONE ), + mLightVector( Vector3::ONE ), + mLightColor( Vector3::ONE ) +{ +} + +Scene::~Scene() +{ +} + +Toolkit::Scene Scene::New( const std::string& filePath ) +{ + Scene* impl = new Scene(); + + Dali::Toolkit::Scene handle = Dali::Toolkit::Scene( *impl ); + + // Second-phase init of the implementation + // This can only be done after the CustomActor connection has been made... + impl->Initialize(); + impl->CreateScene( filePath ); + + return handle; +} + +Toolkit::Scene Scene::New( const std::string& filePath, const std::string& diffuseTexturePath, const std::string& specularTexturePath, Vector4 ScaleFactor ) +{ + Scene* impl = new Scene(); + + Dali::Toolkit::Scene handle = Dali::Toolkit::Scene( *impl ); + + // Second-phase init of the implementation + // This can only be done after the CustomActor connection has been made... + impl->Initialize(); + impl->SetCubeMap( diffuseTexturePath, specularTexturePath, ScaleFactor ); + impl->CreateScene( filePath ); + + return handle; +} + +bool Scene::CreateScene( const std::string& filePath ) +{ + if( std::string::npos != filePath.rfind( GLTF_EXT ) ) + { + Internal::GltfLoader gltfloader; + return( gltfloader.LoadScene( filePath, *this ) ); + } + + return false; +} + +uint32_t Scene::GetAnimationCount() +{ + return mAnimationArray.size(); +} + +bool Scene::PlayAnimation( uint32_t index ) +{ + if( GetAnimationCount() <= index ) + { + return false; + } + + mAnimationArray[index].Play(); + return true; +} + +bool Scene::PlayAnimations() +{ + if( GetAnimationCount() == 0 ) + { + return false; + } + + for( unsigned int i=0; i Toolkit::Scene::LightType::DIRECTIONAL_LIGHT ) + { + return false; + } + + mLightType = static_cast( + ( mLightType >= Toolkit::Scene::LightType::IMAGE_BASED_LIGHT ) ? + Toolkit::Scene::LightType::IMAGE_BASED_LIGHT + type : + type ); + + mLightVector = lightVector; + mLightColor = lightColor; + + for( unsigned int i = 0; i( malloc( byteSize + 4u ) ); + + int srcStride = width * bytesPerPixel; + int destStride = xFaceSize * bytesPerPixel; + int srcOffset = xOffset * bytesPerPixel + yOffset * srcStride; + int destOffset = 0; + for( uint16_t row = yOffset; row < yOffset + yFaceSize; ++row ) + { + memcpy( destBuffer + destOffset, sourceBuffer + srcOffset, destStride ); + srcOffset += srcStride; + destOffset += destStride; + } + + return destBuffer; +} + +void Scene::UploadTextureFace( Texture& texture, Devel::PixelBuffer pixelBuffer, int faceIndex ) +{ + unsigned char* imageBuffer = pixelBuffer.GetBuffer(); + unsigned int bytesPerPixel = Pixel::GetBytesPerPixel( pixelBuffer.GetPixelFormat() ); + unsigned int imageWidth = pixelBuffer.GetWidth(); + unsigned int imageHeight = pixelBuffer.GetHeight(); + + CubeType cubeType = ( imageWidth / 4 == imageHeight / 3 ) ? CROSS_HORIZENTAL : + ( ( imageWidth / 6 == imageHeight ) ? ARRAY_HORIZENTAL : NONE ); + + int faceSize = 0; + if( cubeType == CROSS_HORIZENTAL ) + { + faceSize = imageWidth / 4; + } + else if( cubeType == ARRAY_HORIZENTAL ) + { + faceSize = imageWidth / 6; + } + + unsigned int xOffset = cubeMap_index_x[cubeType][faceIndex] * faceSize; + unsigned int yOffset = cubeMap_index_y[cubeType][faceIndex] * faceSize; + + unsigned char* tempImageBuffer = CropBuffer( imageBuffer, bytesPerPixel, imageWidth, imageHeight, xOffset, yOffset, faceSize, faceSize ); + PixelData pixelData = PixelData::New( tempImageBuffer, faceSize * faceSize * bytesPerPixel, faceSize, faceSize, pixelBuffer.GetPixelFormat(), PixelData::FREE ); + texture.Upload( pixelData, CubeMapLayer::POSITIVE_X + faceIndex, 0, 0, 0, faceSize, faceSize ); +} + +void Scene::SetCubeMap( const std::string& diffuseTexturePath, const std::string& specularTexturePath, Vector4 ScaleFactor ) +{ + mLightType = Toolkit::Scene::LightType::IMAGE_BASED_LIGHT; + + // BRDF texture + std::string imageBrdfUrl = DALI_IMAGE_DIR "brdfLUT.png"; + mBRDFTexture = LoadTexture( imageBrdfUrl.c_str(), true ); + if( !mBRDFTexture ) + { + return; + } + + // Diffuse Cube Map + Devel::PixelBuffer diffusePixelBuffer = LoadImageFromFile( diffuseTexturePath ); + int diffuseFaceSize = diffusePixelBuffer.GetWidth() / 4; + mDiffuseTexture = Texture::New( TextureType::TEXTURE_CUBE, diffusePixelBuffer.GetPixelFormat(), diffuseFaceSize, diffuseFaceSize ); + for( int i = 0; i<6; ++i ) + { + UploadTextureFace( mDiffuseTexture, diffusePixelBuffer, i ); + } + mDiffuseTexture.GenerateMipmaps(); + + // Specular Cube Map + Devel::PixelBuffer specularPixelBuffer = LoadImageFromFile( specularTexturePath ); + int specularFaceSize = specularPixelBuffer.GetWidth() / 4; + mSpecularTexture = Texture::New( TextureType::TEXTURE_CUBE, specularPixelBuffer.GetPixelFormat(), specularFaceSize, specularFaceSize ); + for( int i = 0; i<6; ++i ) + { + UploadTextureFace( mSpecularTexture, specularPixelBuffer, i ); + } + mSpecularTexture.GenerateMipmaps(); + + mIBLScaleFactor = ScaleFactor; +} + +bool Scene::SetDefaultCamera( const Dali::Camera::Type type, const float nearPlane, const Vector3 cameraPosition ) +{ + mDefaultCamera.SetParentOrigin( ParentOrigin::CENTER ); + mDefaultCamera.SetAnchorPoint( AnchorPoint::CENTER ); + mDefaultCamera.SetType( type ); + mDefaultCamera.SetNearClippingPlane( nearPlane ); + mDefaultCamera.SetPosition( cameraPosition ); + return true; +} + +void Scene::AddCamera( CameraActor& cameraActor ) +{ + mCameraActorArray.push_back( cameraActor ); +} + +void Scene::AddAnimation( Animation& animation ) +{ + mAnimationArray.push_back( animation ); +} + +void Scene::AddShader( Shader shader ) +{ + mShaderArray.push_back( shader ); +} + +Actor Scene::GetRoot() +{ + return mRoot; +} + +CameraActor Scene::GetDefaultCamera() +{ + return mDefaultCamera; +} + +CameraActor Scene::GetCamera( const int cameraIndex ) +{ + if( cameraIndex < 0 ) + { + return GetDefaultCamera(); + } + return mCameraActorArray[cameraIndex]; +} + +Toolkit::Scene::LightType Scene::GetLightType() +{ + return mLightType; +} + +Vector3 Scene::GetLightVector() +{ + return mLightVector; +} + +Vector3 Scene::GetLightColor() +{ + return mLightColor; +} + +Vector4 Scene::GetIBLScaleFactor() +{ + return mIBLScaleFactor; +} + +Texture Scene::GetBRDFTexture() +{ + return mBRDFTexture; +} + +Texture Scene::GetSpecularTexture() +{ + return mSpecularTexture; +} + +Texture Scene::GetDiffuseTexture() +{ + return mDiffuseTexture; +} + +Texture Scene::LoadTexture( const char *imageUrl, bool generateMipmaps ) +{ + Texture texture; + + Devel::PixelBuffer pixelBuffer = LoadImageFromFile( imageUrl ); + if( pixelBuffer ) + { + texture = Texture::New( TextureType::TEXTURE_2D, pixelBuffer.GetPixelFormat(), pixelBuffer.GetWidth(), pixelBuffer.GetHeight() ); + PixelData pixelData = Devel::PixelBuffer::Convert( pixelBuffer ); + texture.Upload( pixelData ); + + if( generateMipmaps ) + { + texture.GenerateMipmaps(); + } + } + + return texture; +} + +void Scene::OnInitialize() +{ + mRoot.SetParentOrigin( ParentOrigin::CENTER ); + mRoot.SetAnchorPoint( AnchorPoint::CENTER ); + + Layer layer = Layer::New(); + layer.SetBehavior( Layer::LAYER_3D ); + layer.SetParentOrigin( ParentOrigin::CENTER ); + layer.SetAnchorPoint( AnchorPoint::CENTER ); + layer.Add( mRoot ); + + Actor self = Self(); + // Apply some default resizing rules. + self.SetParentOrigin( ParentOrigin::CENTER ); + self.SetAnchorPoint( AnchorPoint::CENTER ); + self.Add( layer ); + + mShaderArray.clear(); + mCameraActorArray.clear(); + mAnimationArray.clear(); +} + +}//namespace Internal + +}//namespace Toolkit + +}//namespace Dali + diff --git a/dali-toolkit/internal/controls/scene/scene-impl.h b/dali-toolkit/internal/controls/scene/scene-impl.h new file mode 100644 index 0000000..90b1740 --- /dev/null +++ b/dali-toolkit/internal/controls/scene/scene-impl.h @@ -0,0 +1,277 @@ +#ifndef DALI_TOOLKIT_INTERNAL_SCENE_H +#define DALI_TOOLKIT_INTERNAL_SCENE_H + +/* + * Copyright (c) 2018 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 Toolkit +{ + +class Scene; + +namespace Internal +{ + +class GltfLoader; + +namespace +{ + +// glTF file extension +const std::string GLTF_EXT( ".gltf" ); + +/** + * cube map face index + */ +const int cubeMap_index_x[2][6] = { { 2, 0, 1, 1, 1, 3 },{ 0, 1, 2, 3, 4, 5 } }; +const int cubeMap_index_y[2][6] = { { 1, 1, 0, 2, 1, 1 },{ 0, 0, 0, 0, 0, 0 } }; + +} // namespace + +/** + * Scene implementation class + */ +class Scene : public Control +{ +public: + + enum CubeType + { + CROSS_HORIZENTAL = 0, // Cross horizental style cube map + ARRAY_HORIZENTAL, // array horizental style cube map + NONE + }; + + + /** + * @copydoc Dali::Toolkit::Scene::Scene + */ + Scene(); + + /** + * @copydoc Dali::Toolkit::Scene::~Scene + */ + virtual ~Scene(); + + /** + * @copydoc Dali::Toolkit::Scene::New( const std::string& filePath ) + */ + static Dali::Toolkit::Scene New( const std::string& filePath ); + + /** + * @copydoc Dali::Toolkit::Scene::New( const std::string& filePath, const std::string& diffuseTexturePath, const std::string& specularTexturePath, Vector4 ScaleFactor = Vector4( 1.0, 1.0, 1.0, 1.0 ) ) + */ + static Dali::Toolkit::Scene New( const std::string& filePath, const std::string& diffuseTexturePath, const std::string& specularTexturePath, Vector4 ScaleFactor = Vector4( 1.0, 1.0, 1.0, 1.0 ) ); + + /** + * @copydoc Dali::Toolkit::Scene::CreateScene( const std::string& filePath ) + */ + bool CreateScene( const std::string& filePath ); + + /** + * @copydoc Dali::Toolkit::Scene::CreateScene( const std::string& filePath ) + */ + uint32_t GetAnimationCount(); + + /** + * @copydoc Dali::Toolkit::Scene::PlayAnimation() + */ + bool PlayAnimation( uint32_t index ); + + /** + * @copydoc Dali::Toolkit::Scene::PlayAnimations() + */ + bool PlayAnimations(); + + /** + * @copydoc Dali::Toolkit::Scene::SetLight( Toolkit::Scene::LightType type, Vector3 lightVector, Vector3 lightColor = Vector3( 1.0, 1.0, 1.0 ) ) + */ + bool SetLight( Toolkit::Scene::LightType type, Vector3 lightVector, Vector3 lightColor = Vector3( 1.0, 1.0, 1.0 ) ); + + /** + * @brief Set default CameraActor. + * with Dali::Camera::Type = Dali::Camera::LOOK_AT_TARGET, + * near clipping plane = 0.1, + * and camera position = Vector3( 0.0, 0.0, 0.0 ). + */ + bool SetDefaultCamera( const Dali::Camera::Type type = Dali::Camera::LOOK_AT_TARGET, const float nearPlane = 0.1, const Vector3 cameraPosition = Vector3( 0.0, 0.0, 0.0 ) ); + + /** + * @brief Add CameraActor loaded from scene format file. + */ + void AddCamera( CameraActor& cameraActor ); + + /** + * @brief Add Animation loaded from scene format file. + */ + void AddAnimation( Animation& animation ); + + /** + * @brief Add new Shader. + * Actors can share same Shader if they use same properties. + * If a property changes in a shader, then the property of all actors that use the shader change. + */ + void AddShader( Shader shader ); + + /** + * @brief Get Root Actor. + */ + Actor GetRoot(); + + /** + * @copydoc Dali::Toolkit::Scene::GetDefaultCamera() + */ + CameraActor GetDefaultCamera(); + + /** + * @copydoc Dali::Toolkit::Scene::GetCamera( int cameraIndex = -1 ) + */ + CameraActor GetCamera( int cameraIndex = -1 ); + + /** + * @brief Get light type. + */ + Toolkit::Scene::LightType GetLightType(); + + /** + * @brief Get light vector. + * Return light position when light type is LightType::POINT_LIGHT + * Return light direction when light type is LightType::DIRECTIONAL_LIGHT + */ + Vector3 GetLightVector(); + + /** + * @brief Get light color. + */ + Vector3 GetLightColor(); + + /** + * @brief Get Scaling factor of IBL. + */ + Vector4 GetIBLScaleFactor(); + + /** + * @brief Get BRDF Texture. + */ + Texture GetBRDFTexture(); + + /** + * @brief Get diffuse cube map texture. + */ + Texture GetDiffuseTexture(); + + /** + * @brief Get specular cube map texture. + */ + Texture GetSpecularTexture(); + +private: + /** + * @brief Crop image buffer. + * For each direction, Offset + faceSize must be width or height or less then them. + */ + unsigned char* CropBuffer( unsigned char* sourceBuffer, unsigned int bytesPerPixel, unsigned int width, unsigned int height, unsigned int xOffset, unsigned int yOffset, unsigned int xFaceSize, unsigned int yFaceSize ); + + /** + * @brief Upload cube map texture. + */ + void UploadTextureFace( Texture& texture, Devel::PixelBuffer pixelBuffer, int faceIndex ); + + /** + * @brief Set diffuse and specular cube map textures. + */ + void SetCubeMap( const std::string& diffuseTexturePath, const std::string& specularTexturePath, Vector4 ScaleFactor = Vector4( 1.0, 1.0, 1.0, 1.0 ) ); + + virtual void OnInitialize(); + + + /** + * @brief Load 2D texture. + * @param[in] imageUrl Image URL of the texture. + * @param[in] generateMipmaps If generateMipmaps is true, then generate mipmap of this texture. + * @return Texture loaded from imageUrl. + */ + Texture LoadTexture( const char *imageUrl, bool generateMipmaps ); + +private: + Actor mRoot; // Root actor that contains scene graph + + std::vector mShaderArray; // Shader Array to change properties of scene such as lighting. + + std::vector mCameraActorArray; // CameraActer array loaded from scene format file. + CameraActor mDefaultCamera; // Default CameraActor for the empty mCameraActorArray. + + std::vector mAnimationArray; // Animation array loaded from scene format file. + + Toolkit::Scene::LightType mLightType; // Light type + Vector3 mLightVector; // Light position when mLightType is LightType::POINT_LIGHT + // Light direction when mLightType is LightType::DIRECTIONAL_LIGHT + Vector3 mLightColor; // Light color + + Vector4 mIBLScaleFactor; // IBL scaling factor for the IBL rendering + Texture mBRDFTexture; // BRDF texture for the PBR rendering + Texture mSpecularTexture; // Specular cube map texture + Texture mDiffuseTexture; // Diffuse cube map texture + +private: + + // Undefined copy constructor. + Scene( const Scene& ); + + // Undefined assignment operator. + Scene& operator=( const Scene& ); +}; + +} // namespace Internal + + // Helpers for public-api forwarding methods +inline const Internal::Scene& GetImpl( const Toolkit::Scene& scene ) +{ + DALI_ASSERT_ALWAYS( scene && "Scene handle is empty" ); + const Dali::RefObject& handle = scene.GetImplementation(); + + return static_cast( handle ); +} + +inline Internal::Scene& GetImpl( Toolkit::Scene& scene ) +{ + DALI_ASSERT_ALWAYS( scene && "Scene handle is empty" ); + + Dali::RefObject& handle = scene.GetImplementation(); + + return static_cast( handle ); +} + +}//namespace Toolkit + +}//namespace Dali + +#endif // DALI_TOOLKIT_INTERNAL_SCENE_H diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index 51839c7..a5ec5b6 100755 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -90,6 +90,8 @@ toolkit_src_files = \ $(toolkit_src_dir)/controls/scrollable/scroll-view/scroll-view-effect-impl.cpp \ $(toolkit_src_dir)/controls/scrollable/scroll-view/scroll-view-impl.cpp \ $(toolkit_src_dir)/controls/scrollable/scroll-view/scroll-view-page-path-effect-impl.cpp \ + $(toolkit_src_dir)/controls/scene/scene-impl.cpp \ + $(toolkit_src_dir)/controls/scene/gltf-loader.cpp \ $(toolkit_src_dir)/controls/shadow-view/shadow-view-impl.cpp \ $(toolkit_src_dir)/controls/slider/slider-impl.cpp \ $(toolkit_src_dir)/controls/super-blur-view/super-blur-view-impl.cpp \ diff --git a/dali-toolkit/styles/images-common/brdfLUT.png b/dali-toolkit/styles/images-common/brdfLUT.png new file mode 100644 index 0000000..5f6541b Binary files /dev/null and b/dali-toolkit/styles/images-common/brdfLUT.png differ