Merge "Support animation of Visual transform properties" into devel/master
authorHeeyong Song <heeyong.song@samsung.com>
Wed, 23 Dec 2020 23:19:27 +0000 (23:19 +0000)
committerGerrit Code Review <gerrit@review>
Wed, 23 Dec 2020 23:19:27 +0000 (23:19 +0000)
18 files changed:
README.md
automated-tests/patch-coverage.pl
build/tizen/docs/dali.doxy.in
dali-scene-loader/README.md
dali-scene-loader/public-api/animation-definition.cpp
dali-scene-loader/public-api/blend-shape-details.h
dali-scene-loader/public-api/camera-parameters.h
dali-scene-loader/public-api/dli-loader.cpp
dali-scene-loader/public-api/material-definition.cpp
dali-scene-loader/public-api/material-definition.h
dali-scene-loader/public-api/mesh-definition.cpp
dali-scene-loader/public-api/mesh-definition.h
dali-scene-loader/public-api/node-definition.h
dali-scene-loader/public-api/scene-definition.cpp
dali-scene-loader/public-api/skinning-details.h
dali-scene-loader/public-api/utils.cpp
dali-scene-loader/public-api/utils.h
dali-toolkit/internal/controls/control/control-data-impl.cpp

index ff51191..dd18745 100644 (file)
--- a/README.md
+++ b/README.md
@@ -14,6 +14,7 @@
       * [3. Building for MS Windows](#3-building-for-ms-windows)
          * Build with the Visual Studio project.
          * Build with CMake.
+   * [DALi Scene Loader](#dali-scene-loader)
 
 # Build Instructions
 
@@ -109,3 +110,7 @@ vcpkg-script folder in the windows-dependencies repository.
     - INSTALL_CMAKE_MODULES    ---> Whether to install the CMake modules (Used by the CMake command find_package() to find previously installed libraries).
     - ENABLE_DEBUG             ---> Whether to build with debug enabled.
     - USE_DEFAULT_RESOURCE_DIR ---> Whether to use the default resource folders. Otherwise set environment variables for DALI_IMAGE_DIR, DALI_SOUND_DIR, DALI_STYLE_DIR, DALI_STYLE_IMAGE_DIR and DALI_DATA_READ_ONLY_DIR
+
+# DALi Scene Loader
+
+For information about the DALi Scene Loader library, refer to dali-scene-loader/README.md.
\ No newline at end of file
index b3cf098..1f836a4 100755 (executable)
@@ -83,7 +83,7 @@ my %options = (
     "output:s"     => { "optvar"=>\$opt_output, "desc"=>"Generate html output"},
     "help"         => { "optvar"=>\$opt_help, "desc"=>""},
     "quiet"        => { "optvar"=>\$opt_quiet, "desc"=>""},
-    "verbose"      => { "optvar"=>\$opt_verbose, "desc"=>"" });
+    "verbose"      => { "optvar"=>\$opt_verbose, "desc"=>"Also output coverage" });
 
 my %longOptions = map { $_ => $options{$_}->{"optvar"} } keys(%options);
 GetOptions( %longOptions ) or pod2usage(2);
@@ -875,15 +875,14 @@ sub info(@)
     }
 }
 
-# NEW STUFF
 
-## Format per file, repeated, no linebreak
+# Format per file, repeated, no linebreak
 # <diffcmd>
 # index c1..c2 c3
 # --- a/<left-hand-side-file>
 # +++ b/<right-hand-side-file>
 # <diff hunks>
-
+#
 # Format of each diff hunk, repeated, no linebreak
 # @@ <ranges> @@ line
 # 3 lines of context
@@ -986,7 +985,7 @@ sub parse_diff
     $files{$file}->{"patch"} = [@checklines];
     $files{$file}->{"b_lines"} = {%b_lines};
 
-    my %filter = map { $_ => $files{$_} } grep {m!^dali(-toolkit)?/!} (keys(%files));;
+    my %filter = map { $_ => $files{$_} } grep {m!^dali(-toolkit|-scene-loader)?/!} (keys(%files));
 
     if($pd_debug)
     {
@@ -1064,6 +1063,13 @@ sub calc_patch_coverage_percentage
         my $abs_filename = File::Spec->rel2abs($file, $root);
         my $sumcountref = $info_data{$abs_filename}->{"sum"};
 
+        if($debug>1)
+        {
+            print("File:  $abs_filename\n");
+            print Dumper($info_data{$abs_filename});
+            print "\n";
+        }
+
         if( $sumcountref )
         {
             for my $patch (@$patchref)
@@ -1312,27 +1318,6 @@ EOH
 ##                                    MAIN                                    ##
 ################################################################################
 
-my $cwd = getcwd(); # expect this to be automated-tests folder
-
-# execute coverage.sh, generating build/tizen/dali.info from lib, and
-# *.dir/dali.info. Don't generate html
-print `./coverage.sh -n`;
-chdir "..";
-$root = getcwd();
-
-our %info_data; # Hash of all data from .info files
-my @info_files = split(/\n/, `find . -name dali.info`);
-my %new_info;
-
-# Read in all specified .info files
-foreach (@info_files)
-{
-    %new_info = %{read_info_file($_)};
-
-    # Combine %new_info with %info_data
-    %info_data = %{combine_info_files(\%info_data, \%new_info)};
-}
-
 
 # Generate git diff command
 my @cmd=('--no-pager','diff','--no-ext-diff','-U0','--no-color');
@@ -1362,7 +1347,7 @@ else
         }
         else
         {
-            die "Both cached & working files - cannot get correct patch from git\n";
+            die "Error: Both cached & working files - cannot get correct patch from git\nRun git add first.";
             # Would have to diff from separate clone.
         }
     }
@@ -1370,6 +1355,31 @@ else
 
 push @cmd, @ARGV;
 
+# Before executing the diff, run the coverage.sh script. This is done here so that the
+# error condition above happens straight away, rather than after spewing out lots of information.
+
+my $cwd = getcwd(); # expect this to be automated-tests folder
+# execute coverage.sh, generating build/tizen/dali.info from lib, and
+# *.dir/dali.info. Don't generate html
+printf("Running coverage.sh\n");
+my $coverage_output=`./coverage.sh -n`;
+chdir "..";
+$root = getcwd();
+
+our %info_data; # Hash of all data from .info files
+my @info_files = split(/\n/, `find . -name dali.info`);
+my %new_info;
+
+# Read in all specified .info files
+foreach (@info_files)
+{
+    %new_info = %{read_info_file($_)};
+
+    # Combine %new_info with %info_data
+    %info_data = %{combine_info_files(\%info_data, \%new_info)};
+}
+
+
 # Execute diff & coverage from root directory
 my $filesref = run_diff(@cmd);
 
@@ -1386,21 +1396,33 @@ foreach my $file (keys(%$filesref))
 }
 if( $filecount == 0 )
 {
-    print "No source files found\n";
+    print "Warning: No source files found\n";
     exit 0;    # Exit with no error.
 }
 
 #print_simplified_info() if $debug;
 #exit 0;
+if($debug > 1)
+{
+    print "Info keys:\n";
+    for my $key (keys(%info_data))
+    {
+        print "$key\n";
+    }
+    print "\n\n";
+}
 
 my $percentref = calc_patch_coverage_percentage($filesref);
 if($percentref->[0] == 0)
 {
-    print "No coverable lines found\n";
+    print "Warning: No coverable lines found\n";
     exit 0;
 }
 my $percent = $percentref->[1];
 
+printf(join("\n", grep { $_ !~ /^Remov/ } split(/\n/,$coverage_output))) if $opt_verbose;
+#printf($coverage_output) if $opt_verbose;
+
 my $color=BOLD RED;
 if($opt_output)
 {
@@ -1417,6 +1439,7 @@ elsif( ! $opt_quiet )
     print RESET;
 }
 
+printf("\n\n=========================\nPatch coverage output:\n=========================\n");
 printf("Line Coverage: %d/%d\n", $percentref->[2], $percentref->[0]);
 printf("Percentage of change covered: %5.2f%\n", $percent);
 
index 75cece0..0a9d553 100644 (file)
@@ -995,6 +995,7 @@ INPUT                  = @DOXYGEN_DOCS_DIR@/content \
                          @prefix@/include/dali/devel-api \
                          ../../../dali-toolkit/public-api \
                          ../../../dali-toolkit/devel-api \
+                         ../../../dali-scene-loader/public-api \
                          ../../../automated-tests/README.md
 
 # This tag can be used to specify the character encoding of the source files
@@ -2266,7 +2267,10 @@ INCLUDE_FILE_PATTERNS  =
 # recursively expanded use the := operator instead of the = operator.
 # This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
-PREDEFINED             = DALI_TOOLKIT_API \
+PREDEFINED             = DALI_CORE_API \
+                         DALI_ADAPTOR_API \
+                         DALI_TOOLKIT_API \
+                         DALI_SCENE_LOADER_API \
                          DALI_INTERNAL \
                          __attribute__ \
                          ((visibility \
index 2f88dbe..a11d2e4 100644 (file)
-# dali-sceen-loader
+# Table of contents
+   * [Overview](#overview)
+   * [`scenes`](#scenes)
+   * [`nodes`](#nodes)
+      * [Transformations](#transformations)
+      * [Size](#size)
+      * [Visibility](#visibility)
+      * [`children`](#children)
+      * [`customization`](#customization)
+      * [Renderables](#renderables)
+         * [`model`](#model)
+         * [`arc`](#arc)
+      * [`inverseBindPoseMatrix`](#inversebindposematrix)
+   * [`materials`](#materials)
+   * [`meshes`](#meshes)
+   * [`shaders`](#shaders)
+      * [`rendererState`](#rendererState)
+      * [`defines`](#defines)
+      * [`hints`](#hints)
+      * [Uniforms](#uniforms)
+   * [`skeletons`](#skeletons)
+   * [`cameras`](#cameras)
+      * [Perspective cameras](#perspective-cameras)
+      * [Orthographic cameras](#orthographic-cameras)
+   * [`lights`](#lights)
+   * [`animations`](#animations)
+      * [`properties`](#properties)
+         * [`keyFramesBin`](#keyframesbin)
+         * [`keyFrames`](#keyFrames)
+         * [`value`](#value)
+   * [`animationGroups`](#animationGroups)
 
-Provides functionality for loading scenes created in the JSON-based DLI format. DLI is most similar to glTF, but less verbose / granular, and it has a few extra features:
+# Overview
+DLI is a JSON based format for representing 3D scenes.
+   * Like glTF, the DLI document defines a set of scenes, which in turn define a hierarchical structure of nodes, and the additional data required to render them - meshes, geometry.
+   * Unlike glTF, it allows definitions of shaders, environment maps, and lighting parameters as well;
+   * Unlike glTF, DLI does not concern itself with buffers, buffer views and accessors;
+   * It supports customizations, which allow replacing parts of the scene based on customization tags and options, without reloading the whole scene.
+   * It supports the processing of custom categories, which can be scheduled to take place prior to or after the processing of the scene data, as well as custom node and animation processors.
 
-- customizations: switch between alternative definitions of parts of the scene;
-- environment maps;
-- text, arc, and image elements;
-- etc. (TODO)
+# `scenes`
+The "scenes" element is an array of JSON objects, each of which must define a `nodes` array with the index of the definition of the root node.
+:warning: The array must not be empty. Only the first element is used.
+An optional `scene` element with an integer value may be defined to specify the index of the first scene to be created.
+The rest of the scenes are created in the order of their definition (from index 0 to the highest, skipping the default - already created - scene).
+```js
+{
+    "scene": 0,
+    "scenes": [ { "nodes": [ 0 ] } ],
+    "nodes": [ {
+        "name": "some_unique_name"
+    } ]
+}
+```
 
-Please refer to [dli-exporter](http://github.com/dalihub/dli-exporter) for converting 3D models to DLI.
+# `nodes`
+The 3D scene is built using a hierarchy of nodes, which are used to position the objects to render.
+:warning: Each node must have a `name` string that 1, is not an empty string and 2, is unique within the DLI document. The use of alpha-numeric characters and underscore only is highly recommeneded.
 
-## Prequisites
+## Transformations
+There are two ways to define the local transform of each nodes. Both are optional, defaulting to a position at the origin, a scale of one and no rotation.
+   * A `matrix` array of 16 numerical values defining a column-major 4x4 matrix;
+   * A `position` array of 3 numerical values defining a 3D vector and an `angle` array of 3 numerical values defining euler angles of rotation along the 3 axes.
 
-- Windows:
+## Size
+The size of the bounding box of a node may be specified using either of the optional `size` or `bounds` properties, as arrays of 2 or 3 numerical values. Its default value is the unit vector.
 
-  - Microsoft Visual Studio 2017 (or later, with 2017 build tools);
-  - [windows-dependencies](https://github.com/dalihub/windows-dependencies ) - please follow the steps in its README.md *as well as* its vcpkg-script/ReadMe.md, to install VCPKG and all dependencies;
-- Linux:
+## Visibility
+The `visible` optional boolean property defines whether a node and its children are rendered (`true`) or not (`false`).
 
-  - GCC v9.3+;
-  - CMake v3.14+;
-  - [dali-core](https://github.com/dalihub/dali-core );
-  - [dali-adaptor](https://github.com/dalihub/dali-adaptor );
-  - [dali-toolkit](https://github.com/dalihub/dali-toolkit );
-  - configure DALi environment by following the instructions in README.md, in dali-core;
+## `children`
+An array of 0 or more indices into the top level `nodes` array, which shall inherit the transform and visibility of their parent node.
+:warning: Nodes are processed in the order they are encountered during the depth-first traversal of the hierarchy.
+```js
+  "nodes": [ {
+    "name": "hip",
+    "children": [ 3, 1, 2 ]
+  }, {
+    "name": "spine"
+  }, {
+    "name": "left leg"
+  }, {
+    "name": "right leg"
+  } ]
+```
 
-## Build instructions
+## `customization`
+Customizations may allow creating a different sub-tree of each node that define them, based on application specific configuration settings known at the time of creating the scene.
+The definition of a `customization` is a single string tag: 
+```js
+  "nodes": [ {
+    "name": "Soup du jour",
+    "customization": "flavor", // this one
+    "children": [ 1, 2, 3 ]
+  }, {
+    "name": "Broccoli and Stilton",
+  }, {
+    "name": "Butternut Squash",
+  }, {
+    "name": "Strawberry and Cream",
+  } ]
+```
+:warning: Customizations and renderables are mutually exclusive on the same node.
 
-1, build the DALi libraries;
+## Renderables
+There is support for two types of nodes that define renderable content.
+The definition of these renderables come in sub-objects.
+All of them support a `color` property, which is an array of 3 or 4 numerical values for RGB or RGBA components. For the alpha value to take effect, alpha blending must be enabled; this is controlled by the [material](#materiaL).
+:warning: Customizations and renderables are mutually exclusive on the same node.
 
-2,
+### `model`
+Provides definition for a 3D object, which requires a `mesh`, `shader` and `material`.
+Each of these are provided in form of an integer index into the related top-level array of the DLI document.
+:warning: `mesh` must be provided; the rest are optional and default to 0.
+```js
+  "nodes": [ {
+    "name": "Sphere",
+    "model": {
+      "mesh": 0, // required
+      "shader": 0, // optional, defaults to 0
+      "material": 1 // optional, defaults to 0
+    }
+  } ]
+```
 
-  - Windows: refer to the VS2017 solution in the windows-dependencies repository;
-  - Linux: run the ../build/tizen/dali-scene-loader/build.sh;
-  - Tizen:
+### `arc`
+Arc is a specialisation of a model that allows the rendering of circular progress bars. As such, it also must provide a `mesh` ID.
+```js
+  "nodes": [ {
+    "name": "Any Name",
+    "arc": {
+      "mesh": 0, // required
+      "shader": 0, // optional, defaults to 0
+      "material": 1 // optional, defaults to 0
+      "antiAliasing": true,
+      "radius": -0.928,
+      "startAngle": -81.0,
+      "endAngle": 261
+    }
+  } ]
+```
+   * `startAngle` and `endAngle` are the angular positions where the arc starts and ends, in degrees.
+   * `radius` is the inner radius of the arc, the outer radius being defined by the [`size`](#size) of the node.
+   * `antiAliasing` defines whether the edges of the arc should be smoothed.
+   
+## `inverseBindPoseMatrix`
+Nodes that serve as joints of a [skeleton](#skeleton) must define this property as an array of 16 numerical values for a column major 4x4 matrix.
+```js
+  "nodes": [ {
+    "name" : "l_shoulder_JNT",
+    "inverseBindPoseMatrix" : [ 0.996081, -0.0407448, 0.0785079, 0.0, 0.0273643, 0.985992, 0.164531, 0.0, -0.0841121, -0.161738, 0.983242, 0.0, -0.0637747, -1.16091, -0.161038, 1.0 ]
+  } ]
+```
 
-    $ gbs build -A ${target_arch}
+# `environment`
+An array of environment map definitions, which have the following format:
+```js
+  "environment": [{
+    "cubeSpecular": "Studio_001/Radiance.ktx",
+    "cubeDiffuse": "Studio_001/Irradiance.ktx",
+    "cubeInitialOrientation": [ 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 ] 
+  } ]
+```
+`cubeSpecular` and `cubeDiffuse` are the names of the respective cube map files that will be attempted to be located from the _environment_ path, which is up to the application. A 1x1x1 white RGB888 cubemap is created in place of either that was omitted.
+`cubeInitialOrientation` may be used to inform the (PBR) shader of a matrix which describes the initial orientation of the cube map. Defaults to the identity matrix.
 
-    - for debug, add: --define "%enable_debug 1"
-    - for SMACK-enabled targets, add: --define "%enable_dali_smack_rules 1"
+# `materials`
+Defines configurations of textures (and their samplers) that form materials. These can be created from single values or image files (in the formats that DALi supports).
+```js
+  "materials": [ {
+    "environment": 0,
+    "albedoMap": "A.png",
+    "normal": "N.png",
+    "metallicRoughnessMap": "MR.png",
+    "color": [ 1.0, 0.8, 0.7, 0.5 ]
+  } ]
+```
+   * `environment`: The index of the [environment map](#environments) to use. Single integer, defaults to `0`.
+   * `mipmap`: A boolean to speficy if the creation and sampling of mipmaps should be enabled. Off by default.
+   * `color`: Base color, which the color of the node gets multiplied by. Defaults to white.
+   * `metallic` and `roughness`: Properties for PBR materials; both are expected to be a single numerical value and default to `1.0`.
+
+## Texture maps
+`albedoMap` / `albedoMetallicMap` / `normalMap` / `normalRoughnessMap` / `metallicRoughnessMap` / `subsurfaceMap`: define various texture semantics, i.e. the role of the texture, which shall be loaded from an image _inside the materials path_, which is up to the application. All of them are optional.
+:warning: Semantics shall not overlap within the same material, e.g. multiple albedo definitions, or albedo and albedoMetallic.
+
+# `meshes`
+Defines an array of meshes which are used to access geometry data stored in a binary file. The `uri` property is used to locate each file _inside the mesh path_, which is up to the application; alternatively it can be set to `"quad"`, resulting in the creation of a unit quad.
+Those models loaded from a file may provide an accessor, and flag its presence in the `attributes` bitmask property. The following are supported:
+|Attribute Name|Bit|Decimal value|Type|Remarks|
+|-|-|-|-|-|
+|`indices`  |0|  1|unsigned short||
+|`positions`|1|  2|Vector3||
+|`normals`  |2|  4|Vector3||
+|`textures` |3|  8|Vector2|UVs|
+|`tangents` |4| 16|Vector3||
+|           |5| 32||Ignored, but reserved for bitangents|
+|`joints0`  |6| 64|Vector4|Joint IDs for skinned meshes|
+|`weights0` |7|128|Vector4|Joint weights for skinned meshes|
+E.g. if positions, normals and tangents are provided, the `attributes` property must have a value of 2 + 4 + 16 = 22.
+Each attribute must provide a `byteOffset` and `byteLength` property, which must be correctly sized for the type of the given attribute.
+Finally, to specify what primitives should the geometry be rendered as, a `primitive` property may be provided with one of the following values: `TRIANGLES` (default), `LINES`, `POINTS`.
+
+## Skinned meshes
+DLI supports meshes that allow deformation by skeletal animation. These must define a few additional properties:
+   * `joints0` and `weights0` attributes, as above.
+   * A [`skeleton`](#skeletons) ID, to specify which (joint) nodes' transformations affect the mesh.
+
+:warning: The maximum number of bones supported by DALi Scene Loader is `64`.
+
+## Blend shapes
+Blend shapes provide alternate configurations of vertex `positions`, `normals` and/or `tangents` that may be blended with the same attributes of the base mesh, controlled by an animatable `weight`.
+```js
+  "meshes": [ {
+      "uri": "example.bin",
+      "attributes": 2,
+      "positions": {
+          "byteOffset": 0,
+          "byteLength": 12000
+      },
+      "blendShapesHeader": {
+          "version": "2.0",
+          "byteOffset": 12000,
+          "byteLEngth": 4
+      },
+      "blendShapes": [ {
+          "weight": 0.0,
+          "positions": {
+              byteOffset: 12004,
+              byteLength: 12000
+          }
+      } ]
+  } ]
+```
+A `blendShapesHeader`, if present, must define:
+   * the `version` of the blend shapes; supported values are `1.0` and `2.0`. The difference between the versions is that v1.0 requires a per-blend shape definition of an un-normalization factor.
+   * the `byteOffset` and `byteLength` of a buffer in the binary which defines the width (2 bytes) and height (2 bytes) of the texture that dali-scene-loader creates for blend shape data.
+
+The `blendShapes` array then defines the shapes that are available to blend between, comprising of:
+   * An initial `weight` numerical, the default is 0;
+   * `position` / `normals` / `tangents` attributes, which must be also present in the base mesh and are the same format (`byteOffset` / `byteLength`);
+
+:warning: The size of the attributes of the blend shape must match that of the base mesh (and each other) - i.e. they must define the same number of vertices.
+
+# `shaders`
+Provides an array of shader programs that renderables may use for rendering.
+For each shader, `vertex` and `fragment` are required string properties pointing to the shader files _inside the shader path_, which is up to the application.
+   * `rendererState`: This string defines the options for configuring the settings of the renderer. Refer to public-api/renderer-state.h for details.
+   * `defines`: An optional array of strings which will be used to create #defines into the vertex and fragment shaders.
+   * `hints`: An optional array of strings that map to `Dali::Shader::Hint` values. Therefore two values are supported - `MODIFIES_GEOMETRY` and `OUTPUT_IS_TRANSPARENT`.
+
+## Uniforms
+Every property that is not one of the reserved keys above, will be attempted to be registered as a uniform of the same name.
+:warning: boolean values will be converted to floating point 1.0 (for `true`) or 0.0 (for `false`).
+:warning: integer values will be converted to floating point.
+:warning: arrays of numerical values will be treated as one of the vec2 / vec3 / vec4 / mat3 / mat4 types, depending on what do they define sufficient components for.
+```js
+  "shader": [ {
+    "vertex": "dli_pbr.vsh",
+    "fragment": "dli_pbr.fsh",
+    "defines": [ "HIGHP", SKINNING" ],
+    "rendererState": "DEPTH_WRITE|DEPTH_TEST|CULL_BACK",
+    "hints": 
+    "uMaxLOD": 6
+  } ]
+```
+
+# `skeletons`
+Skeletons in DLI simply define the name of a `node` that shall serve as the _root joint_ of the given skeleton.
+```js
+  "skeletons": [ {
+    "node": "hipJoint"
+  } ]
+```
+The Joint IDs in skinned mesh data relate to the descendants of the [node](#nodes) identified as the root joint that are joints, i.e. define [`inverseBindPoseMatrix`](#inversebindposematrix), in depth-first traversal order.
+
+# `cameras`
+Define the transformation of viewers and the projection used by them.
+All cameras may define:
+   * `matrix`: an array of 16 numerical values for the transform matrix
+   * `near` and `far` values for the position of the respective clipping planes. These default to `0.1` and `1000.0`, respectively.
+
+## Perspective cameras
+This projection type - and a vertical field of view of `60` degrees - is the default.
+The (V)FOV can be specified in the `fov` property, as a single numerical value.
+
+## Orthographic cameras
+If the `orthographic` is defined with an array of four numerical values for the left, right, bottom and top clipping planes (in this order), then orthographic projection is used, and `fov` is ignored.
+
+# `lights`
+Define parameters for a single light source - the implementation is up to the application. The following properties are supported.
+   * `transform`: matrix of 16 numerical values for the positioning / directing of the light;
+   * `color`: array of 3 components for RGB;
+   * `intensity`: single float;
+   * `shadowIntensity`: single float;
+   * `shadowMapSize`: unsigned integer size (same width & height) of shadow map.
+   * `orthographicSize`: single float to define the size (same width & height) of orthographic position.
+
+# `animations`
+Animations provide a way to change properties of nodes (and those of their renderables) over time.
+```js
+  "animations": [ {
+     "name": "Idle",
+     "loopCount": 0,
+     "duration": 4.0,
+     "endAction": "DISCARD",
+     "disconnectAction": "DISCARD",
+     "properties": []
+  } ]
+```
+   * `name`: the identifier to look the animation up by;
+   * `loopCount`: the number of times that the animation should be played. The default is `1`; `0` signifies infinity repetitions.
+   * `duration`: the duration of the animation in seconds. If not provided, it will be calculated from the properties.
+   * `endAction` and `disconnectAction`: the supported values, defaults and their meaning are described in the `Dali::Animation::EndAction` enum;
+
+## `properties`
+An array of animation property definitions.
+   * `node`: the name of the node whose property shall be animated;
+   * `property`: the name that the property was registered under.
+   * `alphaFunction`: the name of an alpha function which shall be used in animating a value, or between key frames;
+   * `timePeriod`: `delay` (defaults to `0.0`) and `duration` (defaults to the `duration` of the animation) of the property animation, in sceonds;
+
+The property may be animated using one of the following methods. They are listed in priority order; if e.g. a property defines `keyFramesBin` and `keyFrames`, then only `keyFramesBin` is used. 
+
+### `keyFramesBin`
+JSON object that defines a keyframe animation in a binary buffer, with the following properties:
+   * `url` the path to the file containing the buffer;
+   * `numKeys`: the number of keys.
+   * `byteOffset`: offset to the start of the buffer
+
+The size of the buffer depends on the property being animated, where  the property value for each frame follows a 4 byte floating point value determining progress (between 0 and 1).
+:warning: Only `position` (3D vector of floats, 12 bytes), `rotation` (Quaternion, 12 bytes), and `scale` (3D vector, 12 bytes) properties are supported.
+
+### `keyFrames`
+JSON array of keyframe objects defined with the following properties:
+   * `progress`: a scalar between `0` and `1` to apply to the duration to get the time stamp of the frame;
+   * `value`: array of 3 or 4 numerical values depending on which property is being animated;
+:warning: Only `position`, `rotation`, and `scale` properties are supported.
+
+### `value`
+Value animations animate a property using a single value that may be absolute or relative.
+The properties it supports are the following:
+   * `value`: the value to animate to (if absolute) or by (if `relative`);
+   * `relative`: whether `value` is a target, or an offset;
+
+# `animationGroups`
+Animation groups simply group animations together by name, under another name, which may be used to trigger them at the same time.
+```js
+  "animationGroups": [ {
+    "name": "Idle",
+    "animations": [ "IdleBody", "IdleFace" ]
+  } ]
+```
index b41b8d5..ee2b519 100644 (file)
@@ -32,11 +32,10 @@ Animation::EndAction AnimationDefinition::StopForModification(Animation& anim)
   return endAction;
 }
 
-AnimationDefinition::AnimationDefinition()
-{}
+AnimationDefinition::AnimationDefinition() = default;
 
 AnimationDefinition::AnimationDefinition(AnimationDefinition&& other)
-:  mName(std::move(other.mName)),
+: mName(std::move(other.mName)),
   mDuration(other.mDuration),
   mLoopCount(other.mLoopCount),
   mDisconnectAction(other.mDisconnectAction),
index 7ea6d3f..67283a8 100644 (file)
@@ -68,6 +68,8 @@ struct DALI_SCENE_LOADER_API BlendShapes
    *  on the given @a shader and @a actor.
    */
   static void ConfigureProperties(const std::pair<MeshDefinition, MeshGeometry>& mesh, Shader shader, Actor actor);
+
+  BlendShapes() = delete;
 };
 
 }
index 20b3ee3..044c7f4 100644 (file)
@@ -35,23 +35,12 @@ namespace SceneLoader
 
 struct DALI_SCENE_LOADER_API CameraParameters
 {
-  CameraParameters()
-  : matrix(Matrix::IDENTITY),
-    orthographicSize(-1.f, 1.f, 1.f, -1.f),
-    yFov(60.f),
-    zNear(0.1f),
-    zFar(1000.f),
-    isPerspective(true)
-  {}
-
-  ~CameraParameters() = default;
-
-  Matrix matrix;
-  Vector4 orthographicSize;
-  float yFov;
-  float zNear;
-  float zFar;
-  bool isPerspective;
+  Matrix matrix = Matrix::IDENTITY;
+  Vector4 orthographicSize = Vector4{ -1.f, 1.f, 1.f, -1.f };
+  float yFov = 60.f;
+  float zNear = 0.1f;
+  float zFar = 1000.f;
+  bool isPerspective = true;
 
   /**
    * @return The view-projection matrix of the camera.
index 06268eb..11dc036 100644 (file)
@@ -159,9 +159,9 @@ void ReadArcField(const TreeNode* eArc, ArcNode& arc)
   ReadFloat(eArc->GetChild("endAngle"), arc.mEndAngleDegrees);
 }
 
-const TreeNode *Tidx(const TreeNode *node, int index)
+const TreeNode *GetNthChild(const TreeNode *node, uint32_t index)
 {
-  int i = 0;
+  uint32_t i = 0;
   for (TreeNode::ConstIterator it = (*node).CBegin(); it != (*node).CEnd(); ++it, ++i)
   {
     if (i == index)
@@ -463,8 +463,8 @@ void DliLoader::Impl::ParseScene(LoadParams& params)
 void DliLoader::Impl::ParseSceneInternal(Index iScene, const Toolkit::TreeNode* tnScenes,
   const Toolkit::TreeNode* tnNodes, LoadParams& params)
 {
-  auto getSceneRootIdx = [&](Index iScene) {
-    auto tn = Tidx(tnScenes, iScene);  // now a "scene" object
+  auto getSceneRootIdx = [tnScenes, tnNodes](Index iScene) {
+    auto tn = GetNthChild(tnScenes, iScene);  // now a "scene" object
     if (!tn)
     {
       ExceptionFlinger(ASSERT_LOCATION) << iScene << " is out of bounds access into " << SCENES << ".";
@@ -483,7 +483,7 @@ void DliLoader::Impl::ParseSceneInternal(Index iScene, const Toolkit::TreeNode*
         " must define a node id.";
     }
 
-    tn = Tidx(tn, 0);  // now the first element of the array
+    tn = GetNthChild(tn, 0);  // now the first element of the array
     Index iRootNode;
     if (!ReadIndex(tn, iRootNode))
     {
@@ -496,7 +496,7 @@ void DliLoader::Impl::ParseSceneInternal(Index iScene, const Toolkit::TreeNode*
       ExceptionFlinger(ASSERT_LOCATION) << "Root node index << " << iRootNode << " of scene " << iScene << " is out of bounds.";
     }
 
-    tn = Tidx(tnNodes, iRootNode);  // now a "node" object
+    tn = GetNthChild(tnNodes, iRootNode);  // now a "node" object
     if (tn->GetType() != TreeNode::OBJECT)
     {
       ExceptionFlinger(ASSERT_LOCATION) << "Root node of scene " << iScene << " is of invalid JSON type; object required";
@@ -1095,7 +1095,7 @@ void DliLoader::Impl::ParseNodesInternal(const TreeNode* const nodes, Index inde
   std::vector<IndexProperty> resourceIds;
   resourceIds.reserve(4);
 
-  if (auto node = Tidx(nodes, index))
+  if (auto node = GetNthChild(nodes, index))
   {
     NodeDefinition nodeDef;
     nodeDef.mParentIdx = inOutParentStack.empty() ? INVALID_INDEX : inOutParentStack.back();
index ca1244b..952a824 100644 (file)
@@ -100,6 +100,11 @@ Sampler SamplerFlags::MakeSampler(Type flags)
   return sampler;
 }
 
+TextureDefinition::TextureDefinition(const std::string& imageUri, SamplerFlags::Type samplerFlags)
+: mImageUri(imageUri),
+  mSamplerFlags(samplerFlags)
+{}
+
 MaterialDefinition::RawData
   MaterialDefinition::LoadRaw(const std::string& imagesPath) const
 {
index 619e849..d360c88 100644 (file)
@@ -116,10 +116,7 @@ struct DALI_SCENE_LOADER_API TextureDefinition
   std::string mImageUri;
   SamplerFlags::Type mSamplerFlags;
 
-  TextureDefinition(const std::string& imageUri = "", SamplerFlags::Type samplerFlags = SamplerFlags::DEFAULT)
-  :  mImageUri(imageUri),
-    mSamplerFlags(samplerFlags)
-  {}
+  TextureDefinition(const std::string& imageUri = "", SamplerFlags::Type samplerFlags = SamplerFlags::DEFAULT);
 };
 
 /**
index 9823295..2cea908 100644 (file)
@@ -64,7 +64,7 @@ private:
 };
 
 
-const std::string QUAD_STRING("quad");
+const std::string QUAD("quad");
 
 ///@brief Reads a blob from the given stream @a source into @a target, which must have
 /// at least @a descriptor.length bytes.
@@ -290,10 +290,10 @@ void CalculateTextureSize(uint32_t totalTextureSize, uint32_t& textureWidth, uin
 {
   DALI_ASSERT_DEBUG(0u != totalTextureSize && "totalTextureSize is zero.")
 
-    // Calculate the dimensions of the texture.
-    // The total size of the texture is the length of the blend shapes blob.
+  // Calculate the dimensions of the texture.
+  // The total size of the texture is the length of the blend shapes blob.
 
-    textureWidth = 0u;
+  textureWidth = 0u;
   textureHeight = 0u;
 
   if (0u == totalTextureSize)
@@ -443,14 +443,14 @@ void CalculateGltf2BlendShapes(uint8_t* geometryBuffer, std::ifstream& binFile,
 }
 
 MeshDefinition::SparseBlob::SparseBlob(const Blob& indices, const Blob& values, uint32_t count)
-:  mIndices{indices},
+: mIndices{indices},
   mValues{values},
   mCount{count}
 {}
 
 MeshDefinition::Accessor::Accessor(const MeshDefinition::Blob& blob,
   const MeshDefinition::SparseBlob& sparse)
-:  mBlob{blob},
+: mBlob{blob},
   mSparse{(sparse.mIndices.IsDefined() && sparse.mValues.IsDefined()) ? new SparseBlob{sparse} : nullptr}
 {}
 
@@ -489,6 +489,15 @@ void MeshDefinition::Blob::ApplyMinMax(const std::vector<float>& min, const std:
   }
 }
 
+MeshDefinition::Blob::Blob(uint32_t offset, uint32_t length, uint16_t stride, uint16_t elementSizeHint, const std::vector<float>& min, const std::vector<float>& max)
+: mOffset(offset),
+  mLength(length),
+  mStride(stride),
+  mElementSizeHint(elementSizeHint),
+  mMin(min),
+  mMax(max)
+{}
+
 uint32_t MeshDefinition::Blob::GetBufferSize() const
 {
   return IsConsecutive() ? mLength : (mLength * mElementSizeHint / mStride);
@@ -511,7 +520,7 @@ void MeshDefinition::RawData::Attrib::AttachBuffer(Geometry& g) const
 
 bool MeshDefinition::IsQuad() const
 {
-  return CaseInsensitiveStringCompare("quad", mUri);
+  return CaseInsensitiveStringCompare(QUAD, mUri);
 }
 
 bool MeshDefinition::IsSkinned() const
index 6a1eaa6..057aad7 100644 (file)
@@ -81,14 +81,7 @@ struct DALI_SCENE_LOADER_API MeshDefinition
     Blob() = default;
 
     Blob(uint32_t offset, uint32_t length, uint16_t stride = 0, uint16_t elementSizeHint = 0,
-      const std::vector<float>& min = {}, const std::vector<float>& max = {})
-      : mOffset(offset),
-      mLength(length),
-      mStride(stride),
-      mElementSizeHint(elementSizeHint),
-      mMin(min),
-      mMax(max)
-    {}
+      const std::vector<float>& min = {}, const std::vector<float>& max = {});
 
     /**
      * @brief Calculates the size of a tightly-packed buffer for the elements from the blob.
index 994ec18..3dec499 100644 (file)
@@ -44,8 +44,7 @@ class ViewProjection;
 class DALI_SCENE_LOADER_API IResourceReceiver
 {
 public:
-  virtual ~IResourceReceiver()
-  {}
+  virtual ~IResourceReceiver() = default;
 
   virtual void Register(ResourceType::Value type, Index id) = 0;
 };
@@ -58,8 +57,7 @@ public:
 class DALI_SCENE_LOADER_API IResourceReflector
 {
 public:
-  virtual ~IResourceReflector()
-  {}
+  virtual ~IResourceReflector() = default;
 
   virtual void Reflect(ResourceType::Value type, Index& id) = 0;
 };
@@ -163,7 +161,7 @@ public:  // TYPES
     Index mShaderIdx = INVALID_INDEX;
 
   public: // METHODS
-    virtual ~Renderable() {}
+    virtual ~Renderable() = default;
 
     virtual void RegisterResources(IResourceReceiver& receiver) const;
     virtual void ReflectResources(IResourceReflector& reflector);
@@ -189,7 +187,7 @@ public:  // TYPES
     virtual void Finish(NodeDefinition& n) = 0;
 
   protected:
-    ~IVisitor() {}
+    ~IVisitor() = default; // deliberately non-virtual these are transient objects and we don't want to pay for the vtable.
   };
 
   class IConstVisitor
@@ -199,7 +197,7 @@ public:  // TYPES
     virtual void Finish(const NodeDefinition& n) = 0;
 
   protected:
-    ~IConstVisitor() {}
+    ~IConstVisitor() = default; // deliberately non-virtual these are transient objects and we don't want to pay for the vtable.
   };
 
   struct Extra
index 0bafc3b..409d285 100644 (file)
@@ -206,7 +206,7 @@ class ActorCreatorVisitor : public NodeDefinition::IConstVisitor
 {
 public:
   ActorCreatorVisitor(NodeDefinition::CreateParams& params)
-  :  mCreationContext(params)
+  : mCreationContext(params)
   {}
 
   void Start(const NodeDefinition& n)
@@ -400,7 +400,7 @@ SceneDefinition::SceneDefinition()
 }
 
 SceneDefinition::SceneDefinition(SceneDefinition&& other)
-:  mNodes(std::move(other.mNodes)),
+: mNodes(std::move(other.mNodes)),
   mRootNodeIds(std::move(other.mRootNodeIds))
 {
 #ifdef DEBUG_JOINTS
index 38dd628..415d25a 100644 (file)
@@ -39,6 +39,8 @@ struct DALI_SCENE_LOADER_API Skinning
    * @brief Name of bone matrix uniform (array).
    */
   static const std::string BONE_UNIFORM_NAME;
+
+  Skinning() = delete;
 };
 
 }
index 382e118..8b8132e 100644 (file)
@@ -35,6 +35,27 @@ namespace
 thread_local char sExceptionFlingerMessageBuffer[ExceptionFlinger::MESSAGE_BUFFER_SIZE]{};
 }
 
+StreamBuffer::StreamBuffer(char* buffer, size_t size) noexcept(true)
+{
+  setp(buffer, buffer + size);
+}
+
+ExceptionFlinger::Impl::~Impl() noexcept(false)
+{
+  throw DaliException(mLocation, GetMessageBuffer());
+}
+
+ExceptionFlinger::ExceptionFlinger(const char* location) noexcept(true)
+: mImpl{ location },
+  mStreamBuffer(GetMessageBuffer(), MESSAGE_BUFFER_SIZE - 1),
+  mStream(&mStreamBuffer)
+{}
+
+ExceptionFlinger::~ExceptionFlinger() noexcept(false)
+{
+  operator<<('\0');
+}
+
 char* ExceptionFlinger::GetMessageBuffer() noexcept(true)
 {
   return sExceptionFlingerMessageBuffer;
index 3ab0c33..1aace35 100644 (file)
@@ -41,10 +41,7 @@ namespace SceneLoader
 class DALI_SCENE_LOADER_API StreamBuffer : public std::basic_streambuf<char>
 {
 public:
-  StreamBuffer(char* buffer, size_t size) noexcept(true)
-  {
-    setp(buffer, buffer + size);
-  }
+  StreamBuffer(char* buffer, size_t size) noexcept(true);
 };
 
 /*
@@ -57,18 +54,10 @@ class DALI_SCENE_LOADER_API ExceptionFlinger
 public:
   enum { MESSAGE_BUFFER_SIZE = 512 };
 
-  ExceptionFlinger(const char* location) noexcept(true)
-  : mLocation(location),
-    mStreamBuffer(GetMessageBuffer(), MESSAGE_BUFFER_SIZE - 1),
-    mStream(&mStreamBuffer)
-  {}
+  ExceptionFlinger(const char* location) noexcept(true);
 
   [[noreturn]]
-  ~ExceptionFlinger() noexcept(false)
-  {
-    operator<<('\0');
-    throw DaliException(mLocation, GetMessageBuffer());
-  }
+  ~ExceptionFlinger() noexcept(false);
 
   template <typename T>
   ExceptionFlinger& operator<<(const T& rhs) noexcept(true)
@@ -78,9 +67,17 @@ public:
   }
 
 private:
+  struct Impl
+  {
+    const char* mLocation;
+
+    [[noreturn]]
+    ~Impl() noexcept(false);
+  };
+
   static char* GetMessageBuffer() noexcept(true);
 
-  const char* mLocation;
+  Impl mImpl;
   StreamBuffer mStreamBuffer;
   std::ostream mStream;
 };
index 4e12efb..b10842b 100755 (executable)
@@ -47,6 +47,7 @@
 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
 #include <dali-toolkit/public-api/focus-manager/keyboard-focus-manager.h>
 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
+#include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
 
 namespace
 {
@@ -2132,14 +2133,13 @@ bool Control::Impl::AccessibleImpl::GrabFocus()
   return Toolkit::KeyboardFocusManager::Get().SetCurrentFocusActor( self );
 }
 
-const char* const FOCUS_BORDER_IMAGE_PATH = DALI_IMAGE_DIR "keyboard_focus.9.png";
-
 static Dali::Actor CreateHighlightIndicatorActor()
 {
+  std::string focusBorderImagePath(AssetManager::GetDaliImagePath());
+  focusBorderImagePath += "/keyboard_focus.9.png";
   // Create the default if it hasn't been set and one that's shared by all the
-  // keyboard focusable actors const char* const FOCUS_BORDER_IMAGE_PATH =
-  // DALI_IMAGE_DIR "keyboard_focus.9.png";
-  auto actor = Toolkit::ImageView::New( FOCUS_BORDER_IMAGE_PATH );
+  // keyboard focusable actors
+  auto actor = Toolkit::ImageView::New( focusBorderImagePath );
   actor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
   DevelControl::AppendAccessibilityAttribute( actor, "highlight", "" );
   actor.SetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED, true);