Merge branch 'devel/master' into tizen
authorhuiyu.eun <huiyu.eun@samsung.com>
Wed, 29 Nov 2023 04:46:30 +0000 (13:46 +0900)
committerhuiyu.eun <huiyu.eun@samsung.com>
Wed, 29 Nov 2023 04:46:30 +0000 (13:46 +0900)
Change-Id: I6747a224d6f25bd5173d161d2fc3a3baac76c275

45 files changed:
automated-tests/resources/TextureTransformMultiTest.bin [new file with mode: 0644]
automated-tests/resources/TextureTransformMultiTest.gltf [new file with mode: 0644]
automated-tests/src/dali-scene3d-internal/utc-Dali-Gltf2LoaderImpl.cpp
automated-tests/src/dali-scene3d-internal/utc-Dali-MaterialImpl.cpp
automated-tests/src/dali-scene3d/utc-Dali-ShaderManager.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-async-task-manager.cpp
automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp
dali-scene3d/internal/event/collider-mesh-processor-impl.cpp
dali-scene3d/internal/graphics/shaders/default-physically-based-shader.frag
dali-scene3d/internal/graphics/shaders/default-physically-based-shader.vert
dali-scene3d/internal/loader/gltf2-asset.h
dali-scene3d/internal/loader/gltf2-util.cpp
dali-scene3d/internal/model-components/material-impl.cpp
dali-scene3d/internal/model-components/material-impl.h
dali-scene3d/internal/model-components/model-node-impl.cpp
dali-scene3d/internal/model-components/model-primitive-impl.cpp
dali-scene3d/public-api/loader/material-definition.cpp
dali-scene3d/public-api/loader/material-definition.h
dali-scene3d/public-api/loader/mesh-definition.cpp
dali-scene3d/public-api/loader/node-definition.cpp
dali-scene3d/public-api/loader/shader-definition.cpp
dali-scene3d/public-api/loader/shader-manager.cpp
dali-scene3d/public-api/loader/shader-option.cpp
dali-toolkit/devel-api/visual-factory/visual-factory.cpp
dali-toolkit/devel-api/visual-factory/visual-factory.h
dali-toolkit/internal/graphics/shaders/color-visual-shader.frag
dali-toolkit/internal/graphics/shaders/color-visual-shader.vert
dali-toolkit/internal/graphics/shaders/gradient-visual-shader.frag
dali-toolkit/internal/graphics/shaders/gradient-visual-shader.vert
dali-toolkit/internal/graphics/shaders/image-visual-shader.frag
dali-toolkit/internal/graphics/shaders/image-visual-shader.vert
dali-toolkit/internal/image-loader/fast-track-loading-task.cpp
dali-toolkit/internal/visuals/image-visual-shader-factory.cpp
dali-toolkit/internal/visuals/image-visual-shader-factory.h
dali-toolkit/internal/visuals/text-visual-shader-factory.cpp
dali-toolkit/internal/visuals/text-visual-shader-factory.h
dali-toolkit/internal/visuals/text/text-visual.cpp
dali-toolkit/internal/visuals/visual-factory-cache.h
dali-toolkit/internal/visuals/visual-factory-impl.cpp
dali-toolkit/internal/visuals/visual-factory-impl.h
dali-toolkit/public-api/dali-toolkit-version.cpp
packaging/dali-toolkit.spec
tools/navigation-mesh-exporter/NavigationMeshExport.py [new file with mode: 0644]
tools/navigation-mesh-exporter/README.md [new file with mode: 0644]
tools/navigation-mesh-exporter/screen.png [new file with mode: 0644]

diff --git a/automated-tests/resources/TextureTransformMultiTest.bin b/automated-tests/resources/TextureTransformMultiTest.bin
new file mode 100644 (file)
index 0000000..1dd626e
Binary files /dev/null and b/automated-tests/resources/TextureTransformMultiTest.bin differ
diff --git a/automated-tests/resources/TextureTransformMultiTest.gltf b/automated-tests/resources/TextureTransformMultiTest.gltf
new file mode 100644 (file)
index 0000000..9f37ec0
--- /dev/null
@@ -0,0 +1,3186 @@
+{
+    "asset" : {
+        "copyright" : "Copyright 2020 Analytical Graphics, Inc, CC-BY 4.0 https://creativecommons.org/licenses/by/4.0/ - Model and textures by Ed Mackey.",
+        "generator" : "Khronos glTF Blender I/O v1.2.75",
+        "version" : "2.0"
+    },
+    "extensionsUsed" : [
+        "KHR_texture_transform",
+        "KHR_materials_unlit",
+        "KHR_materials_clearcoat"
+    ],
+    "extensionsRequired" : [
+        "KHR_texture_transform"
+    ],
+    "scene" : 0,
+    "scenes" : [
+        {
+            "name" : "Scene",
+            "nodes" : [
+                0,
+                1,
+                2,
+                3,
+                4,
+                5,
+                6,
+                7,
+                8,
+                9,
+                10,
+                11,
+                12,
+                13,
+                14,
+                15,
+                16,
+                17,
+                18,
+                19,
+                20,
+                21,
+                22,
+                23,
+                24,
+                25,
+                26,
+                27,
+                28
+            ]
+        }
+    ],
+    "nodes" : [
+        {
+            "mesh" : 0,
+            "name" : "BaseColorUV0",
+            "translation" : [
+                0.10000000149011612,
+                0.75,
+                0
+            ]
+        },
+        {
+            "mesh" : 1,
+            "name" : "BaseColorUV1",
+            "translation" : [
+                0.3499999940395355,
+                0.75,
+                0
+            ]
+        },
+        {
+            "mesh" : 2,
+            "name" : "BaseColorSample",
+            "translation" : [
+                0.6000000238418579,
+                0.75,
+                0
+            ]
+        },
+        {
+            "mesh" : 3,
+            "name" : "Background",
+            "translation" : [
+                0,
+                0,
+                -0.02500000037252903
+            ]
+        },
+        {
+            "mesh" : 4,
+            "name" : "Labels"
+        },
+        {
+            "mesh" : 5,
+            "name" : "EmissionUV0",
+            "translation" : [
+                0.10000000149011612,
+                0.5,
+                0
+            ]
+        },
+        {
+            "mesh" : 6,
+            "name" : "EmissionUV1",
+            "translation" : [
+                0.3499999940395355,
+                0.5,
+                0
+            ]
+        },
+        {
+            "mesh" : 7,
+            "name" : "EmissionSample",
+            "translation" : [
+                0.6000000238418579,
+                0.5,
+                0
+            ]
+        },
+        {
+            "mesh" : 8,
+            "name" : "NormalUV0",
+            "translation" : [
+                0.10000000149011612,
+                0.25,
+                0
+            ]
+        },
+        {
+            "mesh" : 9,
+            "name" : "NormalUV1",
+            "translation" : [
+                0.3499999940395355,
+                0.25,
+                0
+            ]
+        },
+        {
+            "mesh" : 10,
+            "name" : "NormalSample",
+            "translation" : [
+                0.6000000238418579,
+                0.25,
+                0
+            ]
+        },
+        {
+            "mesh" : 11,
+            "name" : "MetalRoughUV0",
+            "translation" : [
+                0.10000000149011612,
+                0,
+                0
+            ]
+        },
+        {
+            "mesh" : 12,
+            "name" : "MetalRoughUV1",
+            "translation" : [
+                0.3499999940395355,
+                0,
+                0
+            ]
+        },
+        {
+            "mesh" : 13,
+            "name" : "MetalRoughSample",
+            "translation" : [
+                0.6000000238418579,
+                0,
+                0
+            ]
+        },
+        {
+            "mesh" : 14,
+            "name" : "OcclusionUV0",
+            "translation" : [
+                0.10000000149011612,
+                -0.25,
+                0
+            ]
+        },
+        {
+            "mesh" : 15,
+            "name" : "OcclusionUV1",
+            "translation" : [
+                0.3499999940395355,
+                -0.25,
+                0
+            ]
+        },
+        {
+            "mesh" : 16,
+            "name" : "OcclusionSample",
+            "translation" : [
+                0.6000000238418579,
+                -0.25,
+                0
+            ]
+        },
+        {
+            "mesh" : 17,
+            "name" : "UnlitUV0",
+            "translation" : [
+                0.10000000149011612,
+                -0.5,
+                0
+            ]
+        },
+        {
+            "mesh" : 18,
+            "name" : "UnlitUV1",
+            "translation" : [
+                0.3499999940395355,
+                -0.5,
+                0
+            ]
+        },
+        {
+            "mesh" : 19,
+            "name" : "UnlitSample",
+            "translation" : [
+                0.6000000238418579,
+                -0.5,
+                0
+            ]
+        },
+        {
+            "mesh" : 20,
+            "name" : "ClearcoatUV0",
+            "translation" : [
+                0.10000000149011612,
+                -0.75,
+                0
+            ]
+        },
+        {
+            "mesh" : 21,
+            "name" : "ClearcoatUV1",
+            "translation" : [
+                0.3499999940395355,
+                -0.75,
+                0
+            ]
+        },
+        {
+            "mesh" : 22,
+            "name" : "ClearcoatSample",
+            "translation" : [
+                0.6000000238418579,
+                -0.75,
+                0
+            ]
+        },
+        {
+            "mesh" : 23,
+            "name" : "ClearcoatRoughUV0",
+            "translation" : [
+                0.10000000149011612,
+                -1,
+                0
+            ]
+        },
+        {
+            "mesh" : 24,
+            "name" : "ClearcoatRoughUV1",
+            "translation" : [
+                0.3499999940395355,
+                -1,
+                0
+            ]
+        },
+        {
+            "mesh" : 25,
+            "name" : "ClearcoatRoughSample",
+            "translation" : [
+                0.6000000238418579,
+                -1,
+                0
+            ]
+        },
+        {
+            "mesh" : 26,
+            "name" : "ClearcoatNormalUV0",
+            "translation" : [
+                0.10000000149011612,
+                -1.25,
+                0
+            ]
+        },
+        {
+            "mesh" : 27,
+            "name" : "ClearcoatNormalUV1",
+            "translation" : [
+                0.3499999940395355,
+                -1.25,
+                0
+            ]
+        },
+        {
+            "mesh" : 28,
+            "name" : "ClearcoatNormalSample",
+            "translation" : [
+                0.6000000238418579,
+                -1.25,
+                0
+            ]
+        }
+    ],
+    "materials" : [
+        {
+            "emissiveFactor" : [
+                0,
+                0,
+                0
+            ],
+            "name" : "BaseColorTest0Mat",
+            "pbrMetallicRoughness" : {
+                "baseColorTexture" : {
+                    "extensions" : {
+                        "KHR_texture_transform" : {
+                            "offset" : [
+                                0.7049999535083774,
+                                0.28500004152502995
+                            ],
+                            "rotation" : 1.5707963705062866,
+                            "scale" : [
+                                0.3499999940395355,
+                                0.3499999940395355
+                            ]
+                        }
+                    },
+                    "index" : 0,
+                    "texCoord" : 0
+                },
+                "metallicFactor" : 0,
+                "roughnessFactor" : 1
+            }
+        },
+        {
+            "emissiveFactor" : [
+                0,
+                0,
+                0
+            ],
+            "name" : "BaseColorTest1Mat",
+            "pbrMetallicRoughness" : {
+                "baseColorTexture" : {
+                    "extensions" : {
+                        "KHR_texture_transform" : {
+                            "offset" : [
+                                0.7049999535083774,
+                                0.28500004152502995
+                            ],
+                            "rotation" : 1.5707963705062866,
+                            "scale" : [
+                                0.3499999940395355,
+                                0.3499999940395355
+                            ]
+                        }
+                    },
+                    "index" : 1,
+                    "texCoord" : 1
+                },
+                "metallicFactor" : 0,
+                "roughnessFactor" : 1
+            }
+        },
+        {
+            "emissiveFactor" : [
+                0,
+                0,
+                0
+            ],
+            "name" : "BaseColorSampleMat",
+            "pbrMetallicRoughness" : {
+                "baseColorTexture" : {
+                    "index" : 2,
+                    "texCoord" : 0
+                },
+                "metallicFactor" : 0,
+                "roughnessFactor" : 1
+            }
+        },
+        {
+            "doubleSided" : true,
+            "emissiveFactor" : [
+                0,
+                0,
+                0
+            ],
+            "name" : "BackgroundMat",
+            "pbrMetallicRoughness" : {
+                "baseColorFactor" : [
+                    0.007408552337437868,
+                    0.07486194372177124,
+                    0.4639684557914734,
+                    1
+                ],
+                "metallicFactor" : 0,
+                "roughnessFactor" : 1
+            }
+        },
+        {
+            "doubleSided" : true,
+            "emissiveFactor" : [
+                0,
+                0,
+                0
+            ],
+            "name" : "LabelMat",
+            "pbrMetallicRoughness" : {
+                "baseColorTexture" : {
+                    "index" : 3,
+                    "texCoord" : 0
+                },
+                "metallicFactor" : 0,
+                "roughnessFactor" : 1
+            }
+        },
+        {
+            "emissiveFactor" : [
+                1,
+                1,
+                1
+            ],
+            "emissiveTexture" : {
+                "extensions" : {
+                    "KHR_texture_transform" : {
+                        "offset" : [
+                            0.7049999535083774,
+                            0.28500004152502995
+                        ],
+                        "rotation" : 1.5707963705062866,
+                        "scale" : [
+                            0.3499999940395355,
+                            0.3499999940395355
+                        ]
+                    }
+                },
+                "index" : 4,
+                "texCoord" : 0
+            },
+            "name" : "EmissionTest0Mat",
+            "pbrMetallicRoughness" : {
+                "baseColorFactor" : [
+                    0,
+                    0.15000000596046448,
+                    0,
+                    1
+                ],
+                "metallicFactor" : 0,
+                "roughnessFactor" : 1
+            }
+        },
+        {
+            "emissiveFactor" : [
+                1,
+                1,
+                1
+            ],
+            "emissiveTexture" : {
+                "extensions" : {
+                    "KHR_texture_transform" : {
+                        "offset" : [
+                            0.7049999535083774,
+                            0.28500004152502995
+                        ],
+                        "rotation" : 1.5707963705062866,
+                        "scale" : [
+                            0.3499999940395355,
+                            0.3499999940395355
+                        ]
+                    }
+                },
+                "index" : 5,
+                "texCoord" : 1
+            },
+            "name" : "EmissionTest1Mat",
+            "pbrMetallicRoughness" : {
+                "baseColorFactor" : [
+                    0,
+                    0.15000000596046448,
+                    0,
+                    1
+                ],
+                "metallicFactor" : 0,
+                "roughnessFactor" : 1
+            }
+        },
+        {
+            "emissiveFactor" : [
+                1,
+                1,
+                1
+            ],
+            "emissiveTexture" : {
+                "index" : 6,
+                "texCoord" : 0
+            },
+            "name" : "EmissionSampleMat",
+            "pbrMetallicRoughness" : {
+                "baseColorFactor" : [
+                    0,
+                    0.15000000596046448,
+                    0,
+                    1
+                ],
+                "metallicFactor" : 0,
+                "roughnessFactor" : 1
+            }
+        },
+        {
+            "emissiveFactor" : [
+                0,
+                0,
+                0
+            ],
+            "name" : "NormalTest0Mat",
+            "normalTexture" : {
+                "extensions" : {
+                    "KHR_texture_transform" : {
+                        "offset" : [
+                            0.7049999535083774,
+                            0.28500004152502995
+                        ],
+                        "rotation" : 1.5707963705062866,
+                        "scale" : [
+                            0.3499999940395355,
+                            0.3499999940395355
+                        ]
+                    }
+                },
+                "index" : 7,
+                "texCoord" : 0
+            },
+            "pbrMetallicRoughness" : {
+                "baseColorFactor" : [
+                    0.800000011920929,
+                    0.800000011920929,
+                    0.800000011920929,
+                    1
+                ],
+                "metallicFactor" : 0,
+                "roughnessFactor" : 0.10000000149011612
+            }
+        },
+        {
+            "emissiveFactor" : [
+                0,
+                0,
+                0
+            ],
+            "name" : "NormalTest1Mat",
+            "normalTexture" : {
+                "extensions" : {
+                    "KHR_texture_transform" : {
+                        "offset" : [
+                            0.7049999535083774,
+                            0.28500004152502995
+                        ],
+                        "rotation" : 1.5707963705062866,
+                        "scale" : [
+                            0.3499999940395355,
+                            0.3499999940395355
+                        ]
+                    }
+                },
+                "index" : 8,
+                "texCoord" : 1
+            },
+            "pbrMetallicRoughness" : {
+                "baseColorFactor" : [
+                    0.800000011920929,
+                    0.800000011920929,
+                    0.800000011920929,
+                    1
+                ],
+                "metallicFactor" : 0,
+                "roughnessFactor" : 0.10000000149011612
+            }
+        },
+        {
+            "emissiveFactor" : [
+                0,
+                0,
+                0
+            ],
+            "name" : "NormalSampleMat",
+            "normalTexture" : {
+                "index" : 9,
+                "texCoord" : 0
+            },
+            "pbrMetallicRoughness" : {
+                "baseColorFactor" : [
+                    0.800000011920929,
+                    0.800000011920929,
+                    0.800000011920929,
+                    1
+                ],
+                "metallicFactor" : 0,
+                "roughnessFactor" : 0.10000000149011612
+            }
+        },
+        {
+            "emissiveFactor" : [
+                0,
+                0,
+                0
+            ],
+            "name" : "MetalRoughTest0Mat",
+            "pbrMetallicRoughness" : {
+                "baseColorFactor" : [
+                    0.800000011920929,
+                    0.800000011920929,
+                    0.800000011920929,
+                    1
+                ],
+                "metallicRoughnessTexture" : {
+                    "extensions" : {
+                        "KHR_texture_transform" : {
+                            "offset" : [
+                                0.7049999535083774,
+                                0.28500004152502995
+                            ],
+                            "rotation" : 1.5707963705062866,
+                            "scale" : [
+                                0.3499999940395355,
+                                0.3499999940395355
+                            ]
+                        }
+                    },
+                    "index" : 10,
+                    "texCoord" : 0
+                }
+            }
+        },
+        {
+            "emissiveFactor" : [
+                0,
+                0,
+                0
+            ],
+            "name" : "MetalRoughTest1Mat",
+            "pbrMetallicRoughness" : {
+                "baseColorFactor" : [
+                    0.800000011920929,
+                    0.800000011920929,
+                    0.800000011920929,
+                    1
+                ],
+                "metallicRoughnessTexture" : {
+                    "extensions" : {
+                        "KHR_texture_transform" : {
+                            "offset" : [
+                                0.7049999535083774,
+                                0.28500004152502995
+                            ],
+                            "rotation" : 1.5707963705062866,
+                            "scale" : [
+                                0.3499999940395355,
+                                0.3499999940395355
+                            ]
+                        }
+                    },
+                    "index" : 11,
+                    "texCoord" : 1
+                }
+            }
+        },
+        {
+            "emissiveFactor" : [
+                0,
+                0,
+                0
+            ],
+            "name" : "MetalRoughSampleMat",
+            "pbrMetallicRoughness" : {
+                "baseColorFactor" : [
+                    0.800000011920929,
+                    0.800000011920929,
+                    0.800000011920929,
+                    1
+                ],
+                "metallicRoughnessTexture" : {
+                    "index" : 12,
+                    "texCoord" : 0
+                }
+            }
+        },
+        {
+            "emissiveFactor" : [
+                0,
+                0,
+                0
+            ],
+            "name" : "OcclusionTest0Mat",
+            "occlusionTexture" : {
+                "extensions" : {
+                    "KHR_texture_transform" : {
+                        "offset" : [
+                            0.7049999535083774,
+                            0.28500004152502995
+                        ],
+                        "rotation" : 1.5707963705062866,
+                        "scale" : [
+                            0.3499999940395355,
+                            0.3499999940395355
+                        ]
+                    }
+                },
+                "index" : 13,
+                "texCoord" : 0
+            },
+            "pbrMetallicRoughness" : {
+                "baseColorFactor" : [
+                    0.800000011920929,
+                    0.800000011920929,
+                    0.800000011920929,
+                    1
+                ],
+                "metallicFactor" : 0,
+                "roughnessFactor" : 1
+            }
+        },
+        {
+            "emissiveFactor" : [
+                0,
+                0,
+                0
+            ],
+            "name" : "OcclusionTest1Mat",
+            "occlusionTexture" : {
+                "extensions" : {
+                    "KHR_texture_transform" : {
+                        "offset" : [
+                            0.7049999535083774,
+                            0.28500004152502995
+                        ],
+                        "rotation" : 1.5707963705062866,
+                        "scale" : [
+                            0.3499999940395355,
+                            0.3499999940395355
+                        ]
+                    }
+                },
+                "index" : 14,
+                "texCoord" : 1
+            },
+            "pbrMetallicRoughness" : {
+                "baseColorFactor" : [
+                    0.800000011920929,
+                    0.800000011920929,
+                    0.800000011920929,
+                    1
+                ],
+                "metallicFactor" : 0,
+                "roughnessFactor" : 1
+            }
+        },
+        {
+            "emissiveFactor" : [
+                0,
+                0,
+                0
+            ],
+            "name" : "OcclusionSampleMat",
+            "occlusionTexture" : {
+                "index" : 15,
+                "texCoord" : 0
+            },
+            "pbrMetallicRoughness" : {
+                "baseColorFactor" : [
+                    0.800000011920929,
+                    0.800000011920929,
+                    0.800000011920929,
+                    1
+                ],
+                "metallicFactor" : 0,
+                "roughnessFactor" : 1
+            }
+        },
+        {
+            "extensions" : {
+                "KHR_materials_unlit" : {}
+            },
+            "name" : "UnlitTest0Mat",
+            "pbrMetallicRoughness" : {
+                "baseColorTexture" : {
+                    "extensions" : {
+                        "KHR_texture_transform" : {
+                            "offset" : [
+                                0.7049999535083774,
+                                0.28500004152502995
+                            ],
+                            "rotation" : 1.5707963705062866,
+                            "scale" : [
+                                0.3499999940395355,
+                                0.3499999940395355
+                            ]
+                        }
+                    },
+                    "index" : 16,
+                    "texCoord" : 0
+                }
+            }
+        },
+        {
+            "extensions" : {
+                "KHR_materials_unlit" : {}
+            },
+            "name" : "UnlitTest1Mat",
+            "pbrMetallicRoughness" : {
+                "baseColorTexture" : {
+                    "extensions" : {
+                        "KHR_texture_transform" : {
+                            "offset" : [
+                                0.7049999535083774,
+                                0.28500004152502995
+                            ],
+                            "rotation" : 1.5707963705062866,
+                            "scale" : [
+                                0.3499999940395355,
+                                0.3499999940395355
+                            ]
+                        }
+                    },
+                    "index" : 17,
+                    "texCoord" : 1
+                }
+            }
+        },
+        {
+            "extensions" : {
+                "KHR_materials_unlit" : {}
+            },
+            "name" : "UnlitSampleMat",
+            "pbrMetallicRoughness" : {
+                "baseColorTexture" : {
+                    "index" : 18,
+                    "texCoord" : 0
+                }
+            }
+        },
+        {
+            "emissiveFactor" : [
+                0,
+                0,
+                0
+            ],
+            "extensions" : {
+                "KHR_materials_clearcoat" : {
+                    "clearcoatFactor" : 1,
+                    "clearcoatRoughnessFactor" : 0.029999999329447746,
+                    "clearcoatTexture" : {
+                        "extensions" : {
+                            "KHR_texture_transform" : {
+                                "offset" : [
+                                    0.7049999535083774,
+                                    0.28500004152502995
+                                ],
+                                "rotation" : 1.5707963705062866,
+                                "scale" : [
+                                    0.3499999940395355,
+                                    0.3499999940395355
+                                ]
+                            }
+                        },
+                        "index" : 19,
+                        "texCoord" : 0
+                    }
+                }
+            },
+            "name" : "ClearcoatTest0Mat",
+            "pbrMetallicRoughness" : {
+                "baseColorFactor" : [
+                    0.0040703266859054565,
+                    0.030168700963258743,
+                    0.16859287023544312,
+                    1
+                ],
+                "metallicFactor" : 1,
+                "roughnessFactor" : 1
+            }
+        },
+        {
+            "emissiveFactor" : [
+                0,
+                0,
+                0
+            ],
+            "extensions" : {
+                "KHR_materials_clearcoat" : {
+                    "clearcoatFactor" : 1,
+                    "clearcoatRoughnessFactor" : 0.029999999329447746,
+                    "clearcoatTexture" : {
+                        "extensions" : {
+                            "KHR_texture_transform" : {
+                                "offset" : [
+                                    0.7049999535083774,
+                                    0.28500004152502995
+                                ],
+                                "rotation" : 1.5707963705062866,
+                                "scale" : [
+                                    0.3499999940395355,
+                                    0.3499999940395355
+                                ]
+                            }
+                        },
+                        "index" : 20,
+                        "texCoord" : 1
+                    }
+                }
+            },
+            "name" : "ClearcoatTest1Mat",
+            "pbrMetallicRoughness" : {
+                "baseColorFactor" : [
+                    0.0040703266859054565,
+                    0.030168700963258743,
+                    0.16859287023544312,
+                    1
+                ],
+                "metallicFactor" : 1,
+                "roughnessFactor" : 1
+            }
+        },
+        {
+            "emissiveFactor" : [
+                0,
+                0,
+                0
+            ],
+            "extensions" : {
+                "KHR_materials_clearcoat" : {
+                    "clearcoatFactor" : 1,
+                    "clearcoatRoughnessFactor" : 0.029999999329447746,
+                    "clearcoatTexture" : {
+                        "index" : 21,
+                        "texCoord" : 0
+                    }
+                }
+            },
+            "name" : "ClearcoatSampleMat",
+            "pbrMetallicRoughness" : {
+                "baseColorFactor" : [
+                    0.0040703266859054565,
+                    0.030168700963258743,
+                    0.16859287023544312,
+                    1
+                ],
+                "metallicFactor" : 1,
+                "roughnessFactor" : 1
+            }
+        },
+        {
+            "emissiveFactor" : [
+                0,
+                0,
+                0
+            ],
+            "extensions" : {
+                "KHR_materials_clearcoat" : {
+                    "clearcoatFactor" : 1,
+                    "clearcoatRoughnessFactor" : 1,
+                    "clearcoatRoughnessTexture" : {
+                        "extensions" : {
+                            "KHR_texture_transform" : {
+                                "offset" : [
+                                    0.7049999535083774,
+                                    0.28500004152502995
+                                ],
+                                "rotation" : 1.5707963705062866,
+                                "scale" : [
+                                    0.3499999940395355,
+                                    0.3499999940395355
+                                ]
+                            }
+                        },
+                        "index" : 22,
+                        "texCoord" : 0
+                    }
+                }
+            },
+            "name" : "ClearcoatRoughTest0Mat",
+            "pbrMetallicRoughness" : {
+                "baseColorFactor" : [
+                    0.0040703266859054565,
+                    0.030168700963258743,
+                    0.16859287023544312,
+                    1
+                ],
+                "metallicFactor" : 1,
+                "roughnessFactor" : 1
+            }
+        },
+        {
+            "emissiveFactor" : [
+                0,
+                0,
+                0
+            ],
+            "extensions" : {
+                "KHR_materials_clearcoat" : {
+                    "clearcoatFactor" : 1,
+                    "clearcoatRoughnessFactor" : 1,
+                    "clearcoatRoughnessTexture" : {
+                        "extensions" : {
+                            "KHR_texture_transform" : {
+                                "offset" : [
+                                    0.7049999535083774,
+                                    0.28500004152502995
+                                ],
+                                "rotation" : 1.5707963705062866,
+                                "scale" : [
+                                    0.3499999940395355,
+                                    0.3499999940395355
+                                ]
+                            }
+                        },
+                        "index" : 23,
+                        "texCoord" : 1
+                    }
+                }
+            },
+            "name" : "ClearcoatRoughTest1Mat",
+            "pbrMetallicRoughness" : {
+                "baseColorFactor" : [
+                    0.0040703266859054565,
+                    0.030168700963258743,
+                    0.16859287023544312,
+                    1
+                ],
+                "metallicFactor" : 1,
+                "roughnessFactor" : 1
+            }
+        },
+        {
+            "emissiveFactor" : [
+                0,
+                0,
+                0
+            ],
+            "extensions" : {
+                "KHR_materials_clearcoat" : {
+                    "clearcoatFactor" : 1,
+                    "clearcoatRoughnessFactor" : 1,
+                    "clearcoatRoughnessTexture" : {
+                        "index" : 24,
+                        "texCoord" : 0
+                    }
+                }
+            },
+            "name" : "ClearcoatRoughSampleMat",
+            "pbrMetallicRoughness" : {
+                "baseColorFactor" : [
+                    0.0040703266859054565,
+                    0.030168700963258743,
+                    0.16859287023544312,
+                    1
+                ],
+                "metallicFactor" : 1,
+                "roughnessFactor" : 1
+            }
+        },
+        {
+            "emissiveFactor" : [
+                0,
+                0,
+                0
+            ],
+            "extensions" : {
+                "KHR_materials_clearcoat" : {
+                    "clearcoatFactor" : 1,
+                    "clearcoatRoughnessFactor" : 0.029999999329447746,
+                    "clearcoatNormalTexture" : {
+                        "extensions" : {
+                            "KHR_texture_transform" : {
+                                "offset" : [
+                                    0.7049999535083774,
+                                    0.28500004152502995
+                                ],
+                                "rotation" : 1.5707963705062866,
+                                "scale" : [
+                                    0.3499999940395355,
+                                    0.3499999940395355
+                                ]
+                            }
+                        },
+                        "index" : 25,
+                        "texCoord" : 0
+                    }
+                }
+            },
+            "name" : "ClearcoatNormalTest0Mat",
+            "pbrMetallicRoughness" : {
+                "baseColorFactor" : [
+                    0.0040703266859054565,
+                    0.030168700963258743,
+                    0.16859287023544312,
+                    1
+                ],
+                "metallicFactor" : 1,
+                "roughnessFactor" : 1
+            }
+        },
+        {
+            "emissiveFactor" : [
+                0,
+                0,
+                0
+            ],
+            "extensions" : {
+                "KHR_materials_clearcoat" : {
+                    "clearcoatFactor" : 1,
+                    "clearcoatRoughnessFactor" : 0.029999999329447746,
+                    "clearcoatNormalTexture" : {
+                        "extensions" : {
+                            "KHR_texture_transform" : {
+                                "offset" : [
+                                    0.7049999535083774,
+                                    0.28500004152502995
+                                ],
+                                "rotation" : 1.5707963705062866,
+                                "scale" : [
+                                    0.3499999940395355,
+                                    0.3499999940395355
+                                ]
+                            }
+                        },
+                        "index" : 26,
+                        "texCoord" : 1
+                    }
+                }
+            },
+            "name" : "ClearcoatNormalTest1Mat",
+            "pbrMetallicRoughness" : {
+                "baseColorFactor" : [
+                    0.0040703266859054565,
+                    0.030168700963258743,
+                    0.16859287023544312,
+                    1
+                ],
+                "metallicFactor" : 1,
+                "roughnessFactor" : 1
+            }
+        },
+        {
+            "emissiveFactor" : [
+                0,
+                0,
+                0
+            ],
+            "extensions" : {
+                "KHR_materials_clearcoat" : {
+                    "clearcoatFactor" : 1,
+                    "clearcoatRoughnessFactor" : 0.029999999329447746,
+                    "clearcoatNormalTexture" : {
+                        "index" : 27,
+                        "texCoord" : 0
+                    }
+                }
+            },
+            "name" : "ClearcoatNormalSampleMat",
+            "pbrMetallicRoughness" : {
+                "baseColorFactor" : [
+                    0.0040703266859054565,
+                    0.030168700963258743,
+                    0.16859287023544312,
+                    1
+                ],
+                "metallicFactor" : 1,
+                "roughnessFactor" : 1
+            }
+        }
+    ],
+    "meshes" : [
+        {
+            "name" : "BaseColorUV0",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 0,
+                        "NORMAL" : 1,
+                        "TEXCOORD_0" : 2,
+                        "TEXCOORD_1" : 3
+                    },
+                    "indices" : 4,
+                    "material" : 0
+                }
+            ]
+        },
+        {
+            "name" : "BaseColorUV1",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 5,
+                        "NORMAL" : 6,
+                        "TEXCOORD_0" : 7,
+                        "TEXCOORD_1" : 8
+                    },
+                    "indices" : 4,
+                    "material" : 1
+                }
+            ]
+        },
+        {
+            "name" : "BaseColorSample",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 9,
+                        "NORMAL" : 10,
+                        "TEXCOORD_0" : 11
+                    },
+                    "indices" : 4,
+                    "material" : 2
+                }
+            ]
+        },
+        {
+            "name" : "BackgroundMesh",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 12,
+                        "NORMAL" : 13
+                    },
+                    "indices" : 4,
+                    "material" : 3
+                }
+            ]
+        },
+        {
+            "name" : "LabelMesh",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 14,
+                        "NORMAL" : 15,
+                        "TEXCOORD_0" : 16
+                    },
+                    "indices" : 17,
+                    "material" : 4
+                }
+            ]
+        },
+        {
+            "name" : "EmissionUV0",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 18,
+                        "NORMAL" : 19,
+                        "TEXCOORD_0" : 20,
+                        "TEXCOORD_1" : 21
+                    },
+                    "indices" : 4,
+                    "material" : 5
+                }
+            ]
+        },
+        {
+            "name" : "EmissionUV1",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 22,
+                        "NORMAL" : 23,
+                        "TEXCOORD_0" : 24,
+                        "TEXCOORD_1" : 25
+                    },
+                    "indices" : 4,
+                    "material" : 6
+                }
+            ]
+        },
+        {
+            "name" : "EmissionSample",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 26,
+                        "NORMAL" : 27,
+                        "TEXCOORD_0" : 28
+                    },
+                    "indices" : 4,
+                    "material" : 7
+                }
+            ]
+        },
+        {
+            "name" : "NormalUV0",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 29,
+                        "NORMAL" : 30,
+                        "TEXCOORD_0" : 31,
+                        "TEXCOORD_1" : 32
+                    },
+                    "indices" : 4,
+                    "material" : 8
+                }
+            ]
+        },
+        {
+            "name" : "NormalUV1",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 33,
+                        "NORMAL" : 34,
+                        "TEXCOORD_0" : 35,
+                        "TEXCOORD_1" : 36
+                    },
+                    "indices" : 4,
+                    "material" : 9
+                }
+            ]
+        },
+        {
+            "name" : "NormalSample",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 37,
+                        "NORMAL" : 38,
+                        "TEXCOORD_0" : 39
+                    },
+                    "indices" : 4,
+                    "material" : 10
+                }
+            ]
+        },
+        {
+            "name" : "MetalRoughUV0",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 40,
+                        "NORMAL" : 41,
+                        "TEXCOORD_0" : 42,
+                        "TEXCOORD_1" : 43
+                    },
+                    "indices" : 4,
+                    "material" : 11
+                }
+            ]
+        },
+        {
+            "name" : "MetalRoughUV1",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 44,
+                        "NORMAL" : 45,
+                        "TEXCOORD_0" : 46,
+                        "TEXCOORD_1" : 47
+                    },
+                    "indices" : 4,
+                    "material" : 12
+                }
+            ]
+        },
+        {
+            "name" : "MetalRoughSample",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 48,
+                        "NORMAL" : 49,
+                        "TEXCOORD_0" : 50
+                    },
+                    "indices" : 4,
+                    "material" : 13
+                }
+            ]
+        },
+        {
+            "name" : "OcclusionUV0",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 51,
+                        "NORMAL" : 52,
+                        "TEXCOORD_0" : 53,
+                        "TEXCOORD_1" : 54
+                    },
+                    "indices" : 4,
+                    "material" : 14
+                }
+            ]
+        },
+        {
+            "name" : "OcclusionUV1",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 55,
+                        "NORMAL" : 56,
+                        "TEXCOORD_0" : 57,
+                        "TEXCOORD_1" : 58
+                    },
+                    "indices" : 4,
+                    "material" : 15
+                }
+            ]
+        },
+        {
+            "name" : "OcclusionSample",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 59,
+                        "NORMAL" : 60,
+                        "TEXCOORD_0" : 61
+                    },
+                    "indices" : 4,
+                    "material" : 16
+                }
+            ]
+        },
+        {
+            "name" : "UnlitUV0",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 62,
+                        "NORMAL" : 63,
+                        "TEXCOORD_0" : 64,
+                        "TEXCOORD_1" : 65
+                    },
+                    "indices" : 4,
+                    "material" : 17
+                }
+            ]
+        },
+        {
+            "name" : "UnlitUV1",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 66,
+                        "NORMAL" : 67,
+                        "TEXCOORD_0" : 68,
+                        "TEXCOORD_1" : 69
+                    },
+                    "indices" : 4,
+                    "material" : 18
+                }
+            ]
+        },
+        {
+            "name" : "UnlitSample",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 70,
+                        "NORMAL" : 71,
+                        "TEXCOORD_0" : 72
+                    },
+                    "indices" : 4,
+                    "material" : 19
+                }
+            ]
+        },
+        {
+            "name" : "ClearcoatUV0",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 73,
+                        "NORMAL" : 74,
+                        "TEXCOORD_0" : 75,
+                        "TEXCOORD_1" : 76
+                    },
+                    "indices" : 77,
+                    "material" : 20
+                }
+            ]
+        },
+        {
+            "name" : "ClearcoatUV1",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 78,
+                        "NORMAL" : 79,
+                        "TEXCOORD_0" : 80,
+                        "TEXCOORD_1" : 81
+                    },
+                    "indices" : 77,
+                    "material" : 21
+                }
+            ]
+        },
+        {
+            "name" : "ClearcoatSample",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 82,
+                        "NORMAL" : 83,
+                        "TEXCOORD_0" : 84
+                    },
+                    "indices" : 77,
+                    "material" : 22
+                }
+            ]
+        },
+        {
+            "name" : "ClearcoarRoughUV0",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 85,
+                        "NORMAL" : 86,
+                        "TEXCOORD_0" : 87,
+                        "TEXCOORD_1" : 88
+                    },
+                    "indices" : 77,
+                    "material" : 23
+                }
+            ]
+        },
+        {
+            "name" : "ClearcoatRoughUV1",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 89,
+                        "NORMAL" : 90,
+                        "TEXCOORD_0" : 91,
+                        "TEXCOORD_1" : 92
+                    },
+                    "indices" : 77,
+                    "material" : 24
+                }
+            ]
+        },
+        {
+            "name" : "ClearcoatRoughSample",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 93,
+                        "NORMAL" : 94,
+                        "TEXCOORD_0" : 95
+                    },
+                    "indices" : 77,
+                    "material" : 25
+                }
+            ]
+        },
+        {
+            "name" : "ClearcoatNormalUV0",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 96,
+                        "NORMAL" : 97,
+                        "TEXCOORD_0" : 98,
+                        "TEXCOORD_1" : 99
+                    },
+                    "indices" : 4,
+                    "material" : 26
+                }
+            ]
+        },
+        {
+            "name" : "ClearcoatNormalUV1",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 100,
+                        "NORMAL" : 101,
+                        "TEXCOORD_0" : 102,
+                        "TEXCOORD_1" : 103
+                    },
+                    "indices" : 4,
+                    "material" : 27
+                }
+            ]
+        },
+        {
+            "name" : "ClearcoatNormalSample",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 104,
+                        "NORMAL" : 105,
+                        "TEXCOORD_0" : 106
+                    },
+                    "indices" : 4,
+                    "material" : 28
+                }
+            ]
+        }
+    ],
+    "textures" : [
+        {
+            "source" : 0
+        },
+        {
+            "source" : 0
+        },
+        {
+            "source" : 0
+        },
+        {
+            "source" : 1
+        },
+        {
+            "source" : 0
+        },
+        {
+            "source" : 0
+        },
+        {
+            "source" : 0
+        },
+        {
+            "source" : 2
+        },
+        {
+            "source" : 2
+        },
+        {
+            "source" : 2
+        },
+        {
+            "source" : 0
+        },
+        {
+            "source" : 0
+        },
+        {
+            "source" : 0
+        },
+        {
+            "source" : 0
+        },
+        {
+            "source" : 0
+        },
+        {
+            "source" : 0
+        },
+        {
+            "source" : 0
+        },
+        {
+            "source" : 0
+        },
+        {
+            "source" : 0
+        },
+        {
+            "source" : 0
+        },
+        {
+            "source" : 0
+        },
+        {
+            "source" : 0
+        },
+        {
+            "source" : 3
+        },
+        {
+            "source" : 3
+        },
+        {
+            "source" : 3
+        },
+        {
+            "source" : 2
+        },
+        {
+            "source" : 2
+        },
+        {
+            "source" : 2
+        }
+    ],
+    "images" : [
+        {
+            "mimeType" : "image/png",
+            "name" : "TestMap",
+            "uri" : "TestMap.png"
+        },
+        {
+            "mimeType" : "image/png",
+            "name" : "TTMT_Labels",
+            "uri" : "TTMT_Labels.png"
+        },
+        {
+            "mimeType" : "image/png",
+            "name" : "TestMap_Normal",
+            "uri" : "TestMap_Normal.png"
+        },
+        {
+            "mimeType" : "image/png",
+            "name" : "TestMap",
+            "uri" : "TestMap-1.png"
+        }
+    ],
+    "accessors" : [
+        {
+            "bufferView" : 0,
+            "componentType" : 5126,
+            "count" : 4,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 1,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 2,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 3,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 4,
+            "componentType" : 5123,
+            "count" : 6,
+            "type" : "SCALAR"
+        },
+        {
+            "bufferView" : 5,
+            "componentType" : 5126,
+            "count" : 4,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 6,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 7,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 8,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 9,
+            "componentType" : 5126,
+            "count" : 4,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 10,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 11,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 12,
+            "componentType" : 5126,
+            "count" : 4,
+            "max" : [
+                0.9999999403953552,
+                1,
+                0
+            ],
+            "min" : [
+                -0.9999999403953552,
+                -1.399999976158142,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 13,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 14,
+            "componentType" : 5126,
+            "count" : 48,
+            "max" : [
+                0.8163908123970032,
+                0.9983971118927002,
+                0
+            ],
+            "min" : [
+                -0.9999999403953552,
+                -1.3177802562713623,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 15,
+            "componentType" : 5126,
+            "count" : 48,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 16,
+            "componentType" : 5126,
+            "count" : 48,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 17,
+            "componentType" : 5123,
+            "count" : 72,
+            "type" : "SCALAR"
+        },
+        {
+            "bufferView" : 18,
+            "componentType" : 5126,
+            "count" : 4,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 19,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 20,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 21,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 22,
+            "componentType" : 5126,
+            "count" : 4,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 23,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 24,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 25,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 26,
+            "componentType" : 5126,
+            "count" : 4,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 27,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 28,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 29,
+            "componentType" : 5126,
+            "count" : 4,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 30,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 31,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 32,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 33,
+            "componentType" : 5126,
+            "count" : 4,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 34,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 35,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 36,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 37,
+            "componentType" : 5126,
+            "count" : 4,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 38,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 39,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 40,
+            "componentType" : 5126,
+            "count" : 4,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 41,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 42,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 43,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 44,
+            "componentType" : 5126,
+            "count" : 4,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 45,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 46,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 47,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 48,
+            "componentType" : 5126,
+            "count" : 4,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 49,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 50,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 51,
+            "componentType" : 5126,
+            "count" : 4,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 52,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 53,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 54,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 55,
+            "componentType" : 5126,
+            "count" : 4,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 56,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 57,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 58,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 59,
+            "componentType" : 5126,
+            "count" : 4,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 60,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 61,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 62,
+            "componentType" : 5126,
+            "count" : 4,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 63,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 64,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 65,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 66,
+            "componentType" : 5126,
+            "count" : 4,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 67,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 68,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 69,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 70,
+            "componentType" : 5126,
+            "count" : 4,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 71,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 72,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 73,
+            "componentType" : 5126,
+            "count" : 361,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0.035051580518484116
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                -0.014266523532569408
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 74,
+            "componentType" : 5126,
+            "count" : 361,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 75,
+            "componentType" : 5126,
+            "count" : 361,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 76,
+            "componentType" : 5126,
+            "count" : 361,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 77,
+            "componentType" : 5123,
+            "count" : 1944,
+            "type" : "SCALAR"
+        },
+        {
+            "bufferView" : 78,
+            "componentType" : 5126,
+            "count" : 361,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0.03505159914493561
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                -0.014266500249505043
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 79,
+            "componentType" : 5126,
+            "count" : 361,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 80,
+            "componentType" : 5126,
+            "count" : 361,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 81,
+            "componentType" : 5126,
+            "count" : 361,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 82,
+            "componentType" : 5126,
+            "count" : 361,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0.03505159914493561
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                -0.014266500249505043
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 83,
+            "componentType" : 5126,
+            "count" : 361,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 84,
+            "componentType" : 5126,
+            "count" : 361,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 85,
+            "componentType" : 5126,
+            "count" : 361,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0.03505159914493561
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                -0.014266500249505043
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 86,
+            "componentType" : 5126,
+            "count" : 361,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 87,
+            "componentType" : 5126,
+            "count" : 361,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 88,
+            "componentType" : 5126,
+            "count" : 361,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 89,
+            "componentType" : 5126,
+            "count" : 361,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0.03505159914493561
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                -0.014266500249505043
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 90,
+            "componentType" : 5126,
+            "count" : 361,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 91,
+            "componentType" : 5126,
+            "count" : 361,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 92,
+            "componentType" : 5126,
+            "count" : 361,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 93,
+            "componentType" : 5126,
+            "count" : 361,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0.03505159914493561
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                -0.014266500249505043
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 94,
+            "componentType" : 5126,
+            "count" : 361,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 95,
+            "componentType" : 5126,
+            "count" : 361,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 96,
+            "componentType" : 5126,
+            "count" : 4,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 97,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 98,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 99,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 100,
+            "componentType" : 5126,
+            "count" : 4,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 101,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 102,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 103,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 104,
+            "componentType" : 5126,
+            "count" : 4,
+            "max" : [
+                0.10000002384185791,
+                0.10000002384185791,
+                0
+            ],
+            "min" : [
+                -0.10000002384185791,
+                -0.10000002384185791,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 105,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 106,
+            "componentType" : 5126,
+            "count" : 4,
+            "type" : "VEC2"
+        }
+    ],
+    "bufferViews" : [
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 0
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 48
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 96
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 128
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 12,
+            "byteOffset" : 160
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 172
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 220
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 268
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 300
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 332
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 380
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 428
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 460
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 508
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 576,
+            "byteOffset" : 556
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 576,
+            "byteOffset" : 1132
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 384,
+            "byteOffset" : 1708
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 144,
+            "byteOffset" : 2092
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 2236
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 2284
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 2332
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 2364
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 2396
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 2444
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 2492
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 2524
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 2556
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 2604
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 2652
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 2684
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 2732
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 2780
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 2812
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 2844
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 2892
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 2940
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 2972
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 3004
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 3052
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 3100
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 3132
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 3180
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 3228
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 3260
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 3292
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 3340
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 3388
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 3420
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 3452
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 3500
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 3548
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 3580
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 3628
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 3676
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 3708
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 3740
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 3788
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 3836
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 3868
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 3900
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 3948
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 3996
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 4028
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 4076
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 4124
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 4156
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 4188
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 4236
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 4284
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 4316
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 4348
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 4396
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 4444
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 4332,
+            "byteOffset" : 4476
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 4332,
+            "byteOffset" : 8808
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 2888,
+            "byteOffset" : 13140
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 2888,
+            "byteOffset" : 16028
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 3888,
+            "byteOffset" : 18916
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 4332,
+            "byteOffset" : 22804
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 4332,
+            "byteOffset" : 27136
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 2888,
+            "byteOffset" : 31468
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 2888,
+            "byteOffset" : 34356
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 4332,
+            "byteOffset" : 37244
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 4332,
+            "byteOffset" : 41576
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 2888,
+            "byteOffset" : 45908
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 4332,
+            "byteOffset" : 48796
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 4332,
+            "byteOffset" : 53128
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 2888,
+            "byteOffset" : 57460
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 2888,
+            "byteOffset" : 60348
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 4332,
+            "byteOffset" : 63236
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 4332,
+            "byteOffset" : 67568
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 2888,
+            "byteOffset" : 71900
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 2888,
+            "byteOffset" : 74788
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 4332,
+            "byteOffset" : 77676
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 4332,
+            "byteOffset" : 82008
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 2888,
+            "byteOffset" : 86340
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 89228
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 89276
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 89324
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 89356
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 89388
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 89436
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 89484
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 89516
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 89548
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 48,
+            "byteOffset" : 89596
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 32,
+            "byteOffset" : 89644
+        }
+    ],
+    "buffers" : [
+        {
+            "byteLength" : 89676,
+            "uri" : "TextureTransformMultiTest.bin"
+        }
+    ]
+}
index 30ad93f..069941c 100644 (file)
@@ -538,6 +538,7 @@ int UtcDaliGltfLoaderSuccessShort(void)
         "MorphPrimitivesTest",
         "MRendererTest",
         "SimpleSparseAccessor",
+        "TextureTransformMultiTest",
         "AnimatedCube",
         /**
          * For the Avocado glTF file and its Assets
@@ -944,3 +945,48 @@ int UtcDaliGltfLoaderQuantizedMesh(void)
 
   END_TEST;
 }
+
+int UtcDaliGltfLoaderTextureTransform(void)
+{
+  Context ctx;
+
+  auto& resources = ctx.resources;
+
+  /**
+   * For the Avocado glTF file and its Assets
+   * Donated by Microsoft for glTF testing
+   * Take from https://github.com/KhronosGroup/glTF-Sample-Models/blob/master/2.0/Avocado/glTF-Quantized
+   */
+  ctx.loader.LoadModel(TEST_RESOURCE_DIR "/AvocadoQuantized.gltf", ctx.loadResult);
+
+  auto& scene = ctx.scene;
+  DALI_TEST_EQUAL(1u, scene.GetRoots().size());
+  DALI_TEST_EQUAL(1u, scene.GetNodeCount());
+
+  TestApplication app;
+
+  Customization::Choices choices;
+  for(auto iRoot : scene.GetRoots())
+  {
+    auto resourceRefs = resources.CreateRefCounter();
+    scene.CountResourceRefs(iRoot, choices, resourceRefs);
+    resources.mReferenceCounts = std::move(resourceRefs);
+    resources.CountEnvironmentReferences();
+    resources.LoadResources(ctx.pathProvider);
+  }
+
+  auto& materials = resources.mMaterials;
+  DALI_TEST_EQUAL(1u, materials.size());
+
+  auto  iMaterial = materials.begin();
+  auto& md        = iMaterial->first;
+
+  DALI_TEST_EQUAL(3u, md.mTextureStages.size());
+
+  Matrix3 textureTransformGroundTruth(0.000238f, 0.0f, 0.0f, 0.0f, 0.000242f, 0.0f, 0.00678f, 0.002982f, 1.0f);
+  DALI_TEST_EQUALS(md.mTextureStages[0].mTexture.mTransform, textureTransformGroundTruth, 0.01f, TEST_LOCATION);
+  DALI_TEST_EQUALS(md.mTextureStages[1].mTexture.mTransform, textureTransformGroundTruth, 0.01f, TEST_LOCATION);
+  DALI_TEST_EQUALS(md.mTextureStages[2].mTexture.mTransform, textureTransformGroundTruth, 0.01f, TEST_LOCATION);
+
+  END_TEST;
+}
index e3bc2d2..38eb937 100644 (file)
@@ -265,6 +265,13 @@ int UtcDaliMaterialCheckUniform(void)
   DALI_TEST_EQUALS(FaceCullingMode::BACK, renderer.GetProperty<FaceCullingMode::Type>(Dali::Renderer::Property::FACE_CULLING_MODE), TEST_LOCATION);
   DALI_TEST_EQUALS(DepthTestMode::ON, renderer.GetProperty<DepthTestMode::Type>(Dali::Renderer::Property::DEPTH_TEST_MODE), TEST_LOCATION);
 
+  DALI_TEST_EQUALS(0.0f, renderer.GetProperty<float>(renderer.GetPropertyIndex("uBaseColorTextureTransformAvailable")), TEST_LOCATION);
+  DALI_TEST_EQUALS(0.0f, renderer.GetProperty<float>(renderer.GetPropertyIndex("uNormalTextureTransformAvailable")), TEST_LOCATION);
+  DALI_TEST_EQUALS(0.0f, renderer.GetProperty<float>(renderer.GetPropertyIndex("uNormalRoughnessTextureTransformAvailable")), TEST_LOCATION);
+  DALI_TEST_EQUALS(0.0f, renderer.GetProperty<float>(renderer.GetPropertyIndex("uMetalRoughnessTextureTransformAvailable")), TEST_LOCATION);
+  DALI_TEST_EQUALS(0.0f, renderer.GetProperty<float>(renderer.GetPropertyIndex("uOcclusionTextureTransformAvailable")), TEST_LOCATION);
+  DALI_TEST_EQUALS(0.0f, renderer.GetProperty<float>(renderer.GetPropertyIndex("uEmissiveTextureTransformAvailable")), TEST_LOCATION);
+
   END_TEST;
 }
 
index 191a631..f17dcb3 100644 (file)
@@ -255,6 +255,7 @@ int UtcDaliShaderManagerProduceShader(void)
     MeshDefinition     meshDefinition;
     MaterialDefinition materialDefinition;
     ShaderParameters   shaderParameter{meshDefinition, materialDefinition, nodeDefinition};
+
     // Only define skinning accessors for skinning test...
     if(permutationSet.permutations.size() > 1)
     {
@@ -280,6 +281,8 @@ int UtcDaliShaderManagerProduceShader(void)
       {
         option1.AddOption(optionType);
       }
+      // No permutation uses extra joint weights.
+      option1.AddJointMacros(0);
       rendererState = (rendererState | permutation->rendererStateSet) & ~permutation->rendererStateClear;
     }
     option1.AddOption(ShaderOption::Type::THREE_TEXTURE);
index 6678d8d..204ca22 100644 (file)
@@ -723,8 +723,11 @@ void AsyncTaskManager::RemoveTask(AsyncTaskPtr task)
         {
           // We cannot erase container. Just mark as canceled.
           // Note : mAvaliableLowPriorityTaskCounts will be increased after process finished.
-          (*iterator).second = RunningTaskState::CANCELED;
-          ++removedCount;
+          if((*iterator).second == RunningTaskState::RUNNING)
+          {
+            (*iterator).second = RunningTaskState::CANCELED;
+            ++removedCount;
+          }
         }
         ++iterator;
       }
@@ -738,8 +741,11 @@ void AsyncTaskManager::RemoveTask(AsyncTaskPtr task)
       {
         if((*iterator).first == task)
         {
+          if((*iterator).second == CompletedTaskState::REQUIRE_CALLBACK)
+          {
+            ++removedCount;
+          }
           iterator = mCompletedTasks.erase(iterator);
-          ++removedCount;
         }
         else
         {
@@ -749,7 +755,7 @@ void AsyncTaskManager::RemoveTask(AsyncTaskPtr task)
     }
 
     // Remove TasksCompleted callback trace
-    if(mTasksCompletedImpl->IsTasksCompletedCallbackExist() && removedCount > 0u)
+    if(removedCount > 0u && mTasksCompletedImpl->IsTasksCompletedCallbackExist())
     {
       mTasksCompletedImpl->RemoveTaskTrace(task, removedCount);
     }
@@ -787,28 +793,40 @@ Dali::AsyncTaskManager::TasksCompletedId AsyncTaskManager::SetCompletedCallback(
         // Collect all tasks from running tasks
         for(auto& taskPair : mRunningTasks)
         {
-          auto& task      = taskPair.first;
-          auto  checkMask = (task->GetCallbackInvocationThread() == Dali::AsyncTask::ThreadType::MAIN_THREAD ? Dali::AsyncTaskManager::CompletedCallbackTraceMask::THREAD_MASK_MAIN : Dali::AsyncTaskManager::CompletedCallbackTraceMask::THREAD_MASK_WORKER) |
-                           (task->GetPriorityType() == Dali::AsyncTask::PriorityType::HIGH ? Dali::AsyncTaskManager::CompletedCallbackTraceMask::PRIORITY_MASK_HIGH : Dali::AsyncTaskManager::CompletedCallbackTraceMask::PRIORITY_MASK_LOW);
-
-          if((checkMask & mask) == checkMask)
+          // Trace only if it is running now.
+          if(taskPair.second == RunningTaskState::RUNNING)
           {
-            taskAdded = true;
-            mTasksCompletedImpl->AppendTaskTrace(tasksCompletedId, task);
+            auto& task      = taskPair.first;
+            auto  checkMask = (task->GetCallbackInvocationThread() == Dali::AsyncTask::ThreadType::MAIN_THREAD ? Dali::AsyncTaskManager::CompletedCallbackTraceMask::THREAD_MASK_MAIN : Dali::AsyncTaskManager::CompletedCallbackTraceMask::THREAD_MASK_WORKER) |
+                             (task->GetPriorityType() == Dali::AsyncTask::PriorityType::HIGH ? Dali::AsyncTaskManager::CompletedCallbackTraceMask::PRIORITY_MASK_HIGH : Dali::AsyncTaskManager::CompletedCallbackTraceMask::PRIORITY_MASK_LOW);
+
+            if((checkMask & mask) == checkMask)
+            {
+              taskAdded = true;
+              mTasksCompletedImpl->AppendTaskTrace(tasksCompletedId, task);
+            }
           }
         }
 
         // Collect all tasks from complete tasks
         for(auto& taskPair : mCompletedTasks)
         {
-          auto& task      = taskPair.first;
-          auto  checkMask = (task->GetCallbackInvocationThread() == Dali::AsyncTask::ThreadType::MAIN_THREAD ? Dali::AsyncTaskManager::CompletedCallbackTraceMask::THREAD_MASK_MAIN : Dali::AsyncTaskManager::CompletedCallbackTraceMask::THREAD_MASK_WORKER) |
-                           (task->GetPriorityType() == Dali::AsyncTask::PriorityType::HIGH ? Dali::AsyncTaskManager::CompletedCallbackTraceMask::PRIORITY_MASK_HIGH : Dali::AsyncTaskManager::CompletedCallbackTraceMask::PRIORITY_MASK_LOW);
-
-          if((checkMask & mask) == checkMask)
+          // Trace only if it is need callback.
+          // Note : There are two CompletedTaskState::SKIP_CALLBACK cases, worker thread invocation and canceled cases.
+          //        If worker thread invocation, than it already remove trace at completed timing.
+          //        If canceled cases, we don't append trace at running tasks already.
+          //        So, we don't need to trace for SKIP_CALLBACK cases.
+          if(taskPair.second == CompletedTaskState::REQUIRE_CALLBACK)
           {
-            taskAdded = true;
-            mTasksCompletedImpl->AppendTaskTrace(tasksCompletedId, task);
+            auto& task      = taskPair.first;
+            auto  checkMask = (task->GetCallbackInvocationThread() == Dali::AsyncTask::ThreadType::MAIN_THREAD ? Dali::AsyncTaskManager::CompletedCallbackTraceMask::THREAD_MASK_MAIN : Dali::AsyncTaskManager::CompletedCallbackTraceMask::THREAD_MASK_WORKER) |
+                             (task->GetPriorityType() == Dali::AsyncTask::PriorityType::HIGH ? Dali::AsyncTaskManager::CompletedCallbackTraceMask::PRIORITY_MASK_HIGH : Dali::AsyncTaskManager::CompletedCallbackTraceMask::PRIORITY_MASK_LOW);
+
+            if((checkMask & mask) == checkMask)
+            {
+              taskAdded = true;
+              mTasksCompletedImpl->AppendTaskTrace(tasksCompletedId, task);
+            }
           }
         }
       }
index 92e54d4..726a7b8 100644 (file)
@@ -29,6 +29,7 @@
 #include <dali-toolkit/internal/visuals/npatch-loader.h>
 #include <dali/devel-api/adaptor-framework/image-loading.h>
 #include <dali/integration-api/debug.h>
+#include <dali/integration-api/adaptor-framework/shader-precompiler.h>
 
 using namespace Dali;
 using namespace Dali::Toolkit;
@@ -2788,3 +2789,41 @@ int UtcDaliVisualFactoryGetAnimatedImageVisual2(void)
 
   END_TEST;
 }
+
+
+int UtcDaliVisualFactoryGetPreCompiler(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliVisualFactoryGetAnimatedImageVisual2: Request animated image visual with a Property::Map, test custom wrap mode and pixel area");
+
+
+  std::vector<RawShaderData> precompiledShaderList;
+  DALI_TEST_CHECK(precompiledShaderList.size() == 0u); // before Get Shader
+  ShaderPreCompiler::Get().GetPreCompileShaderList(precompiledShaderList);
+  DALI_TEST_CHECK(precompiledShaderList.size() == 0u); // after Get Shader
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK(factory);
+
+  factory.UsePreCompiledShader();
+
+  ShaderPreCompiler::Get().GetPreCompileShaderList(precompiledShaderList);
+  DALI_TEST_CHECK(precompiledShaderList.size() != 0u); // after Get Shader
+
+  Property::Map propertyMap;
+  propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE);
+  propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME);
+  Visual::Base visual = factory.CreateVisual(propertyMap);
+  DALI_TEST_CHECK(visual);
+
+  DummyControl      actor     = DummyControl::New(true);
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual(Control::CONTROL_PROPERTY_END_INDEX + 1, visual);
+  actor.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f));
+  application.GetScene().Add(actor);
+
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
index d8ce462..c205433 100644 (file)
@@ -178,7 +178,7 @@ void ColliderMeshProcessor::Process(bool /* postProcess */)
   std::sort(mSceneViewsToProcess.begin(), mSceneViewsToProcess.end());
   mSceneViewsToProcess.erase(std::unique(mSceneViewsToProcess.begin(), mSceneViewsToProcess.end()), mSceneViewsToProcess.end());
 
-  for(auto sceneView : mSceneViewsToProcess)
+  for(auto& sceneView : mSceneViewsToProcess)
   {
     std::vector<ColliderMeshData> meshData;
     IterateThroughChildren(sceneView, meshData);
index db3c146..a77b5fa 100644 (file)
@@ -40,26 +40,42 @@ uniform lowp float uDielectricSpecular;
 #ifdef THREE_TEX
 #ifdef BASECOLOR_TEX
 uniform sampler2D sAlbedoAlpha;
+uniform float uBaseColorTextureTransformAvailable;
+uniform mat3 uBaseColorTextureTransform;
 #endif // BASECOLOR_TEX
 #ifdef METALLIC_ROUGHNESS_TEX
 uniform sampler2D sMetalRoughness;
+uniform float uMetalRoughnessTextureTransformAvailable;
+uniform mat3 uMetalRoughnessTextureTransform;
 #endif // METALLIC_ROUGHNESS_TEX
 #ifdef NORMAL_TEX
 uniform sampler2D sNormal;
+uniform float uNormalTextureTransformAvailable;
+uniform mat3 uNormalTextureTransform;
 uniform float uNormalScale;
 #endif // NORMAL_TEX
 #else // THREE_TEX
 uniform sampler2D sAlbedoMetal;
+uniform float uBaseColorTextureTransformAvailable;
+uniform mat3 uBaseColorTextureTransform;
 uniform sampler2D sNormalRoughness;
+uniform float uNormalRoughnessTextureTransformAvailable;
+uniform mat3 uNormalRoughnessTextureTransform;
 #endif
 
+
+
 #ifdef OCCLUSION
 uniform sampler2D sOcclusion;
+uniform float uOcclusionTextureTransformAvailable;
+uniform mat3 uOcclusionTextureTransform;
 uniform float uOcclusionStrength;
 #endif
 
 #ifdef EMISSIVE_TEXTURE
 uniform sampler2D sEmissive;
+uniform float uEmissiveTextureTransformAvailable;
+uniform mat3 uEmissiveTextureTransform;
 #endif
 uniform vec3 uEmissiveFactor;
 
@@ -127,6 +143,11 @@ vec3 linear(vec3 color)
   return pow(color, vec3(2.2));
 }
 
+vec2 computeTextureTransform(vec2 texCoord, mat3 textureTransform)
+{
+    return vec2(textureTransform * vec3(texCoord, 1.0));
+}
+
 void main()
 {
   // Metallic and Roughness material properties are packed together
@@ -142,29 +163,34 @@ void main()
 #ifdef THREE_TEX
   // The albedo may be defined from a base texture or a flat color
 #ifdef BASECOLOR_TEX
-  lowp vec4 baseColor = texture(sAlbedoAlpha, vUV);
+  mediump vec2 baseColorTexCoords = mix(vUV, computeTextureTransform(vUV, uBaseColorTextureTransform), uBaseColorTextureTransformAvailable);
+  lowp vec4 baseColor = texture(sAlbedoAlpha, baseColorTexCoords);
   baseColor = vColor * vec4(linear(baseColor.rgb), baseColor.w) * uColorFactor;
 #else // BASECOLOR_TEX
   lowp vec4 baseColor = vColor * uColorFactor;
 #endif // BASECOLOR_TEX
 
 #ifdef METALLIC_ROUGHNESS_TEX
-  lowp vec4 metrou = texture(sMetalRoughness, vUV);
+  mediump vec2 metalRoughnessTexCoords = mix(vUV, computeTextureTransform(vUV, uMetalRoughnessTextureTransform), uMetalRoughnessTextureTransformAvailable);
+  lowp vec4 metrou = texture(sMetalRoughness, metalRoughnessTexCoords);
   metallic = metrou.METALLIC * metallic;
   perceptualRoughness = metrou.ROUGHNESS * perceptualRoughness;
 #endif // METALLIC_ROUGHNESS_TEX
 
 #ifdef NORMAL_TEX
-  n = texture(sNormal, vUV).rgb;
+  mediump vec2 normalTexCoords = mix(vUV, computeTextureTransform(vUV, uNormalTextureTransform), uNormalTextureTransformAvailable);
+  n = texture(sNormal, normalTexCoords).rgb;
   n = normalize(vTBN * ((2.0 * n - 1.0) * vec3(uNormalScale, uNormalScale, 1.0)));
 #endif // NORMAL_TEX
 #else // THREE_TEX
-  vec4 albedoMetal = texture(sAlbedoMetal, vUV);
+  mediump vec2 baseColorTexCoords = mix(vUV, computeTextureTransform(vUV, uBaseColorTextureTransform), uBaseColorTextureTransformAvailable);
+  vec4 albedoMetal = texture(sAlbedoMetal, baseColorTexCoords);
   lowp vec4 baseColor = vec4(linear(albedoMetal.rgb), 1.0) * vColor * uColorFactor;
 
   metallic = albedoMetal.METALLIC * metallic;
 
-  vec4 normalRoughness = texture(sNormalRoughness, vUV);
+  mediump vec2 normalRoughnessTexCoords = mix(vUV, computeTextureTransform(vUV, uNormalRoughnessTextureTransform), uNormalRoughnessTextureTransformAvailable);
+  vec4 normalRoughness = texture(sNormalRoughness, normalRoughnessTexCoords);
   perceptualRoughness = normalRoughness.ROUGHNESS * perceptualRoughness;
 
   n = normalRoughness.rgb;
@@ -290,12 +316,14 @@ void main()
   }
 
 #ifdef OCCLUSION
-  lowp float ao = texture(sOcclusion, vUV).r;
+  mediump vec2 occlusionTexCoords = mix(vUV, computeTextureTransform(vUV, uOcclusionTextureTransform), uOcclusionTextureTransformAvailable);
+  lowp float ao = texture(sOcclusion, occlusionTexCoords).r;
   color = mix(color, color * ao, uOcclusionStrength);
 #endif // OCCLUSION
 
 #ifdef EMISSIVE_TEXTURE
-  lowp vec3 emissive = linear(texture(sEmissive, vUV).rgb) * uEmissiveFactor;
+  mediump vec2 emissiveTexCoords = mix(vUV, computeTextureTransform(vUV, uEmissiveTextureTransform), uEmissiveTextureTransformAvailable);
+  lowp vec3 emissive = linear(texture(sEmissive, emissiveTexCoords).rgb) * uEmissiveFactor;
 #else
   lowp vec3 emissive = uEmissiveFactor;
 #endif // EMISSIVE_TEXTURE
index 7ea0654..fc0bff7 100644 (file)
@@ -6,7 +6,10 @@
 
 #define MORPH defined(MORPH_POSITION) || defined(MORPH_NORMAL) || defined(MORPH_TANGENT)
 
-// If needed, define these strings in code, insert after each.
+// These lines in the shader may be replaced with actual definitions by the model loader,
+// if they are needed. Note, some shader compilers have problems with spurious ";", so
+// the macro invocations don't have a trailing ";". The replacement strings in the model
+// loader will provide it instead.
 #define ADD_EXTRA_SKINNING_ATTRIBUTES
 #define ADD_EXTRA_WEIGHTS
 
@@ -31,7 +34,7 @@ in vec4 aVertexColor;
 #ifdef SKINNING
 in vec4 aJoints0;
 in vec4 aWeights0;
-ADD_EXTRA_SKINNING_ATTRIBUTES;
+ADD_EXTRA_SKINNING_ATTRIBUTES
 #endif
 
 #ifdef MORPH
@@ -165,7 +168,7 @@ void main()
     uBone[int(aJoints0.z)] * aWeights0.z +
     uBone[int(aJoints0.w)] * aWeights0.w;
 
-  ADD_EXTRA_WEIGHTS;
+  ADD_EXTRA_WEIGHTS
 
   position = bone * position;
   normal = uYDirection * (bone * vec4(normal, 0.0)).xyz;
index e90cf38..16c7cd8 100644 (file)
@@ -20,7 +20,9 @@
 // EXTERNAL INCLUDES
 #include <dali/devel-api/common/map-wrapper.h>
 #include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/math/matrix3.h>
 #include <dali/public-api/math/quaternion.h>
+#include <dali/public-api/math/vector2.h>
 #include <dali/public-api/math/vector4.h>
 #include <cstdint>
 #include <memory>
@@ -375,6 +377,39 @@ struct Texture
   Ref<Sampler> mSampler;
 };
 
+struct TextureTransform
+{
+  float         mRotation = 0.0f;
+  Dali::Vector2 mUvOffset = Dali::Vector2::ZERO;
+  Dali::Vector2 mUvScale  = Dali::Vector2::ONE;
+  uint32_t      mTexCoord = 0u;
+
+  operator bool() const
+  {
+    return !Dali::EqualsZero(mRotation) || mUvOffset != Dali::Vector2::ZERO || mUvScale != Dali::Vector2::ONE || mTexCoord != 0u;
+  }
+
+  const Dali::Matrix3 GetTransform() const
+  {
+    // See: https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_texture_transform
+    Dali::Matrix3 translation = Dali::Matrix3(1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, mUvOffset.x, mUvOffset.y, 1.0f);
+    Dali::Matrix3 rotation    = Dali::Matrix3(cos(-mRotation), sin(-mRotation), 0.0f, -sin(-mRotation), cos(-mRotation), 0.0f, 0.0f, 0.0f, 1.0f);
+    Dali::Matrix3 scale       = Dali::Matrix3(mUvScale.x, 0.0f, 0.0f, 0.0f, mUvScale.y, 0.0f, 0.0f, 0.0f, 1.0f);
+
+    return translation * rotation * scale;
+  }
+};
+
+struct TextureExtensions
+{
+  TextureTransform mTextureTransform;
+
+  operator bool() const
+  {
+    return mTextureTransform;
+  }
+};
+
 struct TextureInfo
 {
   Ref<gltf2::Texture> mTexture;
@@ -382,9 +417,11 @@ struct TextureInfo
   float               mScale    = 1.f;
   float               mStrength = 1.f;
 
+  TextureExtensions mTextureExtensions;
+
   operator bool() const
   {
-    return !!mTexture;
+    return mTexture;
   }
 };
 
index c4e492f..7979786 100644 (file)
@@ -49,12 +49,12 @@ static const Geometry::Type GLTF2_TO_DALI_PRIMITIVES[]{
   Geometry::TRIANGLE_FAN}; //...because Dali swaps the last two.
 
 static const Dali::Scripting::StringEnum EXTENSION_STRING_TABLE[] =
-{
-  {"NONE", gltf2::ExtensionFlags::NONE},
-  {"KHR_mesh_quantization", gltf2::ExtensionFlags::KHR_MESH_QUANTIZATION},
-  {"KHR_texture_transform", gltf2::ExtensionFlags::KHR_TEXTURE_TRANSFORM},
-  {"KHR_materials_ior", gltf2::ExtensionFlags::KHR_MATERIALS_IOR},
-  {"KHR_materials_specular", gltf2::ExtensionFlags::KHR_MATERIALS_SPECULAR},
+  {
+    {"NONE", gltf2::ExtensionFlags::NONE},
+    {"KHR_mesh_quantization", gltf2::ExtensionFlags::KHR_MESH_QUANTIZATION},
+    {"KHR_texture_transform", gltf2::ExtensionFlags::KHR_TEXTURE_TRANSFORM},
+    {"KHR_materials_ior", gltf2::ExtensionFlags::KHR_MATERIALS_IOR},
+    {"KHR_materials_specular", gltf2::ExtensionFlags::KHR_MATERIALS_SPECULAR},
 };
 static const unsigned int EXTENSION_STRING_TABLE_COUNT = sizeof(EXTENSION_STRING_TABLE) / sizeof(EXTENSION_STRING_TABLE[0]);
 
@@ -173,13 +173,31 @@ const json::Reader<gltf2::Texture>& GetTextureReader()
   return TEXURE_READER;
 }
 
+const json::Reader<gltf2::TextureTransform>& GetTextureTransformReader()
+{
+  static const auto TEXURE_TRANSFORM_READER = std::move(json::Reader<gltf2::TextureTransform>()
+                                                          .Register(*json::MakeProperty("rotation", json::Read::Number<float>, &gltf2::TextureTransform::mRotation))
+                                                          .Register(*json::MakeProperty("offset", gltf2::ReadDaliVector<Vector2>, &gltf2::TextureTransform::mUvOffset))
+                                                          .Register(*json::MakeProperty("scale", gltf2::ReadDaliVector<Vector2>, &gltf2::TextureTransform::mUvScale))
+                                                          .Register(*json::MakeProperty("texCoord", json::Read::Number<uint32_t>, &gltf2::TextureTransform::mTexCoord)));
+  return TEXURE_TRANSFORM_READER;
+}
+
+const json::Reader<gltf2::TextureExtensions>& GetTextureExtensionsReader()
+{
+  static const auto TEXTURE_EXTENSION_READER = std::move(json::Reader<gltf2::TextureExtensions>()
+                                                           .Register(*json::MakeProperty("KHR_texture_transform", json::ObjectReader<gltf2::TextureTransform>::Read, &gltf2::TextureExtensions::mTextureTransform)));
+  return TEXTURE_EXTENSION_READER;
+}
+
 const json::Reader<gltf2::TextureInfo>& GetTextureInfoReader()
 {
   static const auto TEXURE_INFO_READER = std::move(json::Reader<gltf2::TextureInfo>()
                                                      .Register(*json::MakeProperty("index", gltf2::RefReader<gltf2::Document>::Read<gltf2::Texture, &gltf2::Document::mTextures>, &gltf2::TextureInfo::mTexture))
                                                      .Register(*json::MakeProperty("texCoord", json::Read::Number<uint32_t>, &gltf2::TextureInfo::mTexCoord))
                                                      .Register(*json::MakeProperty("scale", json::Read::Number<float>, &gltf2::TextureInfo::mScale))
-                                                     .Register(*json::MakeProperty("strength", json::Read::Number<float>, &gltf2::TextureInfo::mStrength)));
+                                                     .Register(*json::MakeProperty("strength", json::Read::Number<float>, &gltf2::TextureInfo::mStrength))
+                                                     .Register(*json::MakeProperty("extensions", json::ObjectReader<gltf2::TextureExtensions>::Read, &gltf2::TextureInfo::mTextureExtensions)));
   return TEXURE_INFO_READER;
 }
 
@@ -588,18 +606,23 @@ TextureDefinition ConvertTextureInfo(const gltf2::TextureInfo& textureInfo, Conv
       std::vector<uint8_t> dataBuffer;
       dataBuffer.resize(textureInfo.mTexture->mSource->mBufferView->mByteLength);
       stream.read(reinterpret_cast<char*>(dataBuffer.data()), static_cast<std::streamsize>(static_cast<size_t>(textureInfo.mTexture->mSource->mBufferView->mByteLength)));
-      return TextureDefinition{std::move(dataBuffer), ConvertSampler(textureInfo.mTexture->mSampler), metaData.mMinSize, metaData.mSamplingMode};
+      return TextureDefinition{std::move(dataBuffer), ConvertSampler(textureInfo.mTexture->mSampler), metaData.mMinSize, metaData.mSamplingMode, textureInfo.mTextureExtensions.mTextureTransform.GetTransform()};
     }
     return TextureDefinition();
   }
   else
   {
-    return TextureDefinition{uri, ConvertSampler(textureInfo.mTexture->mSampler), metaData.mMinSize, metaData.mSamplingMode};
+    return TextureDefinition{uri, ConvertSampler(textureInfo.mTexture->mSampler), metaData.mMinSize, metaData.mSamplingMode, textureInfo.mTextureExtensions.mTextureTransform.GetTransform()};
   }
 }
 
 void AddTextureStage(uint32_t semantic, MaterialDefinition& materialDefinition, gltf2::TextureInfo textureInfo, const Dali::Scene3D::Loader::ImageMetadata& metaData, ConversionContext& context)
 {
+  // Overrides the textureInfo texCoord value if KHR_texture_transform extension is supported and texCoord value is supplied.
+  if(textureInfo.mTextureExtensions && textureInfo.mTexCoord != textureInfo.mTextureExtensions.mTextureTransform.mTexCoord && textureInfo.mTextureExtensions.mTextureTransform.mTexCoord != 0u)
+  {
+    textureInfo.mTexCoord = textureInfo.mTextureExtensions.mTextureTransform.mTexCoord;
+  }
   materialDefinition.mTextureStages.push_back({semantic, ConvertTextureInfo(textureInfo, context, metaData)});
   materialDefinition.mFlags |= semantic;
 }
@@ -767,19 +790,20 @@ MeshDefinition::Accessor ConvertMeshPrimitiveAccessor(const gltf2::Accessor& acc
 
   return MeshDefinition::Accessor{
     std::move(MeshDefinition::Blob{bufferViewOffset + accessor.mByteOffset,
-          accessor.GetBytesLength(),
-          static_cast<uint16_t>(bufferViewStride),
-          static_cast<uint16_t>(accessor.GetElementSizeBytes()),
-          accessor.mMin,
-          accessor.mMax}),
-      std::move(sparseBlob),
-      accessor.mBufferView ? accessor.mBufferView->mBuffer.GetIndex() : 0,
-      accessor.mNormalized};
+                                   accessor.GetBytesLength(),
+                                   static_cast<uint16_t>(bufferViewStride),
+                                   static_cast<uint16_t>(accessor.GetElementSizeBytes()),
+                                   accessor.mMin,
+                                   accessor.mMax}),
+    std::move(sparseBlob),
+    accessor.mBufferView ? accessor.mBufferView->mBuffer.GetIndex() : 0,
+    accessor.mNormalized};
 }
 
 MeshDefinition::Accessor* GetAccessorFromAttribute(gltf2::Attribute::HashType attributeHash,
-                                                   MeshDefinition& meshDefinition,
-                                                   bool& needNormals, bool& needTangents)
+                                                   MeshDefinition&            meshDefinition,
+                                                   bool&                      needNormals,
+                                                   bool&                      needTangents)
 {
   MeshDefinition::Accessor* accessorDest{nullptr};
 
@@ -841,10 +865,10 @@ MeshDefinition::Accessor* GetAccessorFromAttribute(gltf2::Attribute::HashType at
   return accessorDest;
 }
 
-void SetFlagsFromComponentType(const gltf2::Accessor& accessor,
+void SetFlagsFromComponentType(const gltf2::Accessor&     accessor,
                                gltf2::Attribute::HashType attributeHash,
-                               MeshDefinition& meshDefinition,
-                               bool isQuantized)
+                               MeshDefinition&            meshDefinition,
+                               bool                       isQuantized)
 {
   switch(gltf2::Attribute::TypeFromHash(attributeHash))
   {
@@ -1554,6 +1578,8 @@ void SetObjectReaders()
   json::SetObjectReader(GetImageReader());
   json::SetObjectReader(GetSamplerReader());
   json::SetObjectReader(GetTextureReader());
+  json::SetObjectReader(GetTextureTransformReader());
+  json::SetObjectReader(GetTextureExtensionsReader());
   json::SetObjectReader(GetTextureInfoReader());
   json::SetObjectReader(GetMaterialPbrReader());
   json::SetObjectReader(GetMaterialSpecularReader());
index 69a1a53..0e58ce5 100644 (file)
@@ -679,6 +679,14 @@ void Material::SetRendererUniform(Dali::Renderer renderer)
   renderer.RegisterProperty("uSpecularFactor", mTextureInformations[TextureIndex::SPECULAR].mFactor.x);
   renderer.RegisterProperty("uSpecularColorFactor", Vector3(mTextureInformations[TextureIndex::SPECULAR_COLOR].mFactor));
 
+  // No requirement to use texture transform for runtime generated models.
+  renderer.RegisterProperty("uBaseColorTextureTransformAvailable", 0.0f);
+  renderer.RegisterProperty("uNormalTextureTransformAvailable", 0.0f);
+  renderer.RegisterProperty("uNormalRoughnessTextureTransformAvailable", 0.0f);
+  renderer.RegisterProperty("uMetalRoughnessTextureTransformAvailable", 0.0f);
+  renderer.RegisterProperty("uOcclusionTextureTransformAvailable", 0.0f);
+  renderer.RegisterProperty("uEmissiveTextureTransformAvailable", 0.0f);
+
   float opaque = mIsOpaque ? 1.0f : 0.0f;
   float mask   = mIsMask ? 1.0f : 0.0f;
   renderer.RegisterProperty("uOpaque", opaque);
@@ -752,8 +760,7 @@ void Material::NotifyObserver()
     mObserverNotifying = false;
 
     // Resolve observer queue during notify
-    mObservers.erase(std::remove_if(mObservers.begin(), mObservers.end(), [](auto& e)
-                                    { return !e.second; }),
+    mObservers.erase(std::remove_if(mObservers.begin(), mObservers.end(), [](auto& e) { return !e.second; }),
                      mObservers.end());
   }
 }
index fe45dee..a41b8b5 100644 (file)
@@ -73,6 +73,7 @@ public:
     uint32_t                            mLoadingTaskId{0u};
     uint32_t                            mSemantic;
     Scene3D::Loader::ShaderOption::Type mShaderOptionType;
+    Matrix3                             mTransform{Scene3D::Loader::TextureDefinition::DEFAULT_TRANSFORM};
   };
 
   using TextureInformationContainer = std::vector<TextureInformation>;
@@ -278,10 +279,10 @@ private:
 
 private:
   // Delete copy & move operator
-  Material(const Material&)                = delete;
-  Material(Material&&)                     = delete;
+  Material(const Material&) = delete;
+  Material(Material&&)      = delete;
   Material& operator=(const Material& rhs) = delete;
-  Material& operator=(Material&& rhs)      = delete;
+  Material& operator=(Material&& rhs) = delete;
 
 private:
   ObserverContainer mObservers{}; ///< List of observers who need to be notified after some properties are changed.
index d566163..6b2c8a2 100644 (file)
@@ -432,11 +432,15 @@ void ModelNode::SetColliderMesh(ColliderMeshUniquePtr&& colliderMesh)
   auto handle = Scene3D::ModelNode::DownCast(Self());
   if(mParentModel)
   {
-    if(mColliderMesh || colliderMesh == nullptr)
+    if(mColliderMesh)
     {
       mParentModel->RemoveColliderMesh(handle);
     }
-    mParentModel->RegisterColliderMesh(handle, *colliderMesh);
+
+    if(colliderMesh)
+    {
+      mParentModel->RegisterColliderMesh(handle, *colliderMesh);
+    }
   }
 
   mColliderMesh = std::move(colliderMesh);
index e58327c..48519f7 100644 (file)
@@ -310,6 +310,10 @@ void ModelPrimitive::ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag
       shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::SKINNING);
       shaderOption.AddJointMacros(mNumberOfJointSets);
     }
+    else
+    {
+      shaderOption.AddJointMacros(0);
+    }
     if(mHasVertexColor)
     {
       shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::COLOR_ATTRIBUTE);
@@ -344,13 +348,13 @@ void ModelPrimitive::ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag
       {
         Property::Map oldMap = GetMap(mShader);
         DALI_LOG_WRITE_FILE(tmpFilename("oldShader", ".txt"), "Vertex Shader:\n"
-                            << oldMap["vertex"] << "\n\nFragmentShader: " << oldMap["fragment"] << "\n");
+                                                                << oldMap["vertex"] << "\n\nFragmentShader: " << oldMap["fragment"] << "\n");
       }
       if(newShader)
       {
         Property::Map newMap = GetMap(newShader);
         DALI_LOG_WRITE_FILE(tmpFilename("newShader", ".txt"), "Vertex Shader:\n"
-                            << newMap["vertex"] << "\n\nFragmentShader: " << newMap["fragment"] << "\n");
+                                                                << newMap["vertex"] << "\n\nFragmentShader: " << newMap["fragment"] << "\n");
       }
 #endif
     }
index 0d3cb20..2e6ef5f 100644 (file)
@@ -33,6 +33,8 @@ namespace Scene3D
 {
 namespace Loader
 {
+const Matrix3 TextureDefinition::DEFAULT_TRANSFORM = Matrix3(1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
+
 namespace
 {
 constexpr SamplerFlags::Type FILTER_MODES_FROM_DALI[]{
@@ -152,27 +154,30 @@ Sampler SamplerFlags::MakeSampler(Type flags)
   return sampler;
 }
 
-TextureDefinition::TextureDefinition(const std::string& imageUri, SamplerFlags::Type samplerFlags, ImageDimensions minImageDimensions, SamplingMode::Type samplingMode)
+TextureDefinition::TextureDefinition(const std::string& imageUri, SamplerFlags::Type samplerFlags, ImageDimensions minImageDimensions, SamplingMode::Type samplingMode, Matrix3 transform)
 : mImageUri(imageUri),
   mSamplerFlags(samplerFlags),
   mMinImageDimensions(minImageDimensions),
-  mSamplingMode(samplingMode)
+  mSamplingMode(samplingMode),
+  mTransform(transform)
 {
 }
 
-TextureDefinition::TextureDefinition(std::string&& imageUri, SamplerFlags::Type samplerFlags, ImageDimensions minImageDimensions, SamplingMode::Type samplingMode)
+TextureDefinition::TextureDefinition(std::string&& imageUri, SamplerFlags::Type samplerFlags, ImageDimensions minImageDimensions, SamplingMode::Type samplingMode, Matrix3 transform)
 : mImageUri(std::move(imageUri)),
   mSamplerFlags(samplerFlags),
   mMinImageDimensions(minImageDimensions),
-  mSamplingMode(samplingMode)
+  mSamplingMode(samplingMode),
+  mTransform(transform)
 {
 }
 
-TextureDefinition::TextureDefinition(std::vector<uint8_t>&& textureBuffer, SamplerFlags::Type samplerFlags, ImageDimensions minImageDimensions, SamplingMode::Type samplingMode)
+TextureDefinition::TextureDefinition(std::vector<uint8_t>&& textureBuffer, SamplerFlags::Type samplerFlags, ImageDimensions minImageDimensions, SamplingMode::Type samplingMode, Matrix3 transform)
 : mImageUri(),
   mSamplerFlags(samplerFlags),
   mMinImageDimensions(minImageDimensions),
   mSamplingMode(samplingMode),
+  mTransform(transform),
   mTextureBuffer(std::move(textureBuffer))
 {
 }
index 39b9153..fcd942d 100644 (file)
@@ -120,16 +120,19 @@ struct DALI_SCENE3D_API SamplerFlags
  */
 struct DALI_SCENE3D_API TextureDefinition
 {
+  static const Matrix3 DEFAULT_TRANSFORM;
+
   std::string          mImageUri; // When the texture is loaded from embedded resources, this URI is used as a data stream.
   std::string          mDirectoryPath;
   SamplerFlags::Type   mSamplerFlags;
   ImageDimensions      mMinImageDimensions;
   SamplingMode::Type   mSamplingMode;
+  Matrix3              mTransform{DEFAULT_TRANSFORM}; // Texture transform
   std::vector<uint8_t> mTextureBuffer;
 
-  TextureDefinition(const std::string& imageUri = "", SamplerFlags::Type samplerFlags = SamplerFlags::DEFAULT, ImageDimensions minImageDimensions = ImageDimensions(), SamplingMode::Type samplingMode = SamplingMode::BOX_THEN_LINEAR);
-  TextureDefinition(std::string&& imageUri, SamplerFlags::Type samplerFlags = SamplerFlags::DEFAULT, ImageDimensions minImageDimensions = ImageDimensions(), SamplingMode::Type samplingMode = SamplingMode::BOX_THEN_LINEAR);
-  TextureDefinition(std::vector<uint8_t>&& textureBuffer, SamplerFlags::Type samplerFlags = SamplerFlags::DEFAULT, ImageDimensions minImageDimensions = ImageDimensions(), SamplingMode::Type samplingMode = SamplingMode::BOX_THEN_LINEAR);
+  TextureDefinition(const std::string& imageUri = "", SamplerFlags::Type samplerFlags = SamplerFlags::DEFAULT, ImageDimensions minImageDimensions = ImageDimensions(), SamplingMode::Type samplingMode = SamplingMode::BOX_THEN_LINEAR, Matrix3 transform = DEFAULT_TRANSFORM);
+  TextureDefinition(std::string&& imageUri, SamplerFlags::Type samplerFlags = SamplerFlags::DEFAULT, ImageDimensions minImageDimensions = ImageDimensions(), SamplingMode::Type samplingMode = SamplingMode::BOX_THEN_LINEAR, Matrix3 transform = DEFAULT_TRANSFORM);
+  TextureDefinition(std::vector<uint8_t>&& textureBuffer, SamplerFlags::Type samplerFlags = SamplerFlags::DEFAULT, ImageDimensions minImageDimensions = ImageDimensions(), SamplingMode::Type samplingMode = SamplingMode::BOX_THEN_LINEAR, Matrix3 transform = DEFAULT_TRANSFORM);
 };
 
 /**
index 6b2feb6..10555aa 100644 (file)
@@ -32,6 +32,34 @@ namespace Dali::Scene3D::Loader
 {
 namespace
 {
+
+enum class LoadDataType
+{
+  UNSIGNED_BYTE = 0,
+  UNSIGNED_SHORT,
+  FLOAT
+};
+
+struct LoadAccessorInputs
+{
+  MeshDefinition::RawData&  rawData;
+  MeshDefinition::Accessor& accessor;
+  uint32_t                  flags;
+  std::fstream&             fileStream;
+  std::string&              meshPath;
+  BufferDefinition::Vector& buffers;
+};
+
+struct LoadAccessorListInputs
+{
+  MeshDefinition::RawData&               rawData;
+  std::vector<MeshDefinition::Accessor>& accessors;
+  uint32_t                               flags;
+  std::fstream&                          fileStream;
+  std::string&                           meshPath;
+  BufferDefinition::Vector&              buffers;
+};
+
 template<bool use32BitIndices>
 class IndexProvider
 {
@@ -210,104 +238,59 @@ bool ReadAccessor(const MeshDefinition::Accessor& accessor, std::istream& source
   return ReadAccessor(accessor, source, target, nullptr);
 }
 
-template<typename T>
-void ReadJointAccessor(MeshDefinition::RawData& raw, const MeshDefinition::Accessor& accessor, std::istream& source, const std::string& meshPath, const std::string& name)
+template<typename T, bool needsNormalize>
+void ReadVectorAccessor(const MeshDefinition::Accessor& accessor, std::istream& source, std::vector<uint8_t>& buffer)
 {
   constexpr auto sizeofBlobUnit = sizeof(T) * 4;
 
   DALI_ASSERT_ALWAYS(((accessor.mBlob.mLength % sizeofBlobUnit == 0) ||
                       accessor.mBlob.mStride >= sizeofBlobUnit) &&
-                     "Joints buffer length not a multiple of element size");
+                     "Buffer length not a multiple of element size");
   const auto inBufferSize  = accessor.mBlob.GetBufferSize();
   const auto outBufferSize = (sizeof(Vector4) / sizeofBlobUnit) * inBufferSize;
 
-  std::vector<uint8_t> buffer(outBufferSize);
-  auto                 inBuffer = buffer.data() + outBufferSize - inBufferSize;
+  buffer.resize(outBufferSize);
+  auto inBuffer = buffer.data() + outBufferSize - inBufferSize;
   if(!ReadAccessor(accessor, source, inBuffer))
   {
-    ExceptionFlinger(ASSERT_LOCATION) << "Failed to read joints from '" << meshPath << "'.";
+    ExceptionFlinger(ASSERT_LOCATION) << "Failed to read vector data from Accessor.";
   }
 
-  if constexpr(sizeofBlobUnit != sizeof(Vector4))
+  if(sizeofBlobUnit != sizeof(Vector4))
   {
     auto       floats = reinterpret_cast<float*>(buffer.data());
     const auto end    = inBuffer + inBufferSize;
     while(inBuffer != end)
     {
       const auto value = *reinterpret_cast<T*>(inBuffer);
-      *floats          = static_cast<float>(value);
+      *floats          = (needsNormalize) ? static_cast<float>(value) / static_cast<float>((1 << (sizeof(T) * 8)) - 1) : static_cast<float>(value);
 
       inBuffer += sizeof(T);
       ++floats;
     }
   }
-  raw.mAttribs.push_back({name, Property::VECTOR4, static_cast<uint32_t>(outBufferSize / sizeof(Vector4)), std::move(buffer)});
-}
-
-void ReadTypedJointAccessor(MeshDefinition::RawData& raw, uint32_t flags, MeshDefinition::Accessor& accessor, std::iostream& stream, std::string& path, const std::string& name)
-{
-  if(MaskMatch(flags, MeshDefinition::U16_JOINT_IDS))
-  {
-    ReadJointAccessor<uint16_t>(raw, accessor, stream, path, name);
-  }
-  else if(MaskMatch(flags, MeshDefinition::U8_JOINT_IDS))
-  {
-    ReadJointAccessor<uint8_t>(raw, accessor, stream, path, name);
-  }
-  else
-  {
-    ReadJointAccessor<float>(raw, accessor, stream, path, name);
-  }
 }
 
-template<typename T>
-void ReadWeightAccessor(MeshDefinition::RawData& raw, const MeshDefinition::Accessor& accessor, std::istream& source, const std::string& meshPath, const std::string& name)
+template<bool needsNormalize>
+void ReadTypedVectorAccessor(LoadDataType loadDataType, MeshDefinition::Accessor& accessor, std::iostream& stream, std::vector<uint8_t>& buffer)
 {
-  constexpr auto sizeofBlobUnit = sizeof(T) * 4;
-
-  DALI_ASSERT_ALWAYS(((accessor.mBlob.mLength % sizeofBlobUnit == 0) ||
-                      accessor.mBlob.mStride >= sizeofBlobUnit) &&
-                     "weights buffer length not a multiple of element size");
-  const auto inBufferSize  = accessor.mBlob.GetBufferSize();
-  const auto outBufferSize = (sizeof(Vector4) / sizeofBlobUnit) * inBufferSize;
-
-  std::vector<uint8_t> buffer(outBufferSize);
-  auto                 inBuffer = buffer.data() + outBufferSize - inBufferSize;
-  if(!ReadAccessor(accessor, source, inBuffer))
+  switch(loadDataType)
   {
-    ExceptionFlinger(ASSERT_LOCATION) << "Failed to read weights from '" << meshPath << "'.";
-  }
-
-  if constexpr(sizeofBlobUnit != sizeof(Vector4))
-  {
-    auto       floats = reinterpret_cast<float*>(buffer.data());
-    const auto end    = inBuffer + inBufferSize;
-    while(inBuffer != end)
+    case LoadDataType::UNSIGNED_SHORT:
     {
-      const auto value = *reinterpret_cast<T*>(inBuffer);
-      // Normalize weight value. value /= 255 for uint8_t weight, and value /= 65535 for uint16_t weight.
-      *floats = static_cast<float>(value) / static_cast<float>((1 << (sizeof(T) * 8)) - 1);
-
-      inBuffer += sizeof(T);
-      ++floats;
+      ReadVectorAccessor<uint16_t, needsNormalize>(accessor, stream, buffer);
+      break;
+    }
+    case LoadDataType::UNSIGNED_BYTE:
+    {
+      ReadVectorAccessor<uint8_t, needsNormalize>(accessor, stream, buffer);
+      break;
+    }
+    default:
+    {
+      ReadVectorAccessor<float, needsNormalize>(accessor, stream, buffer);
+      break;
     }
-  }
-  raw.mAttribs.push_back({name, Property::VECTOR4, static_cast<uint32_t>(outBufferSize / sizeof(Vector4)), std::move(buffer)});
-}
-
-void ReadTypedWeightAccessor(MeshDefinition::RawData& raw, uint32_t flags, MeshDefinition::Accessor& accessor, std::iostream& stream, std::string& path, std::string name)
-{
-  if(MaskMatch(flags, MeshDefinition::U16_WEIGHT))
-  {
-    ReadWeightAccessor<uint16_t>(raw, accessor, stream, path, name);
-  }
-  else if(MaskMatch(flags, MeshDefinition::U8_WEIGHT))
-  {
-    ReadWeightAccessor<uint8_t>(raw, accessor, stream, path, name);
-  }
-  else
-  {
-    ReadWeightAccessor<float>(raw, accessor, stream, path, name);
   }
 }
 
@@ -841,218 +824,58 @@ std::iostream& GetAvailableData(std::fstream& meshStream, const std::string& mes
   return stream;
 }
 
-} // namespace
-
-MeshDefinition::SparseBlob::SparseBlob(const Blob& indices, const Blob& values, uint32_t count)
-: mIndices{indices},
-  mValues{values},
-  mCount{count}
-{
-}
-
-MeshDefinition::SparseBlob::SparseBlob(Blob&& indices, Blob&& values, uint32_t count)
-: mIndices(std::move(indices)),
-  mValues(std::move(values)),
-  mCount{count}
-{
-}
-
-MeshDefinition::Accessor::Accessor(const MeshDefinition::Blob&       blob,
-                                   const MeshDefinition::SparseBlob& sparse,
-                                   Index                             bufferIndex,
-                                   bool                              normalized)
-: mBlob{blob},
-  mSparse{(sparse.mIndices.IsDefined() && sparse.mValues.IsDefined()) ? new SparseBlob{sparse} : nullptr},
-  mBufferIdx(bufferIndex),
-  mNormalized(normalized)
+template<bool needsNormalize>
+void ReadTypedVectorAccessors(LoadAccessorListInputs loadAccessorListInputs, LoadDataType loadDataType, std::string attributeName)
 {
-}
-
-MeshDefinition::Accessor::Accessor(MeshDefinition::Blob&&       blob,
-                                   MeshDefinition::SparseBlob&& sparse,
-                                   Index                        bufferIndex,
-                                   bool                         normalized)
-: mBlob{std::move(blob)},
-  mSparse{(sparse.mIndices.IsDefined() && sparse.mValues.IsDefined()) ? new SparseBlob{std::move(sparse)} : nullptr},
-  mBufferIdx(bufferIndex),
-  mNormalized(normalized)
-{
-}
-
-void MeshDefinition::Blob::ComputeMinMax(std::vector<float>& min, std::vector<float>& max, uint32_t numComponents, uint32_t count, const float* values)
-{
-  min.assign(numComponents, MAXFLOAT);
-  max.assign(numComponents, -MAXFLOAT);
-  for(uint32_t i = 0; i < count; ++i)
+  int setIndex = 0;
+  for(auto& accessor : loadAccessorListInputs.accessors)
   {
-    for(uint32_t j = 0; j < numComponents; ++j)
-    {
-      min[j] = std::min(min[j], *values);
-      max[j] = std::max(max[j], *values);
-      values++;
-    }
+    std::string        pathJoint;
+    auto&              dataStream = GetAvailableData(loadAccessorListInputs.fileStream, loadAccessorListInputs.meshPath, loadAccessorListInputs.buffers[accessor.mBufferIdx], pathJoint);
+    std::ostringstream name;
+    name << attributeName << setIndex++;
+    std::vector<uint8_t> buffer;
+    ReadTypedVectorAccessor<needsNormalize>(loadDataType, accessor, dataStream, buffer);
+    loadAccessorListInputs.rawData.mAttribs.push_back({name.str(), Property::VECTOR4, static_cast<uint32_t>(buffer.size() / sizeof(Vector4)), std::move(buffer)});
   }
 }
 
-void MeshDefinition::Blob::ApplyMinMax(const std::vector<float>& min, const std::vector<float>& max, uint32_t count, float* values, std::vector<uint32_t>* sparseIndices)
+void LoadIndices(LoadAccessorInputs indicesInput)
 {
-  DALI_ASSERT_DEBUG(max.size() == min.size() || max.size() * min.size() == 0);
-  const auto numComponents = std::max(min.size(), max.size());
-
-  using ClampFn   = void (*)(const float*, const float*, uint32_t, float&);
-  ClampFn clampFn = min.empty() ? (max.empty() ? static_cast<ClampFn>(nullptr) : [](const float* min, const float* max, uint32_t i, float& value) { value = std::min(max[i], value); })
-                                : (max.empty() ? [](const float* min, const float* max, uint32_t i, float& value) { value = std::max(min[i], value); }
-                                               : static_cast<ClampFn>([](const float* min, const float* max, uint32_t i, float& value) { value = std::min(std::max(min[i], value), max[i]); }));
-
-  if(!clampFn)
-  {
-    return;
-  }
-
-  auto end = values + count * numComponents;
-  while(values != end)
-  {
-    auto     nextElement = values + numComponents;
-    uint32_t i           = 0;
-    while(values != nextElement)
-    {
-      clampFn(min.data(), max.data(), i, *values);
-      ++values;
-      ++i;
-    }
-  }
-}
-
-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 mLength;
-}
-
-void MeshDefinition::Blob::ComputeMinMax(uint32_t numComponents, uint32_t count, float* values)
-{
-  ComputeMinMax(mMin, mMax, numComponents, count, values);
-}
-
-void MeshDefinition::Blob::ApplyMinMax(uint32_t count, float* values, std::vector<uint32_t>* sparseIndices) const
-{
-  ApplyMinMax(mMin, mMax, count, values, sparseIndices);
-}
-
-void MeshDefinition::RawData::Attrib::AttachBuffer(Geometry& g) const
-{
-  Property::Map attribMap;
-  attribMap[mName]          = mType;
-  VertexBuffer attribBuffer = VertexBuffer::New(attribMap);
-  attribBuffer.SetData(mData.data(), mNumElements);
-
-  g.AddVertexBuffer(attribBuffer);
-}
-
-bool MeshDefinition::IsQuad() const
-{
-  return CaseInsensitiveStringCompare(QUAD, mUri);
-}
-
-bool MeshDefinition::IsSkinned() const
-{
-  return !mJoints.empty() && !mWeights.empty();
-}
-
-bool MeshDefinition::HasVertexColor() const
-{
-  return !mColors.empty();
-}
-
-uint32_t MeshDefinition::GetNumberOfJointSets() const
-{
-  uint32_t number = static_cast<uint32_t>(mJoints.size());
-  if(number > MeshDefinition::MAX_NUMBER_OF_JOINT_SETS)
+  if(indicesInput.accessor.IsDefined())
   {
-    number = MeshDefinition::MAX_NUMBER_OF_JOINT_SETS;
-  }
-  return number;
-}
-
-bool MeshDefinition::HasBlendShapes() const
-{
-  return !mBlendShapes.empty();
-}
-
-void MeshDefinition::RequestNormals()
-{
-  mNormals.mBlob.mLength = mPositions.mBlob.GetBufferSize();
-}
-
-void MeshDefinition::RequestTangents()
-{
-  mTangents.mBlob.mLength = mNormals.mBlob.GetBufferSize();
-}
-
-MeshDefinition::RawData
-MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector& buffers)
-{
-  RawData raw;
-  if(IsQuad())
-  {
-    return raw;
-  }
-
-  std::string meshPath;
-  meshPath = modelsPath + mUri;
-  std::fstream fileStream;
-  if(!mUri.empty())
-  {
-    fileStream.open(meshPath, std::ios::in | std::ios::binary);
-    if(!fileStream.is_open())
+    if(MaskMatch(indicesInput.flags, MeshDefinition::Flags::U32_INDICES))
     {
-      DALI_LOG_ERROR("Fail to open buffer from %s.\n", meshPath.c_str());
-    }
-  }
-
-  if(mIndices.IsDefined())
-  {
-    if(MaskMatch(mFlags, U32_INDICES))
-    {
-      DALI_ASSERT_ALWAYS(((mIndices.mBlob.mLength % sizeof(uint32_t) == 0) ||
-                          mIndices.mBlob.mStride >= sizeof(uint32_t)) &&
+      DALI_ASSERT_ALWAYS(((indicesInput.accessor.mBlob.mLength % sizeof(uint32_t) == 0) ||
+                          indicesInput.accessor.mBlob.mStride >= sizeof(uint32_t)) &&
                          "Index buffer length not a multiple of element size");
-      const auto indexCount = mIndices.mBlob.GetBufferSize() / sizeof(uint32_t);
-      raw.mIndices.resize(indexCount * 2); // NOTE: we need space for uint32_ts initially.
+      const auto indexCount = indicesInput.accessor.mBlob.GetBufferSize() / sizeof(uint32_t);
+      indicesInput.rawData.mIndices.resize(indexCount * 2); // NOTE: we need space for uint32_ts initially.
 
       std::string path;
-      auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mIndices.mBufferIdx], path);
-      if(!ReadAccessor(mIndices, stream, reinterpret_cast<uint8_t*>(raw.mIndices.data())))
+      auto&       stream = GetAvailableData(indicesInput.fileStream, indicesInput.meshPath, indicesInput.buffers[indicesInput.accessor.mBufferIdx], path);
+      if(!ReadAccessor(indicesInput.accessor, stream, reinterpret_cast<uint8_t*>(indicesInput.rawData.mIndices.data())))
       {
         ExceptionFlinger(ASSERT_LOCATION) << "Failed to read indices from '" << path << "'.";
       }
     }
-    else if(MaskMatch(mFlags, U8_INDICES))
+    else if(MaskMatch(indicesInput.flags, MeshDefinition::Flags::U8_INDICES))
     {
-      DALI_ASSERT_ALWAYS(((mIndices.mBlob.mLength % sizeof(uint8_t) == 0) ||
-                          mIndices.mBlob.mStride >= sizeof(uint8_t)) &&
+      DALI_ASSERT_ALWAYS(((indicesInput.accessor.mBlob.mLength % sizeof(uint8_t) == 0) ||
+                          indicesInput.accessor.mBlob.mStride >= sizeof(uint8_t)) &&
                          "Index buffer length not a multiple of element size");
-      const auto indexCount = mIndices.mBlob.GetBufferSize() / sizeof(uint8_t);
-      raw.mIndices.resize(indexCount); // NOTE: we need space for uint16_ts initially.
+      const auto indexCount = indicesInput.accessor.mBlob.GetBufferSize() / sizeof(uint8_t);
+      indicesInput.rawData.mIndices.resize(indexCount); // NOTE: we need space for uint16_ts initially.
 
       std::string path;
-      auto        u8s    = reinterpret_cast<uint8_t*>(raw.mIndices.data()) + indexCount;
-      auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mIndices.mBufferIdx], path);
-      if(!ReadAccessor(mIndices, stream, u8s))
+      auto        u8s    = reinterpret_cast<uint8_t*>(indicesInput.rawData.mIndices.data()) + indexCount;
+      auto&       stream = GetAvailableData(indicesInput.fileStream, indicesInput.meshPath, indicesInput.buffers[indicesInput.accessor.mBufferIdx], path);
+      if(!ReadAccessor(indicesInput.accessor, stream, u8s))
       {
         ExceptionFlinger(ASSERT_LOCATION) << "Failed to read indices from '" << path << "'.";
       }
 
-      auto u16s = raw.mIndices.data();
+      auto u16s = indicesInput.rawData.mIndices.data();
       auto end  = u8s + indexCount;
       while(u8s != end)
       {
@@ -1063,111 +886,113 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector&
     }
     else
     {
-      DALI_ASSERT_ALWAYS(((mIndices.mBlob.mLength % sizeof(unsigned short) == 0) ||
-                          mIndices.mBlob.mStride >= sizeof(unsigned short)) &&
+      DALI_ASSERT_ALWAYS(((indicesInput.accessor.mBlob.mLength % sizeof(unsigned short) == 0) ||
+                          indicesInput.accessor.mBlob.mStride >= sizeof(unsigned short)) &&
                          "Index buffer length not a multiple of element size");
-      raw.mIndices.resize(mIndices.mBlob.mLength / sizeof(unsigned short));
+      indicesInput.rawData.mIndices.resize(indicesInput.accessor.mBlob.mLength / sizeof(unsigned short));
 
       std::string path;
-      auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mIndices.mBufferIdx], path);
-      if(!ReadAccessor(mIndices, stream, reinterpret_cast<uint8_t*>(raw.mIndices.data())))
+      auto&       stream = GetAvailableData(indicesInput.fileStream, indicesInput.meshPath, indicesInput.buffers[indicesInput.accessor.mBufferIdx], path);
+      if(!ReadAccessor(indicesInput.accessor, stream, reinterpret_cast<uint8_t*>(indicesInput.rawData.mIndices.data())))
       {
-        ExceptionFlinger(ASSERT_LOCATION) << "Failed to read indices from '" << path << "'.";
+        ExceptionFlinger(ASSERT_LOCATION) << "Failed to read indicesInput.accessor from '" << path << "'.";
       }
     }
   }
+}
 
-  uint32_t numberOfVertices = 0u;
-
+uint32_t LoadPositions(LoadAccessorInputs positionsInput, bool hasBlendShape)
+{
+  uint32_t             numVector3 = 0u;
   std::vector<Vector3> positions;
-  if(mPositions.IsDefined())
+  if(positionsInput.accessor.IsDefined())
   {
-    const auto bufferSize = mPositions.mBlob.GetBufferSize();
-    uint32_t   numVector3;
+    const auto bufferSize = positionsInput.accessor.mBlob.GetBufferSize();
 
-    if(MaskMatch(mFlags, S8_POSITION) || MaskMatch(mFlags, U8_POSITION))
+    if(MaskMatch(positionsInput.flags, MeshDefinition::Flags::S8_POSITION) || MaskMatch(positionsInput.flags, MeshDefinition::Flags::U8_POSITION))
     {
-      DALI_ASSERT_ALWAYS(((mPositions.mBlob.mLength % (sizeof(uint8_t) * 3) == 0) ||
-                          mPositions.mBlob.mStride >= (sizeof(uint8_t) * 3)) &&
+      DALI_ASSERT_ALWAYS(((positionsInput.accessor.mBlob.mLength % (sizeof(uint8_t) * 3) == 0) ||
+                          positionsInput.accessor.mBlob.mStride >= (sizeof(uint8_t) * 3)) &&
                          "Position buffer length not a multiple of element size");
       numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(uint8_t) * 3));
     }
-    else if(MaskMatch(mFlags, S16_POSITION) || MaskMatch(mFlags, U16_POSITION))
+    else if(MaskMatch(positionsInput.flags, MeshDefinition::Flags::S16_POSITION) || MaskMatch(positionsInput.flags, MeshDefinition::Flags::U16_POSITION))
     {
-      DALI_ASSERT_ALWAYS(((mPositions.mBlob.mLength % (sizeof(uint16_t) * 3) == 0) ||
-                          mPositions.mBlob.mStride >= (sizeof(uint16_t) * 3)) &&
+      DALI_ASSERT_ALWAYS(((positionsInput.accessor.mBlob.mLength % (sizeof(uint16_t) * 3) == 0) ||
+                          positionsInput.accessor.mBlob.mStride >= (sizeof(uint16_t) * 3)) &&
                          "Position buffer length not a multiple of element size");
       numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(uint16_t) * 3));
     }
     else
     {
-      DALI_ASSERT_ALWAYS(((mPositions.mBlob.mLength % sizeof(Vector3) == 0) ||
-                          mPositions.mBlob.mStride >= sizeof(Vector3)) &&
+      DALI_ASSERT_ALWAYS(((positionsInput.accessor.mBlob.mLength % sizeof(Vector3) == 0) ||
+                          positionsInput.accessor.mBlob.mStride >= sizeof(Vector3)) &&
                          "Position buffer length not a multiple of element size");
       numVector3 = static_cast<uint32_t>(bufferSize / sizeof(Vector3));
     }
 
-    numberOfVertices = numVector3;
-
     std::vector<uint8_t> buffer(bufferSize);
 
     std::string path;
-    auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mPositions.mBufferIdx], path);
-    if(!ReadAccessor(mPositions, stream, buffer.data()))
+    auto&       stream = GetAvailableData(positionsInput.fileStream, positionsInput.meshPath, positionsInput.buffers[positionsInput.accessor.mBufferIdx], path);
+    if(!ReadAccessor(positionsInput.accessor, stream, buffer.data()))
     {
       ExceptionFlinger(ASSERT_LOCATION) << "Failed to read positions from '" << path << "'.";
     }
 
-    GetDequantizedData(buffer, 3u, numVector3, mFlags & POSITIONS_MASK, mPositions.mNormalized);
+    GetDequantizedData(buffer, 3u, numVector3, positionsInput.flags & MeshDefinition::FlagMasks::POSITIONS_MASK, positionsInput.accessor.mNormalized);
 
-    if(mPositions.mNormalized)
+    if(positionsInput.accessor.mNormalized)
     {
-      GetDequantizedMinMax(mPositions.mBlob.mMin, mPositions.mBlob.mMax, mFlags & POSITIONS_MASK);
+      GetDequantizedMinMax(positionsInput.accessor.mBlob.mMin, positionsInput.accessor.mBlob.mMax, positionsInput.flags & MeshDefinition::FlagMasks::POSITIONS_MASK);
     }
 
-    if(mPositions.mBlob.mMin.size() != 3u || mPositions.mBlob.mMax.size() != 3u)
+    if(positionsInput.accessor.mBlob.mMin.size() != 3u || positionsInput.accessor.mBlob.mMax.size() != 3u)
     {
-      mPositions.mBlob.ComputeMinMax(3u, numVector3, reinterpret_cast<float*>(buffer.data()));
+      positionsInput.accessor.mBlob.ComputeMinMax(3u, numVector3, reinterpret_cast<float*>(buffer.data()));
     }
     else
     {
-      mPositions.mBlob.ApplyMinMax(numVector3, reinterpret_cast<float*>(buffer.data()));
+      positionsInput.accessor.mBlob.ApplyMinMax(numVector3, reinterpret_cast<float*>(buffer.data()));
     }
 
-    if(HasBlendShapes())
+    if(hasBlendShape)
     {
       positions.resize(numVector3);
       std::copy(buffer.data(), buffer.data() + buffer.size(), reinterpret_cast<uint8_t*>(positions.data()));
     }
 
-    raw.mAttribs.push_back({"aPosition", Property::VECTOR3, numVector3, std::move(buffer)});
+    positionsInput.rawData.mAttribs.push_back({"aPosition", Property::VECTOR3, numVector3, std::move(buffer)});
   }
+  return numVector3;
+}
 
-  const auto isTriangles = mPrimitiveType == Geometry::TRIANGLES;
-  auto       hasNormals  = mNormals.IsDefined();
+bool LoadNormals(LoadAccessorInputs normalsInput, bool isTriangles, uint32_t positionBufferSize)
+{
+  auto       hasNormals  = normalsInput.accessor.IsDefined();
   if(hasNormals)
   {
-    const auto bufferSize = mNormals.mBlob.GetBufferSize();
+    const auto bufferSize = normalsInput.accessor.mBlob.GetBufferSize();
     uint32_t   numVector3;
 
-    if(MaskMatch(mFlags, S8_NORMAL))
+    if(MaskMatch(normalsInput.flags, MeshDefinition::Flags::S8_NORMAL))
     {
-      DALI_ASSERT_ALWAYS(((mNormals.mBlob.mLength % (sizeof(int8_t) * 3) == 0) ||
-                          mNormals.mBlob.mStride >= (sizeof(int8_t) * 3)) &&
+      DALI_ASSERT_ALWAYS(((normalsInput.accessor.mBlob.mLength % (sizeof(int8_t) * 3) == 0) ||
+                          normalsInput.accessor.mBlob.mStride >= (sizeof(int8_t) * 3)) &&
                          "Normal buffer length not a multiple of element size");
       numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(int8_t) * 3));
     }
-    else if(MaskMatch(mFlags, S16_NORMAL))
+    else if(MaskMatch(normalsInput.flags, MeshDefinition::Flags::S16_NORMAL))
     {
-      DALI_ASSERT_ALWAYS(((mNormals.mBlob.mLength % (sizeof(int16_t) * 3) == 0) ||
-                          mNormals.mBlob.mStride >= (sizeof(int16_t) * 3)) &&
+      DALI_ASSERT_ALWAYS(((normalsInput.accessor.mBlob.mLength % (sizeof(int16_t) * 3) == 0) ||
+                          normalsInput.accessor.mBlob.mStride >= (sizeof(int16_t) * 3)) &&
                          "Normal buffer length not a multiple of element size");
       numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(int16_t) * 3));
     }
     else
     {
-      DALI_ASSERT_ALWAYS(((mNormals.mBlob.mLength % sizeof(Vector3) == 0) ||
-                          mNormals.mBlob.mStride >= sizeof(Vector3)) &&
+      DALI_ASSERT_ALWAYS(((normalsInput.accessor.mBlob.mLength % sizeof(Vector3) == 0) ||
+                          normalsInput.accessor.mBlob.mStride >= sizeof(Vector3)) &&
                          "Normal buffer length not a multiple of element size");
       numVector3 = static_cast<uint32_t>(bufferSize / sizeof(Vector3));
     }
@@ -1175,32 +1000,32 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector&
     std::vector<uint8_t> buffer(bufferSize);
 
     std::string path;
-    auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mNormals.mBufferIdx], path);
-    if(!ReadAccessor(mNormals, stream, buffer.data()))
+    auto&       stream = GetAvailableData(normalsInput.fileStream, normalsInput.meshPath, normalsInput.buffers[normalsInput.accessor.mBufferIdx], path);
+    if(!ReadAccessor(normalsInput.accessor, stream, buffer.data()))
     {
       ExceptionFlinger(ASSERT_LOCATION) << "Failed to read normals from '" << path << "'.";
     }
 
-    GetDequantizedData(buffer, 3u, numVector3, mFlags & NORMALS_MASK, mNormals.mNormalized);
+    GetDequantizedData(buffer, 3u, numVector3, normalsInput.flags & MeshDefinition::FlagMasks::NORMALS_MASK, normalsInput.accessor.mNormalized);
 
-    if(mNormals.mNormalized)
+    if(normalsInput.accessor.mNormalized)
     {
-      GetDequantizedMinMax(mNormals.mBlob.mMin, mNormals.mBlob.mMax, mFlags & NORMALS_MASK);
+      GetDequantizedMinMax(normalsInput.accessor.mBlob.mMin, normalsInput.accessor.mBlob.mMax, normalsInput.flags & MeshDefinition::FlagMasks::NORMALS_MASK);
     }
 
-    mNormals.mBlob.ApplyMinMax(numVector3, reinterpret_cast<float*>(buffer.data()));
+    normalsInput.accessor.mBlob.ApplyMinMax(numVector3, reinterpret_cast<float*>(buffer.data()));
 
-    raw.mAttribs.push_back({"aNormal", Property::VECTOR3, numVector3, std::move(buffer)});
+    normalsInput.rawData.mAttribs.push_back({"aNormal", Property::VECTOR3, numVector3, std::move(buffer)});
   }
-  else if(mNormals.mBlob.mLength != 0 && isTriangles)
+  else if(normalsInput.accessor.mBlob.mLength != 0 && isTriangles)
   {
-    DALI_ASSERT_DEBUG(mNormals.mBlob.mLength == mPositions.mBlob.GetBufferSize());
-    static const std::function<bool(RawData&)> GenerateNormalsFunction[2] =
+    DALI_ASSERT_DEBUG(normalsInput.accessor.mBlob.mLength == positionBufferSize);
+    static const std::function<bool(MeshDefinition::RawData&)> GenerateNormalsFunction[2] =
       {
         GenerateNormals<false>,
         GenerateNormals<true>,
       };
-    const bool generateSuccessed = GenerateNormalsFunction[MaskMatch(mFlags, U32_INDICES)](raw);
+    const bool generateSuccessed = GenerateNormalsFunction[MaskMatch(normalsInput.flags, MeshDefinition::Flags::U32_INDICES)](normalsInput.rawData);
     if(!generateSuccessed)
     {
       DALI_LOG_ERROR("Failed to generate normal\n");
@@ -1210,21 +1035,25 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector&
       hasNormals = true;
     }
   }
+  return hasNormals;
+}
 
-  if(!mTexCoords.empty() && mTexCoords[0].IsDefined())
+void LoadTextureCoordinates(LoadAccessorListInputs textureCoordinatesInput)
+{
+  if(!textureCoordinatesInput.accessors.empty() && textureCoordinatesInput.accessors[0].IsDefined())
   {
-    auto& texCoords = mTexCoords[0];
+    auto&      texCoords  = textureCoordinatesInput.accessors[0];
     const auto bufferSize = texCoords.mBlob.GetBufferSize();
     uint32_t uvCount;
 
-    if(MaskMatch(mFlags, S8_TEXCOORD) || MaskMatch(mFlags, U8_TEXCOORD))
+    if(MaskMatch(textureCoordinatesInput.flags, MeshDefinition::Flags::S8_TEXCOORD) || MaskMatch(textureCoordinatesInput.flags, MeshDefinition::Flags::U8_TEXCOORD))
     {
       DALI_ASSERT_ALWAYS(((texCoords.mBlob.mLength % (sizeof(uint8_t) * 2) == 0) ||
                           texCoords.mBlob.mStride >= (sizeof(uint8_t) * 2)) &&
                          "TexCoords buffer length not a multiple of element size");
       uvCount = static_cast<uint32_t>(bufferSize / (sizeof(uint8_t) * 2));
     }
-    else if(MaskMatch(mFlags, S16_TEXCOORD) || MaskMatch(mFlags, U16_TEXCOORD))
+    else if(MaskMatch(textureCoordinatesInput.flags, MeshDefinition::Flags::S16_TEXCOORD) || MaskMatch(textureCoordinatesInput.flags, MeshDefinition::Flags::U16_TEXCOORD))
     {
       DALI_ASSERT_ALWAYS(((texCoords.mBlob.mLength % (sizeof(uint16_t) * 2) == 0) ||
                           texCoords.mBlob.mStride >= (sizeof(uint16_t) * 2)) &&
@@ -1242,15 +1071,15 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector&
     std::vector<uint8_t> buffer(bufferSize);
 
     std::string path;
-    auto&       stream = GetAvailableData(fileStream, meshPath, buffers[texCoords.mBufferIdx], path);
+    auto&       stream = GetAvailableData(textureCoordinatesInput.fileStream, textureCoordinatesInput.meshPath, textureCoordinatesInput.buffers[texCoords.mBufferIdx], path);
     if(!ReadAccessor(texCoords, stream, buffer.data()))
     {
       ExceptionFlinger(ASSERT_LOCATION) << "Failed to read uv-s from '" << path << "'.";
     }
 
-    GetDequantizedData(buffer, 2u, uvCount, mFlags & TEXCOORDS_MASK, texCoords.mNormalized);
+    GetDequantizedData(buffer, 2u, uvCount, textureCoordinatesInput.flags & MeshDefinition::FlagMasks::TEXCOORDS_MASK, texCoords.mNormalized);
 
-    if(MaskMatch(mFlags, FLIP_UVS_VERTICAL))
+    if(MaskMatch(textureCoordinatesInput.flags, MeshDefinition::Flags::FLIP_UVS_VERTICAL))
     {
       auto uv    = reinterpret_cast<Vector2*>(buffer.data());
       auto uvEnd = uv + uvCount;
@@ -1263,40 +1092,43 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector&
 
     if(texCoords.mNormalized)
     {
-      GetDequantizedMinMax(texCoords.mBlob.mMin, texCoords.mBlob.mMax, mFlags & TEXCOORDS_MASK);
+      GetDequantizedMinMax(texCoords.mBlob.mMin, texCoords.mBlob.mMax, textureCoordinatesInput.flags & MeshDefinition::FlagMasks::TEXCOORDS_MASK);
     }
 
     texCoords.mBlob.ApplyMinMax(static_cast<uint32_t>(uvCount), reinterpret_cast<float*>(buffer.data()));
-    raw.mAttribs.push_back({"aTexCoord", Property::VECTOR2, static_cast<uint32_t>(uvCount), std::move(buffer)});
+    textureCoordinatesInput.rawData.mAttribs.push_back({"aTexCoord", Property::VECTOR2, static_cast<uint32_t>(uvCount), std::move(buffer)});
   }
+}
 
-  if(mTangents.IsDefined())
+void LoadTangents(LoadAccessorInputs tangentsInput, bool hasNormals, bool hasUvs, bool isTriangles, Property::Type tangentType, uint32_t normalBufferSize)
+{
+  if(tangentsInput.accessor.IsDefined())
   {
-    const auto bufferSize = mTangents.mBlob.GetBufferSize();
+    const auto bufferSize = tangentsInput.accessor.mBlob.GetBufferSize();
 
-    uint32_t propertySize   = static_cast<uint32_t>((mTangentType == Property::VECTOR4) ? sizeof(Vector4) : sizeof(Vector3));
+    uint32_t propertySize   = static_cast<uint32_t>((tangentType == Property::VECTOR4) ? sizeof(Vector4) : sizeof(Vector3));
     uint32_t componentCount = static_cast<uint32_t>(propertySize / sizeof(float));
 
     uint32_t numTangents;
 
-    if(MaskMatch(mFlags, S8_TANGENT))
+    if(MaskMatch(tangentsInput.flags, MeshDefinition::Flags::S8_TANGENT))
     {
-      DALI_ASSERT_ALWAYS(((mTangents.mBlob.mLength % (sizeof(int8_t) * componentCount) == 0) ||
-                          mTangents.mBlob.mStride >= (sizeof(int8_t) * componentCount)) &&
+      DALI_ASSERT_ALWAYS(((tangentsInput.accessor.mBlob.mLength % (sizeof(int8_t) * componentCount) == 0) ||
+                          tangentsInput.accessor.mBlob.mStride >= (sizeof(int8_t) * componentCount)) &&
                          "Tangents buffer length not a multiple of element size");
       numTangents = static_cast<uint32_t>(bufferSize / (sizeof(int8_t) * componentCount));
     }
-    else if(MaskMatch(mFlags, S16_TANGENT))
+    else if(MaskMatch(tangentsInput.flags, MeshDefinition::Flags::S16_TANGENT))
     {
-      DALI_ASSERT_ALWAYS(((mTangents.mBlob.mLength % (sizeof(int16_t) * componentCount) == 0) ||
-                          mTangents.mBlob.mStride >= (sizeof(int16_t) * componentCount)) &&
+      DALI_ASSERT_ALWAYS(((tangentsInput.accessor.mBlob.mLength % (sizeof(int16_t) * componentCount) == 0) ||
+                          tangentsInput.accessor.mBlob.mStride >= (sizeof(int16_t) * componentCount)) &&
                          "Tangents buffer length not a multiple of element size");
       numTangents = static_cast<uint32_t>(bufferSize / (sizeof(int16_t) * componentCount));
     }
     else
     {
-      DALI_ASSERT_ALWAYS(((mTangents.mBlob.mLength % propertySize == 0) ||
-                          mTangents.mBlob.mStride >= propertySize) &&
+      DALI_ASSERT_ALWAYS(((tangentsInput.accessor.mBlob.mLength % propertySize == 0) ||
+                          tangentsInput.accessor.mBlob.mStride >= propertySize) &&
                          "Tangents buffer length not a multiple of element size");
       numTangents = static_cast<uint32_t>(bufferSize / propertySize);
     }
@@ -1304,27 +1136,27 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector&
     std::vector<uint8_t> buffer(bufferSize);
 
     std::string path;
-    auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mTangents.mBufferIdx], path);
-    if(!ReadAccessor(mTangents, stream, buffer.data()))
+    auto&       stream = GetAvailableData(tangentsInput.fileStream, tangentsInput.meshPath, tangentsInput.buffers[tangentsInput.accessor.mBufferIdx], path);
+    if(!ReadAccessor(tangentsInput.accessor, stream, buffer.data()))
     {
       ExceptionFlinger(ASSERT_LOCATION) << "Failed to read tangents from '" << path << "'.";
     }
 
-    GetDequantizedData(buffer, componentCount, numTangents, mFlags & TANGENTS_MASK, mTangents.mNormalized);
+    GetDequantizedData(buffer, componentCount, numTangents, tangentsInput.flags & MeshDefinition::FlagMasks::TANGENTS_MASK, tangentsInput.accessor.mNormalized);
 
-    if(mTangents.mNormalized)
+    if(tangentsInput.accessor.mNormalized)
     {
-      GetDequantizedMinMax(mTangents.mBlob.mMin, mTangents.mBlob.mMax, mFlags & TANGENTS_MASK);
+      GetDequantizedMinMax(tangentsInput.accessor.mBlob.mMin, tangentsInput.accessor.mBlob.mMax, tangentsInput.flags & MeshDefinition::FlagMasks::TANGENTS_MASK);
     }
 
-    mTangents.mBlob.ApplyMinMax(numTangents, reinterpret_cast<float*>(buffer.data()));
+    tangentsInput.accessor.mBlob.ApplyMinMax(numTangents, reinterpret_cast<float*>(buffer.data()));
 
-    raw.mAttribs.push_back({"aTangent", mTangentType, static_cast<uint32_t>(numTangents), std::move(buffer)});
+    tangentsInput.rawData.mAttribs.push_back({"aTangent", tangentType, static_cast<uint32_t>(numTangents), std::move(buffer)});
   }
-  else if(mTangents.mBlob.mLength != 0 && hasNormals && isTriangles)
+  else if(tangentsInput.accessor.mBlob.mLength != 0 && hasNormals && isTriangles)
   {
-    DALI_ASSERT_DEBUG(mTangents.mBlob.mLength == mNormals.mBlob.GetBufferSize());
-    static const std::function<bool(RawData&)> GenerateTangentsFunction[2][2][2] =
+    DALI_ASSERT_DEBUG(tangentsInput.accessor.mBlob.mLength == normalBufferSize);
+    static const std::function<bool(MeshDefinition::RawData&)> GenerateTangentsFunction[2][2][2] =
       {
         {
           {
@@ -1346,83 +1178,64 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector&
             GenerateTangents<true, true, true>,
           },
         }};
-    const bool hasUvs            = !mTexCoords.empty() && mTexCoords[0].IsDefined();
-    const bool generateSuccessed = GenerateTangentsFunction[MaskMatch(mFlags, U32_INDICES)][mTangentType == Property::VECTOR3][hasUvs](raw);
+    const bool generateSuccessed = GenerateTangentsFunction[MaskMatch(tangentsInput.flags, MeshDefinition::Flags::U32_INDICES)][tangentType == Property::VECTOR3][hasUvs](tangentsInput.rawData);
     if(!generateSuccessed)
     {
       DALI_LOG_ERROR("Failed to generate tangents\n");
     }
   }
+}
 
+void LoadColors(LoadAccessorListInputs colorsInput)
+{
   // Only support 1 vertex color
-  if(!mColors.empty() && mColors[0].IsDefined())
+  if(!colorsInput.accessors.empty() && colorsInput.accessors[0].IsDefined())
   {
-    uint32_t       propertySize = mColors[0].mBlob.mElementSizeHint;
+    uint32_t       propertySize = colorsInput.accessors[0].mBlob.mElementSizeHint;
     Property::Type propertyType = (propertySize == sizeof(Vector4)) ? Property::VECTOR4 : ((propertySize == sizeof(Vector3)) ? Property::VECTOR3 : Property::NONE);
     if(propertyType != Property::NONE)
     {
-      DALI_ASSERT_ALWAYS(((mColors[0].mBlob.mLength % propertySize == 0) ||
-                          mColors[0].mBlob.mStride >= propertySize) &&
+      DALI_ASSERT_ALWAYS(((colorsInput.accessors[0].mBlob.mLength % propertySize == 0) ||
+                          colorsInput.accessors[0].mBlob.mStride >= propertySize) &&
                          "Colors buffer length not a multiple of element size");
-      const auto           bufferSize = mColors[0].mBlob.GetBufferSize();
+      const auto           bufferSize = colorsInput.accessors[0].mBlob.GetBufferSize();
       std::vector<uint8_t> buffer(bufferSize);
 
       std::string path;
-      auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mColors[0].mBufferIdx], path);
-      if(!ReadAccessor(mColors[0], stream, buffer.data()))
+      auto&       stream = GetAvailableData(colorsInput.fileStream, colorsInput.meshPath, colorsInput.buffers[colorsInput.accessors[0].mBufferIdx], path);
+      if(!ReadAccessor(colorsInput.accessors[0], stream, buffer.data()))
       {
         ExceptionFlinger(ASSERT_LOCATION) << "Failed to read colors from '" << path << "'.";
       }
-      mColors[0].mBlob.ApplyMinMax(bufferSize / propertySize, reinterpret_cast<float*>(buffer.data()));
+      colorsInput.accessors[0].mBlob.ApplyMinMax(bufferSize / propertySize, reinterpret_cast<float*>(buffer.data()));
 
-      raw.mAttribs.push_back({"aVertexColor", propertyType, static_cast<uint32_t>(bufferSize / propertySize), std::move(buffer)});
+      colorsInput.rawData.mAttribs.push_back({"aVertexColor", propertyType, static_cast<uint32_t>(bufferSize / propertySize), std::move(buffer)});
     }
   }
   else
   {
-    std::vector<uint8_t> buffer(raw.mAttribs[0].mNumElements * sizeof(Vector4));
+    std::vector<uint8_t> buffer(colorsInput.rawData.mAttribs[0].mNumElements * sizeof(Vector4));
     auto                 colors = reinterpret_cast<Vector4*>(buffer.data());
 
-    for(uint32_t i = 0; i < raw.mAttribs[0].mNumElements; i++)
+    for(uint32_t i = 0; i < colorsInput.rawData.mAttribs[0].mNumElements; i++)
     {
       colors[i] = Vector4::ONE;
     }
 
-    raw.mAttribs.push_back({"aVertexColor", Property::VECTOR4, raw.mAttribs[0].mNumElements, std::move(buffer)});
-  }
-
-  if(IsSkinned())
-  {
-    int setIndex = 0;
-    for(auto& accessor : mJoints)
-    {
-      std::string        pathJoint;
-      auto&              streamJoint = GetAvailableData(fileStream, meshPath, buffers[accessor.mBufferIdx], pathJoint);
-      std::ostringstream jointName;
-      jointName << "aJoints" << setIndex;
-      ++setIndex;
-      ReadTypedJointAccessor(raw, mFlags, accessor, streamJoint, pathJoint, jointName.str());
-    }
-    setIndex = 0;
-    for(auto& accessor : mWeights)
-    {
-      std::string        pathWeight;
-      auto&              streamWeight = GetAvailableData(fileStream, meshPath, buffers[accessor.mBufferIdx], pathWeight);
-      std::ostringstream weightName;
-      weightName << "aWeights" << setIndex;
-      ++setIndex;
-      ReadTypedWeightAccessor(raw, mFlags, accessor, streamWeight, pathWeight, weightName.str());
-    }
+    colorsInput.rawData.mAttribs.push_back({"aVertexColor", Property::VECTOR4, colorsInput.rawData.mAttribs[0].mNumElements, std::move(buffer)});
   }
+}
 
+void LoadBlendShapes(MeshDefinition::RawData& rawData, std::vector<MeshDefinition::BlendShape>& blendShapes, MeshDefinition::Blob& blendShapeHeader, BlendShapes::Version blendShapeVersion, uint32_t numberOfVertices, std::fstream& fileStream, BufferDefinition::Vector& buffers)
+{
   // Calculate the Blob for the blend shapes.
-  Blob blendShapesBlob;
+  MeshDefinition::Blob blendShapesBlob;
   blendShapesBlob.mOffset = std::numeric_limits<unsigned int>::max();
   blendShapesBlob.mLength = 0u;
 
   uint32_t totalTextureSize(0u);
 
-  auto processAccessor = [&](const Accessor& accessor, uint32_t vector3Size) {
+  auto processAccessor = [&](const MeshDefinition::Accessor& accessor, uint32_t vector3Size) {
     if(accessor.IsDefined())
     {
       blendShapesBlob.mOffset = std::min(blendShapesBlob.mOffset, accessor.mBlob.mOffset);
@@ -1432,27 +1245,27 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector&
     }
   };
 
-  for(const auto& blendShape : mBlendShapes)
+  for(const auto& blendShape : blendShapes)
   {
-    const auto positionMask = blendShape.mFlags & POSITIONS_MASK;
-    const auto normalMask   = blendShape.mFlags & NORMALS_MASK;
-    const auto tangentMask  = blendShape.mFlags & TANGENTS_MASK;
+    const auto positionMask = blendShape.mFlags & MeshDefinition::FlagMasks::POSITIONS_MASK;
+    const auto normalMask   = blendShape.mFlags & MeshDefinition::FlagMasks::NORMALS_MASK;
+    const auto tangentMask  = blendShape.mFlags & MeshDefinition::FlagMasks::TANGENTS_MASK;
 
-    processAccessor(blendShape.deltas, MaskMatch(positionMask, S8_POSITION) ? sizeof(uint8_t) * 3 : (MaskMatch(positionMask, S16_POSITION) ? sizeof(uint16_t) * 3 : sizeof(Vector3)));
-    processAccessor(blendShape.normals, MaskMatch(normalMask, S8_NORMAL) ? sizeof(uint8_t) * 3 : (MaskMatch(normalMask, S16_NORMAL) ? sizeof(uint16_t) * 3 : sizeof(Vector3)));
-    processAccessor(blendShape.tangents, MaskMatch(tangentMask, S8_TANGENT) ? sizeof(uint8_t) * 3 : (MaskMatch(tangentMask, S16_TANGENT) ? sizeof(uint16_t) * 3 : sizeof(Vector3)));
+    processAccessor(blendShape.deltas, MaskMatch(positionMask, MeshDefinition::S8_POSITION) ? sizeof(uint8_t) * 3 : (MaskMatch(positionMask, MeshDefinition::S16_POSITION) ? sizeof(uint16_t) * 3 : sizeof(Vector3)));
+    processAccessor(blendShape.normals, MaskMatch(normalMask, MeshDefinition::S8_NORMAL) ? sizeof(uint8_t) * 3 : (MaskMatch(normalMask, MeshDefinition::S16_NORMAL) ? sizeof(uint16_t) * 3 : sizeof(Vector3)));
+    processAccessor(blendShape.tangents, MaskMatch(tangentMask, MeshDefinition::S8_TANGENT) ? sizeof(uint8_t) * 3 : (MaskMatch(tangentMask, MeshDefinition::S16_TANGENT) ? sizeof(uint16_t) * 3 : sizeof(Vector3)));
   }
 
-  if(HasBlendShapes())
+  if(!blendShapes.empty())
   {
     // Calculate the size of one buffer inside the texture.
-    raw.mBlendShapeBufferOffset = numberOfVertices;
+    rawData.mBlendShapeBufferOffset = numberOfVertices;
 
     bool     calculateGltf2BlendShapes = false;
     uint32_t textureWidth              = 0u;
     uint32_t textureHeight             = 0u;
 
-    if(!mBlendShapeHeader.IsDefined())
+    if(!blendShapeHeader.IsDefined())
     {
       CalculateTextureSize(totalTextureSize, textureWidth, textureHeight);
       calculateGltf2BlendShapes = true;
@@ -1460,25 +1273,25 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector&
     else
     {
       uint16_t header[2u];
-      ReadBlob(mBlendShapeHeader, fileStream, reinterpret_cast<uint8_t*>(header));
+      ReadBlob(blendShapeHeader, fileStream, reinterpret_cast<uint8_t*>(header));
       textureWidth  = header[0u];
       textureHeight = header[1u];
     }
 
-    const uint32_t numberOfBlendShapes = mBlendShapes.size();
-    raw.mBlendShapeUnnormalizeFactor.Resize(numberOfBlendShapes);
+    const uint32_t numberOfBlendShapes = blendShapes.size();
+    rawData.mBlendShapeUnnormalizeFactor.Resize(numberOfBlendShapes);
 
     Devel::PixelBuffer geometryPixelBuffer = Devel::PixelBuffer::New(textureWidth, textureHeight, Pixel::RGB32F);
     uint8_t*           geometryBuffer      = geometryPixelBuffer.GetBuffer();
 
     if(calculateGltf2BlendShapes)
     {
-      CalculateGltf2BlendShapes(geometryBuffer, mBlendShapes, numberOfVertices, raw.mBlendShapeUnnormalizeFactor[0u], buffers);
+      CalculateGltf2BlendShapes(geometryBuffer, blendShapes, numberOfVertices, rawData.mBlendShapeUnnormalizeFactor[0u], buffers);
     }
     else
     {
-      Blob unnormalizeFactorBlob;
-      unnormalizeFactorBlob.mLength = static_cast<uint32_t>(sizeof(float) * ((BlendShapes::Version::VERSION_2_0 == mBlendShapeVersion) ? 1u : numberOfBlendShapes));
+      MeshDefinition::Blob unnormalizeFactorBlob;
+      unnormalizeFactorBlob.mLength = static_cast<uint32_t>(sizeof(float) * ((BlendShapes::Version::VERSION_2_0 == blendShapeVersion) ? 1u : numberOfBlendShapes));
 
       if(blendShapesBlob.IsDefined())
       {
@@ -1491,12 +1304,224 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector&
       // Read the unnormalize factors.
       if(unnormalizeFactorBlob.IsDefined())
       {
-        ReadBlob(unnormalizeFactorBlob, fileStream, reinterpret_cast<uint8_t*>(&raw.mBlendShapeUnnormalizeFactor[0u]));
+        ReadBlob(unnormalizeFactorBlob, fileStream, reinterpret_cast<uint8_t*>(&rawData.mBlendShapeUnnormalizeFactor[0u]));
       }
     }
-    raw.mBlendShapeData = Devel::PixelBuffer::Convert(geometryPixelBuffer);
+    rawData.mBlendShapeData = Devel::PixelBuffer::Convert(geometryPixelBuffer);
+  }
+}
+
+} // namespace
+
+MeshDefinition::SparseBlob::SparseBlob(const Blob& indices, const Blob& values, uint32_t count)
+: mIndices{indices},
+  mValues{values},
+  mCount{count}
+{
+}
+
+MeshDefinition::SparseBlob::SparseBlob(Blob&& indices, Blob&& values, uint32_t count)
+: mIndices(std::move(indices)),
+  mValues(std::move(values)),
+  mCount{count}
+{
+}
+
+MeshDefinition::Accessor::Accessor(const MeshDefinition::Blob&       blob,
+                                   const MeshDefinition::SparseBlob& sparse,
+                                   Index                             bufferIndex,
+                                   bool                              normalized)
+: mBlob{blob},
+  mSparse{(sparse.mIndices.IsDefined() && sparse.mValues.IsDefined()) ? new SparseBlob{sparse} : nullptr},
+  mBufferIdx(bufferIndex),
+  mNormalized(normalized)
+{
+}
+
+MeshDefinition::Accessor::Accessor(MeshDefinition::Blob&&       blob,
+                                   MeshDefinition::SparseBlob&& sparse,
+                                   Index                        bufferIndex,
+                                   bool                         normalized)
+: mBlob{std::move(blob)},
+  mSparse{(sparse.mIndices.IsDefined() && sparse.mValues.IsDefined()) ? new SparseBlob{std::move(sparse)} : nullptr},
+  mBufferIdx(bufferIndex),
+  mNormalized(normalized)
+{
+}
+
+void MeshDefinition::Blob::ComputeMinMax(std::vector<float>& min, std::vector<float>& max, uint32_t numComponents, uint32_t count, const float* values)
+{
+  min.assign(numComponents, MAXFLOAT);
+  max.assign(numComponents, -MAXFLOAT);
+  for(uint32_t i = 0; i < count; ++i)
+  {
+    for(uint32_t j = 0; j < numComponents; ++j)
+    {
+      min[j] = std::min(min[j], *values);
+      max[j] = std::max(max[j], *values);
+      values++;
+    }
+  }
+}
+
+void MeshDefinition::Blob::ApplyMinMax(const std::vector<float>& min, const std::vector<float>& max, uint32_t count, float* values, std::vector<uint32_t>* sparseIndices)
+{
+  DALI_ASSERT_DEBUG(max.size() == min.size() || max.size() * min.size() == 0);
+  const auto numComponents = std::max(min.size(), max.size());
+
+  using ClampFn   = void (*)(const float*, const float*, uint32_t, float&);
+  ClampFn clampFn = min.empty() ? (max.empty() ? static_cast<ClampFn>(nullptr) : [](const float* min, const float* max, uint32_t i, float& value) { value = std::min(max[i], value); })
+                                : (max.empty() ? [](const float* min, const float* max, uint32_t i, float& value) { value = std::max(min[i], value); }
+                                               : static_cast<ClampFn>([](const float* min, const float* max, uint32_t i, float& value) { value = std::min(std::max(min[i], value), max[i]); }));
+
+  if(!clampFn)
+  {
+    return;
+  }
+
+  auto end = values + count * numComponents;
+  while(values != end)
+  {
+    auto     nextElement = values + numComponents;
+    uint32_t i           = 0;
+    while(values != nextElement)
+    {
+      clampFn(min.data(), max.data(), i, *values);
+      ++values;
+      ++i;
+    }
+  }
+}
+
+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 mLength;
+}
+
+void MeshDefinition::Blob::ComputeMinMax(uint32_t numComponents, uint32_t count, float* values)
+{
+  ComputeMinMax(mMin, mMax, numComponents, count, values);
+}
+
+void MeshDefinition::Blob::ApplyMinMax(uint32_t count, float* values, std::vector<uint32_t>* sparseIndices) const
+{
+  ApplyMinMax(mMin, mMax, count, values, sparseIndices);
+}
+
+void MeshDefinition::RawData::Attrib::AttachBuffer(Geometry& g) const
+{
+  Property::Map attribMap;
+  attribMap[mName]          = mType;
+  VertexBuffer attribBuffer = VertexBuffer::New(attribMap);
+  attribBuffer.SetData(mData.data(), mNumElements);
+
+  g.AddVertexBuffer(attribBuffer);
+}
+
+bool MeshDefinition::IsQuad() const
+{
+  return CaseInsensitiveStringCompare(QUAD, mUri);
+}
+
+bool MeshDefinition::IsSkinned() const
+{
+  return !mJoints.empty() && !mWeights.empty();
+}
+
+bool MeshDefinition::HasVertexColor() const
+{
+  return !mColors.empty();
+}
+
+uint32_t MeshDefinition::GetNumberOfJointSets() const
+{
+  uint32_t number = static_cast<uint32_t>(mJoints.size());
+  if(number > MeshDefinition::MAX_NUMBER_OF_JOINT_SETS)
+  {
+    number = MeshDefinition::MAX_NUMBER_OF_JOINT_SETS;
+  }
+  return number;
+}
+
+bool MeshDefinition::HasBlendShapes() const
+{
+  return !mBlendShapes.empty();
+}
+
+void MeshDefinition::RequestNormals()
+{
+  mNormals.mBlob.mLength = mPositions.mBlob.GetBufferSize();
+}
+
+void MeshDefinition::RequestTangents()
+{
+  mTangents.mBlob.mLength = mNormals.mBlob.GetBufferSize();
+}
+
+MeshDefinition::RawData
+MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector& buffers)
+{
+  RawData raw;
+  if(IsQuad())
+  {
+    return raw;
+  }
+
+  std::string meshPath;
+  meshPath = modelsPath + mUri;
+  std::fstream fileStream;
+  if(!mUri.empty())
+  {
+    fileStream.open(meshPath, std::ios::in | std::ios::binary);
+    if(!fileStream.is_open())
+    {
+      DALI_LOG_ERROR("Fail to open buffer from %s.\n", meshPath.c_str());
+    }
   }
 
+  LoadAccessorInputs indicesInput = {raw, mIndices, mFlags, fileStream, meshPath, buffers};
+  LoadIndices(indicesInput);
+
+  LoadAccessorInputs positionsInput   = {raw, mPositions, mFlags, fileStream, meshPath, buffers};
+  uint32_t           numberOfVertices = LoadPositions(positionsInput, HasBlendShapes());
+
+  const auto         isTriangles  = mPrimitiveType == Geometry::TRIANGLES;
+  LoadAccessorInputs normalsInput = {raw, mNormals, mFlags, fileStream, meshPath, buffers};
+  auto               hasNormals   = LoadNormals(normalsInput, isTriangles, mPositions.mBlob.GetBufferSize());
+
+  LoadAccessorListInputs textureCoordinatesInput = {raw, mTexCoords, mFlags, fileStream, meshPath, buffers};
+  LoadTextureCoordinates(textureCoordinatesInput);
+
+  const bool         hasUvs        = !mTexCoords.empty() && mTexCoords[0].IsDefined();
+  LoadAccessorInputs tangentsInput = {raw, mTangents, mFlags, fileStream, meshPath, buffers};
+  LoadTangents(tangentsInput, hasNormals, hasUvs, isTriangles, mTangentType, mNormals.mBlob.GetBufferSize());
+
+  LoadAccessorListInputs colorsInput = {raw, mColors, mFlags, fileStream, meshPath, buffers};
+  LoadColors(colorsInput);
+
+  if(IsSkinned())
+  {
+    LoadDataType           loadDataType = (MaskMatch(mFlags, MeshDefinition::U16_JOINT_IDS)) ? LoadDataType::UNSIGNED_SHORT : (MaskMatch(mFlags, MeshDefinition::U8_JOINT_IDS) ? LoadDataType::UNSIGNED_BYTE : LoadDataType::FLOAT);
+    LoadAccessorListInputs jointsInput  = {raw, mJoints, mFlags, fileStream, meshPath, buffers};
+    ReadTypedVectorAccessors<false>(jointsInput, loadDataType, "aJoints");
+
+    loadDataType                        = (MaskMatch(mFlags, MeshDefinition::U16_WEIGHT)) ? LoadDataType::UNSIGNED_SHORT : (MaskMatch(mFlags, MeshDefinition::U8_WEIGHT) ? LoadDataType::UNSIGNED_BYTE : LoadDataType::FLOAT);
+    LoadAccessorListInputs weightsInput = {raw, mWeights, mFlags, fileStream, meshPath, buffers};
+    ReadTypedVectorAccessors<true>(weightsInput, loadDataType, "aWeights");
+  }
+
+  LoadBlendShapes(raw, mBlendShapes, mBlendShapeHeader, mBlendShapeVersion, numberOfVertices, fileStream, buffers);
+
   return raw;
 }
 
index 56e63af..218969b 100644 (file)
@@ -350,6 +350,66 @@ void ModelRenderable::OnCreate(const NodeDefinition& nodeDefinition, NodeDefinit
     renderer.RegisterProperty("uOcclusionStrength", matDef.mOcclusionStrength);
   }
 
+  renderer.RegisterProperty("uBaseColorTextureTransformAvailable", 0.0f);
+  renderer.RegisterProperty("uNormalTextureTransformAvailable", 0.0f);
+  renderer.RegisterProperty("uNormalRoughnessTextureTransformAvailable", 0.0f);
+  renderer.RegisterProperty("uMetalRoughnessTextureTransformAvailable", 0.0f);
+  renderer.RegisterProperty("uOcclusionTextureTransformAvailable", 0.0f);
+  renderer.RegisterProperty("uEmissiveTextureTransformAvailable", 0.0f);
+
+  auto iTexture   = matDef.mTextureStages.begin();
+  auto checkStage = [&](uint32_t flags) {
+    return iTexture != matDef.mTextureStages.end() && MaskMatch(iTexture->mSemantic, flags);
+  };
+
+  if(checkStage(MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC))
+  {
+    renderer.RegisterProperty("uBaseColorTextureTransformAvailable", 1.0f);
+    renderer.RegisterProperty("uBaseColorTextureTransform", iTexture->mTexture.mTransform);
+    ++iTexture;
+
+    if(checkStage(MaterialDefinition::NORMAL | MaterialDefinition::ROUGHNESS))
+    {
+      renderer.RegisterProperty("uNormalRoughnessTextureTransformAvailable", 1.0f);
+      renderer.RegisterProperty("uNormalRoughnessTextureTransform", iTexture->mTexture.mTransform);
+      ++iTexture;
+    }
+  }
+  else if(checkStage(MaterialDefinition::ALBEDO))
+  {
+    renderer.RegisterProperty("uBaseColorTextureTransformAvailable", 1.0f);
+    renderer.RegisterProperty("uBaseColorTextureTransform", iTexture->mTexture.mTransform);
+    ++iTexture;
+  }
+
+  if(checkStage(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS))
+  {
+    renderer.RegisterProperty("uMetalRoughnessTextureTransformAvailable", 1.0f);
+    renderer.RegisterProperty("uMetalRoughnessTextureTransform", iTexture->mTexture.mTransform);
+    ++iTexture;
+  }
+
+  if(checkStage(MaterialDefinition::NORMAL))
+  {
+    renderer.RegisterProperty("uNormalTextureTransformAvailable", 1.0f);
+    renderer.RegisterProperty("uNormalTextureTransform", iTexture->mTexture.mTransform);
+    ++iTexture;
+  }
+
+  if(checkStage(MaterialDefinition::OCCLUSION))
+  {
+    renderer.RegisterProperty("uOcclusionTextureTransformAvailable", 1.0f);
+    renderer.RegisterProperty("uOcclusionTextureTransform", iTexture->mTexture.mTransform);
+    ++iTexture;
+  }
+
+  if(checkStage(MaterialDefinition::EMISSIVE))
+  {
+    renderer.RegisterProperty("uEmissiveTextureTransformAvailable", 1.0f);
+    renderer.RegisterProperty("uEmissiveTextureTransform", iTexture->mTexture.mTransform);
+    ++iTexture;
+  }
+
   float opaque      = matDef.mIsOpaque ? 1.0f : 0.0f;
   float mask        = matDef.mIsMask ? 1.0f : 0.0f;
   float alphaCutoff = matDef.GetAlphaCutoff();
@@ -378,9 +438,10 @@ void ModelRenderable::OnCreate(const NodeDefinition& nodeDefinition, NodeDefinit
       Internal::Material::TextureInformation textureInformation;
       if(matDef.CheckTextures(SEMANTICS[i]))
       {
-        textureInformation.mTexture = textures.GetTexture(textureIndex + textureIndexOffset);
-        textureInformation.mSampler = textures.GetSampler(textureIndex + textureIndexOffset);
-        textureInformation.mUrl     = matDef.mTextureStages[textureIndex].mTexture.mDirectoryPath + matDef.mTextureStages[textureIndex].mTexture.mImageUri;
+        textureInformation.mTexture   = textures.GetTexture(textureIndex + textureIndexOffset);
+        textureInformation.mSampler   = textures.GetSampler(textureIndex + textureIndexOffset);
+        textureInformation.mUrl       = matDef.mTextureStages[textureIndex].mTexture.mDirectoryPath + matDef.mTextureStages[textureIndex].mTexture.mImageUri;
+        textureInformation.mTransform = matDef.mTextureStages[textureIndex].mTexture.mTransform;
         textureIndex++;
       }
       textureInformation.mFactor = GetTextureFactor(matDef, SEMANTICS[i]);
index a7727d6..5aba19e 100644 (file)
@@ -91,20 +91,33 @@ void ApplyDefine(std::string& shaderCode, const std::string& definevar)
 
 void RedefineMacro(std::string& shaderCode, const std::string& macro, const std::string& value)
 {
-  std::string definition = "#define " + macro;
-  std::size_t found      = shaderCode.find(definition);
-  if(found != std::string::npos)
+  if(!value.empty())
   {
-    std::size_t insertionPoint = found + definition.length();
+    std::string definition = "#define " + macro;
+    std::size_t found      = shaderCode.find(definition);
+    if(found != std::string::npos)
+    {
+      std::size_t insertionPoint = found + definition.length();
 
-    // Automatically insert line-continuation character into value
-    std::regex                 re("\n");
-    std::sregex_token_iterator first{value.begin(), value.end(), re, -1}, last;
-    for(auto i = first; i != last; ++i)
+      // Automatically insert line-continuation character into value
+      std::regex                 re("\n");
+      std::sregex_token_iterator first{value.begin(), value.end(), re, -1}, last;
+      for(auto i = first; i != last; ++i)
+      {
+        std::string line = std::string(" \\\n") + (*i).str();
+        shaderCode.insert(insertionPoint, line);
+        insertionPoint += line.length();
+      }
+    }
+  }
+  else
+  {
+    std::size_t invocation = shaderCode.rfind(macro);
+    if(invocation != std::string::npos)
     {
-      std::string line = std::string(" \\\n") + (*i).str();
-      shaderCode.insert(insertionPoint, line);
-      insertionPoint += line.length();
+      std::size_t start = shaderCode.rfind("\n", invocation);
+      std::size_t end   = shaderCode.find("\n", invocation);
+      shaderCode.erase(start, end - start);
     }
   }
 }
index 6adb452..35ebd63 100644 (file)
@@ -118,6 +118,10 @@ ShaderOption MakeOption(const MaterialDefinition& materialDef, const MeshDefinit
     option.AddOption(ShaderOption::Type::SKINNING);
     option.AddJointMacros(meshDef.mJoints.size());
   }
+  else
+  {
+    option.AddJointMacros(0);
+  }
 
   if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
   {
index 4654348..f504a99 100644 (file)
@@ -117,6 +117,11 @@ void ShaderOption::AddJointMacros(size_t numberOfJointSets)
     AddMacroDefinition(ADD_EXTRA_SKINNING_ATTRIBUTES, attributes.str());
     AddMacroDefinition(ADD_EXTRA_WEIGHTS, weights.str());
   }
+  else
+  {
+    AddMacroDefinition(ADD_EXTRA_SKINNING_ATTRIBUTES, std::string{});
+    AddMacroDefinition(ADD_EXTRA_WEIGHTS, std::string{});
+  }
 }
 
 void ShaderOption::AddMacroDefinition(std::string macro, std::string definition)
index 93dcb4b..368f8d5 100644 (file)
@@ -116,6 +116,11 @@ void VisualFactory::DiscardVisual(Visual::Base visual)
   GetImplementation(*this).DiscardVisual(visual);
 }
 
+void VisualFactory::UsePreCompiledShader()
+{
+  GetImplementation(*this).UsePreCompiledShader();
+}
+
 } // namespace Toolkit
 
 } // namespace Dali
index 1b7d9b5..cc62c2b 100644 (file)
@@ -133,6 +133,17 @@ public:
    */
   void DiscardVisual(Visual::Base visual);
 
+  /**
+   * @brief Compile the visual shader in advance. Afterwards,
+   * when a visual using a new shader is requested, the pre-compiled shader is used.
+   *
+   * @note It is recommended that this method be called at the top of the application code.
+   * @note Using precompiled shaders is helpful when the application is complex and uses
+   * many different styles of visual options. On the other hand,if most visuals are the same
+   * and the application is simple, it may use memory unnecessarily or slow down the application launching speed.
+   */
+  void UsePreCompiledShader();
+
 private:
   explicit DALI_INTERNAL VisualFactory(Internal::VisualFactory* impl);
 };
index f1b51bb..6c1fef6 100644 (file)
@@ -2,16 +2,12 @@
 INPUT mediump vec2 vPosition;
 INPUT mediump vec2 vRectSize;
 INPUT mediump vec2 vOptRectSize;
+INPUT mediump float vAliasMargin;
 #ifdef IS_REQUIRED_ROUNDED_CORNER
 INPUT mediump vec4 vCornerRadius;
 #endif
 #endif
 
-#if defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE) || defined(IS_REQUIRED_BLUR)
-// Be used when we calculate anti-alias range near 1 pixel.
-uniform highp vec3 uScale;
-#endif
-
 uniform lowp vec4 uColor;
 uniform lowp vec3 mixColor;
 #ifdef IS_REQUIRED_BLUR
@@ -75,10 +71,7 @@ void calculatePotential()
 
 void setupMinMaxPotential()
 {
-  // Set soft anti-alias range at most 10% of visual size.
-  // The range should be inverse proportion with scale of view.
-  // To avoid divid-by-zero, let we allow minimum scale value is 0.001 (0.1%)
-  gPotentialRange = min(1.0, max(vRectSize.x, vRectSize.y) * 0.2) / max(0.001, max(uScale.x, uScale.y));
+  gPotentialRange = vAliasMargin;
 
   gMaxOutlinePotential = gRadius + gPotentialRange;
   gMinOutlinePotential = gRadius - gPotentialRange;
index 29ad984..28c5646 100644 (file)
@@ -3,6 +3,7 @@ INPUT mediump vec2 aPosition;
 OUTPUT mediump vec2 vPosition;
 OUTPUT mediump vec2 vRectSize;
 OUTPUT mediump vec2 vOptRectSize;
+OUTPUT mediump float vAliasMargin;
 #ifdef IS_REQUIRED_ROUNDED_CORNER
 OUTPUT mediump vec4 vCornerRadius;
 #endif
@@ -11,6 +12,11 @@ OUTPUT mediump vec4 vCornerRadius;
 uniform highp mat4 uMvpMatrix;
 uniform highp vec3 uSize;
 
+#if defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE) || defined(IS_REQUIRED_BLUR)
+// Be used when we calculate anti-alias range near 1 pixel.
+uniform highp vec3 uScale;
+#endif
+
 //Visual size and offset
 uniform mediump vec2 offset;
 uniform highp vec2 size;
@@ -37,31 +43,52 @@ vec4 ComputeVertexPosition()
 #if defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE) || defined(IS_REQUIRED_BLUR)
   vRectSize = visualSize * 0.5;
   vOptRectSize = vRectSize;
+
+  // Set soft anti-alias range at most 10% of visual size.
+  // The range should be inverse proportion with scale of view.
+  // To avoid divid-by-zero, let we allow minimum scale value is 0.001 (0.1%)
+  vAliasMargin = min(1.0, max(visualSize.x, visualSize.y) * 0.1) / max(0.001, max(uScale.x, uScale.y));
+
+  mediump float vertexMargin = 0.0;
 #endif
 
 #ifdef IS_REQUIRED_ROUNDED_CORNER
 #ifdef IS_REQUIRED_BLUR
+  mediump float maxSize = max(visualSize.x, visualSize.y);
   mediump float minSize = min(visualSize.x, visualSize.y);
 #elif defined(IS_REQUIRED_BORDERLINE)
+  mediump float maxSize = max(visualSize.x, visualSize.y) + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth;
   mediump float minSize = min(visualSize.x, visualSize.y) + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth;
 #else
+  mediump float maxSize = max(visualSize.x, visualSize.y);
   mediump float minSize = min(visualSize.x, visualSize.y);
 #endif
   vCornerRadius = mix(cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);
   vCornerRadius = min(vCornerRadius, minSize * 0.5);
   // Optimize fragment shader. 0.2929 ~= 1.0 - sqrt(0.5)
   mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
+  mediump float minRadius = min(min(vCornerRadius.x, vCornerRadius.y), min(vCornerRadius.z, vCornerRadius.w));
   vOptRectSize -= 0.2929 * maxRadius + 1.0;
+
+  // Set vertex margin as vAliasMargin if we need to make some more fragments for alias.
+#ifdef IS_REQUIRED_BLUR
+  // Let we always increase alias margin for blur case
+  vertexMargin = 2.0 * vAliasMargin;
+#else
+  // Do not increase margin if the minRadius is small enough rather than maxSize.
+  // TODO : We should change the magic parameter, 0.49
+  vertexMargin = 2.0 * vAliasMargin * smoothstep(maxSize * 0.49, maxSize * 0.5, minRadius);
+#endif
 #endif
 
 #ifdef IS_REQUIRED_BLUR
-  vPosition = aPosition * (visualSize + 2.0 * blurRadius);
+  vPosition = aPosition * (visualSize + 2.0 * blurRadius + vertexMargin);
   vOptRectSize -= blurRadius + 1.0;
 #elif defined(IS_REQUIRED_BORDERLINE)
-  vPosition = aPosition * (visualSize + (1.0 + clamp(borderlineOffset, -1.0, 1.0))* borderlineWidth);
+  vPosition = aPosition * (visualSize + (1.0 + clamp(borderlineOffset, -1.0, 1.0))* borderlineWidth + vertexMargin);
   vOptRectSize -= (1.0 - clamp(borderlineOffset, -1.0, 1.0)) * 0.5 * borderlineWidth + 1.0;
 #elif defined(IS_REQUIRED_ROUNDED_CORNER)
-  vPosition = aPosition * visualSize;
+  vPosition = aPosition * (visualSize + vertexMargin);
 #else
   mediump vec2 vPosition = aPosition * visualSize;
 #endif
index c2b9c5d..752ecdb 100644 (file)
@@ -3,6 +3,7 @@ INPUT mediump vec2 vTexCoord;
 INPUT mediump vec2 vPosition;
 INPUT mediump vec2 vRectSize;
 INPUT mediump vec2 vOptRectSize;
+INPUT mediump float vAliasMargin;
 #ifdef IS_REQUIRED_ROUNDED_CORNER
 INPUT mediump vec4 vCornerRadius;
 #endif
@@ -11,11 +12,6 @@ INPUT mediump vec4 vCornerRadius;
 // scale factor to fit start and end position of gradient.
 uniform mediump float uTextureCoordinateScaleFactor;
 
-#if defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
-// Be used when we calculate anti-alias range near 1 pixel.
-uniform highp vec3 uScale;
-#endif
-
 uniform sampler2D sTexture; // sampler1D?
 uniform lowp vec4 uColor;
 uniform lowp vec3 mixColor;
@@ -77,10 +73,7 @@ void calculatePotential()
 
 void setupMinMaxPotential()
 {
-  // Set soft anti-alias range at most 10% of visual size.
-  // The range should be inverse proportion with scale of view.
-  // To avoid divid-by-zero, let we allow minimum scale value is 0.001 (0.1%)
-  gPotentialRange = min(1.0, max(vRectSize.x, vRectSize.y) * 0.2) / max(0.001, max(uScale.x, uScale.y));
+  gPotentialRange = vAliasMargin;
 
   gMaxOutlinePotential = gRadius + gPotentialRange;
   gMinOutlinePotential = gRadius - gPotentialRange;
index b2b0864..928fd1c 100644 (file)
@@ -4,6 +4,7 @@ OUTPUT mediump vec2 vTexCoord;
 OUTPUT mediump vec2 vPosition;
 OUTPUT mediump vec2 vRectSize;
 OUTPUT mediump vec2 vOptRectSize;
+OUTPUT mediump float vAliasMargin;
 #ifdef IS_REQUIRED_ROUNDED_CORNER
 OUTPUT mediump vec4 vCornerRadius;
 #endif
@@ -13,6 +14,11 @@ uniform highp mat4 uMvpMatrix;
 uniform highp vec3 uSize;
 uniform mediump mat3 uAlignmentMatrix;
 
+#if defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
+// Be used when we calculate anti-alias range near 1 pixel.
+uniform highp vec3 uScale;
+#endif
+
 //Visual size and offset
 uniform mediump vec2 offset;
 uniform highp vec2 size;
@@ -36,28 +42,43 @@ vec4 ComputeVertexPosition()
 #if defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
   vRectSize = visualSize * 0.5;
   vOptRectSize = vRectSize;
+
+  // Set soft anti-alias range at most 10% of visual size.
+  // The range should be inverse proportion with scale of view.
+  // To avoid divid-by-zero, let we allow minimum scale value is 0.001 (0.1%)
+  vAliasMargin = min(1.0, max(visualSize.x, visualSize.y) * 0.1) / max(0.001, max(uScale.x, uScale.y));
+
+  mediump float vertexMargin = 0.0;
 #endif
 
 #ifdef IS_REQUIRED_ROUNDED_CORNER
 #ifdef IS_REQUIRED_BORDERLINE
+  mediump float maxSize = max(visualSize.x, visualSize.y) + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth;
   mediump float minSize = min(visualSize.x, visualSize.y) + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth;
 #else
+  mediump float maxSize = max(visualSize.x, visualSize.y);
   mediump float minSize = min(visualSize.x, visualSize.y);
 #endif
   vCornerRadius = mix(cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);
   vCornerRadius = min(vCornerRadius, minSize * 0.5);
   // Optimize fragment shader. 0.2929 ~= 1.0 - sqrt(0.5)
   mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
+  mediump float minRadius = min(min(vCornerRadius.x, vCornerRadius.y), min(vCornerRadius.z, vCornerRadius.w));
   vOptRectSize -= 0.2929 * maxRadius + 1.0;
+
+  // Set vertex margin as vAliasMargin if we need to make some more fragments for alias.
+  // Do not increase margin if the minRadius is small enough rather than maxSize.
+  // TODO : We should change the magic parameter, 0.49
+  vertexMargin = 2.0 * vAliasMargin * smoothstep(maxSize * 0.49, maxSize * 0.5, minRadius);
 #endif
 
   mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);
 #ifdef IS_REQUIRED_BORDERLINE
-  vPosition = aPosition * (visualSize + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth);
-  vertexPosition.xy *= (1.0 + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth / visualSize);
+  vPosition = aPosition * (visualSize + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth + vertexMargin);
+  vertexPosition.xy *= (1.0 + ((1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth + vertexMargin) / visualSize);
   vOptRectSize -= (1.0 - clamp(borderlineOffset, -1.0, 1.0)) * 0.5 * borderlineWidth + 1.0;
 #elif defined(IS_REQUIRED_ROUNDED_CORNER)
-  vPosition = aPosition * visualSize;
+  vPosition = aPosition * (visualSize + vertexMargin);
 #else
   mediump vec2 vPosition = aPosition * visualSize;
 #endif
index bad5500..98a7347 100644 (file)
@@ -3,6 +3,7 @@ INPUT mediump vec2 vTexCoord;
 INPUT mediump vec2 vPosition;
 INPUT mediump vec2 vRectSize;
 INPUT mediump vec2 vOptRectSize;
+INPUT mediump float vAliasMargin;
 #ifdef IS_REQUIRED_ROUNDED_CORNER
 INPUT mediump vec4 vCornerRadius;
 #endif
@@ -26,11 +27,6 @@ uniform mediump vec4 uAtlasRect;
 uniform lowp vec2 wrapMode;
 #endif
 
-#if defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
-// Be used when we calculate anti-alias range near 1 pixel.
-uniform highp vec3 uScale;
-#endif
-
 uniform lowp vec4 uColor;
 uniform lowp vec3 mixColor;
 uniform lowp float preMultipliedAlpha;
@@ -104,10 +100,7 @@ void calculatePotential()
 
 void setupMinMaxPotential()
 {
-  // Set soft anti-alias range at most 10% of visual size.
-  // The range should be inverse proportion with scale of view.
-  // To avoid divid-by-zero, let we allow minimum scale value is 0.001 (0.1%)
-  gPotentialRange = min(1.0, max(vRectSize.x, vRectSize.y) * 0.2) / max(0.001, max(uScale.x, uScale.y));
+  gPotentialRange = vAliasMargin;
 
   gMaxOutlinePotential = gRadius + gPotentialRange;
   gMinOutlinePotential = gRadius - gPotentialRange;
index a1243ec..6109c29 100644 (file)
@@ -4,6 +4,7 @@ OUTPUT mediump vec2 vTexCoord;
 OUTPUT mediump vec2 vPosition;
 OUTPUT mediump vec2 vRectSize;
 OUTPUT mediump vec2 vOptRectSize;
+OUTPUT mediump float vAliasMargin;
 #ifdef IS_REQUIRED_ROUNDED_CORNER
 OUTPUT mediump vec4 vCornerRadius;
 #endif
@@ -13,6 +14,11 @@ uniform highp mat4 uMvpMatrix;
 uniform highp vec3 uSize;
 uniform mediump vec4 pixelArea;
 
+#if defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
+// Be used when we calculate anti-alias range near 1 pixel.
+uniform highp vec3 uScale;
+#endif
+
 //Visual size and offset
 uniform mediump vec2 offset;
 uniform highp vec2 size;
@@ -42,6 +48,13 @@ vec4 ComputeVertexPosition()
 #if defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
   vRectSize = visualSize * 0.5;
   vOptRectSize = vRectSize;
+
+  // Set soft anti-alias range at most 10% of visual size.
+  // The range should be inverse proportion with scale of view.
+  // To avoid divid-by-zero, let we allow minimum scale value is 0.001 (0.1%)
+  vAliasMargin = min(1.0, max(visualSize.x, visualSize.y) * 0.1) / max(0.001, max(uScale.x, uScale.y));
+
+  mediump float vertexMargin = 0.0;
 #endif
 
 #ifdef IS_REQUIRED_BORDERLINE
@@ -51,22 +64,30 @@ vec4 ComputeVertexPosition()
 
 #ifdef IS_REQUIRED_ROUNDED_CORNER
 #ifdef IS_REQUIRED_BORDERLINE
+  mediump float maxSize = max(visualSize.x, visualSize.y) + outerBorderlineSize;
   mediump float minSize = min(visualSize.x, visualSize.y) + outerBorderlineSize;
 #else
+  mediump float maxSize = max(visualSize.x, visualSize.y);
   mediump float minSize = min(visualSize.x, visualSize.y);
 #endif
   vCornerRadius = mix(cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);
   vCornerRadius = min(vCornerRadius, minSize * 0.5);
   // Optimize fragment shader. 0.2929 ~= 1.0 - sqrt(0.5)
   mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
+  mediump float minRadius = min(min(vCornerRadius.x, vCornerRadius.y), min(vCornerRadius.z, vCornerRadius.w));
   vOptRectSize -= 0.2929 * maxRadius + 1.0;
+
+  // Set vertex margin as vAliasMargin if we need to make some more fragments for alias.
+  // Do not increase margin if the minRadius is small enough rather than maxSize.
+  // TODO : We should change the magic parameter, 0.49
+  vertexMargin = 2.0 * vAliasMargin * smoothstep(maxSize * 0.49, maxSize * 0.5, minRadius);
 #endif
 
 #ifdef IS_REQUIRED_BORDERLINE
-  vPosition = aPosition * (visualSize + outerBorderlineSize);
+  vPosition = aPosition * (visualSize + outerBorderlineSize + vertexMargin);
   vOptRectSize -= (borderlineWidth - outerBorderlineSize * 0.5) + 1.0;
 #elif defined(IS_REQUIRED_ROUNDED_CORNER)
-  vPosition = aPosition * visualSize;
+  vPosition = aPosition * (visualSize + vertexMargin);
 #else
   mediump vec2 vPosition = aPosition * visualSize;
 #endif
@@ -81,13 +102,17 @@ vec4 ComputeVertexPosition()
                        cropToMask);
   vMaskTexCoord = pixelArea.xy + pixelArea.zw * (vec2(0.5) + aPosition.xy
 #ifdef IS_REQUIRED_BORDERLINE
-                                                  * (1.0 +  outerBorderlineSize / visualSize)
+                                                  * (1.0 + (outerBorderlineSize + vertexMargin) / visualSize)
+#elif defined(IS_REQUIRED_ROUNDED_CORNER)
+                                                  * (1.0 + vertexMargin / visualSize)
 #endif
                                                 );
 #endif
   vTexCoord = finalPixelArea.xy + finalPixelArea.zw * (vec2(0.5) + aPosition.xy
 #ifdef IS_REQUIRED_BORDERLINE
-                                                        * (1.0 + outerBorderlineSize / visualSize)
+                                                        * (1.0 + (outerBorderlineSize + vertexMargin) / visualSize)
+#elif defined(IS_REQUIRED_ROUNDED_CORNER)
+                                                        * (1.0 + vertexMargin / visualSize)
 #endif
                                                       );
 
index ebefb94..0f5f123 100644 (file)
@@ -222,9 +222,9 @@ void FastTrackLoadingTask::Load()
     std::ostringstream oss;
     oss << "[";
     oss << "pixelBuffers:" << pixelBuffers.size() << " ";
-    if(!pixelBuffers.empty())
+    if(!mPixelData.empty())
     {
-      oss << "size:" << pixelBuffers[0].GetWidth() << "x" << pixelBuffers[0].GetHeight() << " ";
+      oss << "size:" << mPixelData[0].GetWidth() << "x" << mPixelData[0].GetHeight() << " ";
       oss << "premult:" << mPremultiplied << " ";
     }
     oss << "url:" << mUrl.GetUrl() << "]";
index 9761015..c193fe7 100644 (file)
@@ -36,8 +36,30 @@ namespace
 const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
 
 const int NATIVE_SHADER_TYPE_OFFSET = VisualFactoryCache::ShaderType::NATIVE_IMAGE_SHADER - VisualFactoryCache::ShaderType::IMAGE_SHADER;
+
 } // unnamed namespace
 
+static constexpr auto          SHADER_TYPE_COUNT = 6u;
+
+const std::string_view VertexPredefines[SHADER_TYPE_COUNT]
+{
+  "", // VisualFactoryCache::IMAGE_SHADER,
+  "#define IS_REQUIRED_ROUNDED_CORNER\n", //VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER,
+  "",//VisualFactoryCache::IMAGE_SHADER_YUV_TO_RGB,
+  "#define IS_REQUIRED_ROUNDED_CORNER\n",//VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_TO_RGB,
+  "",//VisualFactoryCache::IMAGE_SHADER_YUV_AND_RGB,
+  "#define IS_REQUIRED_ROUNDED_CORNER\n",//VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_AND_RGB,
+};
+const std::string_view FragmentPredefines[SHADER_TYPE_COUNT]
+{
+  "", // VisualFactoryCache::IMAGE_SHADER,
+  "#define IS_REQUIRED_ROUNDED_CORNER\n", //VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER,
+  "#define IS_REQUIRED_YUV_TO_RGB\n",//VisualFactoryCache::IMAGE_SHADER_YUV_TO_RGB,
+  "#define IS_REQUIRED_YUV_TO_RGB\n#define IS_REQUIRED_ROUNDED_CORNER\n",//VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_TO_RGB,
+  "#define IS_REQUIRED_UNIFIED_YUV_AND_RGB\n",//VisualFactoryCache::IMAGE_SHADER_YUV_AND_RGB,
+  "#define IS_REQUIRED_UNIFIED_YUV_AND_RGB\n#define IS_REQUIRED_ROUNDED_CORNER\n",//VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_AND_RGB,
+};
+
 ImageVisualShaderFactory::ImageVisualShaderFactory()
 : mFragmentShaderNeedChange(ImageVisualShaderFeature::ChangeFragmentShader::UNDECIDED)
 {
@@ -127,6 +149,26 @@ std::string_view ImageVisualShaderFactory::GetFragmentShaderSource()
   return gFragmentShaderNoAtlas;
 }
 
+void ImageVisualShaderFactory::GetPreCompiledShader(RawShaderData& shaders)
+{
+  std::vector<std::string_view> vertexPrefix;
+  std::vector<std::string_view> fragmentPrefix;
+  shaders.shaderCount = 0;
+  int shaderCount = 0;
+  for(uint32_t i=0; i< SHADER_TYPE_COUNT; ++i)
+  {
+    vertexPrefix.push_back(VertexPredefines[i]);
+    fragmentPrefix.push_back(FragmentPredefines[i]);
+    shaderCount++;
+  }
+
+  shaders.vertexPrefix= vertexPrefix;
+  shaders.fragmentPrefix = fragmentPrefix;
+  shaders.vertexShader = SHADER_IMAGE_VISUAL_SHADER_VERT;
+  shaders.fragmentShader = SHADER_IMAGE_VISUAL_SHADER_FRAG;
+  shaders.shaderCount = shaderCount;
+}
+
 } // namespace Internal
 
 } // namespace Toolkit
index cf1c25b..8b50669 100644 (file)
@@ -67,6 +67,12 @@ public:
    */
   std::string_view GetFragmentShaderSource();
 
+  /**
+   * @brief Get the default shader source.
+   * @param[in] shaders shaderList for precompile
+   */
+  void GetPreCompiledShader(RawShaderData& shaders);
+
 protected:
   /**
    * Undefined copy constructor.
index 5f9b04b..62d82f8 100644 (file)
@@ -56,6 +56,16 @@ const VisualFactoryCache::ShaderType SHADER_TYPE_TABLE[] =
     VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE_AND_OVERLAY,
 };
 
+static constexpr auto          SHADER_TYPE_COUNT = 1u;
+const std::string_view VertexPredefines[SHADER_TYPE_COUNT]
+{
+  "", // VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT
+};
+const std::string_view FragmentPredefines[SHADER_TYPE_COUNT]
+{
+  "", // VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT
+};
+
 } // unnamed namespace
 
 namespace TextVisualShaderFeature
@@ -154,6 +164,25 @@ Shader TextVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, cons
   return shader;
 }
 
+void TextVisualShaderFactory::GetPreCompiledShader(RawShaderData& shaders)
+{
+  std::vector<std::string_view> vertexPrefix;
+  std::vector<std::string_view> fragmentPrefix;
+  int shaderCount = 0;
+  for(uint32_t i=0; i< SHADER_TYPE_COUNT; ++i)
+  {
+    vertexPrefix.push_back(VertexPredefines[i]);
+    fragmentPrefix.push_back(FragmentPredefines[i]);
+    shaderCount++;
+  }
+
+  shaders.vertexPrefix= vertexPrefix;
+  shaders.fragmentPrefix = fragmentPrefix;
+  shaders.vertexShader = SHADER_TEXT_VISUAL_SHADER_VERT;
+  shaders.fragmentShader = SHADER_TEXT_VISUAL_SHADER_FRAG;
+  shaders.shaderCount = shaderCount;
+}
+
 } // namespace Internal
 
 } // namespace Toolkit
index 4a9969b..ba4f606 100644 (file)
@@ -149,6 +149,12 @@ public:
    */
   Shader GetShader(VisualFactoryCache& factoryCache, const TextVisualShaderFeature::FeatureBuilder& featureBuilder);
 
+  /**
+   * @brief Get the default shader source.
+   * @param[in] shaders shaderList for precompile
+   */
+  void GetPreCompiledShader(RawShaderData& shaders);
+
 protected:
   /**
    * Undefined copy constructor.
index b3801f6..33e2c41 100644 (file)
@@ -276,7 +276,7 @@ void TextVisual::OnInitialize()
 
   mImpl->mRenderer = VisualRenderer::New(geometry, shader);
   mImpl->mRenderer.ReserveCustomProperties(CUSTOM_PROPERTY_COUNT);
-  mHasMultipleTextColorsIndex = mImpl->mRenderer.RegisterUniqueProperty("uHasMultipleTextColors", false);
+  mHasMultipleTextColorsIndex = mImpl->mRenderer.RegisterUniqueProperty("uHasMultipleTextColors", static_cast<float>(false));
 }
 
 void TextVisual::DoSetProperties(const Property::Map& propertyMap)
index f1d9703..7e651a6 100644 (file)
@@ -23,6 +23,7 @@
 #include <dali/public-api/object/ref-object.h>
 #include <dali/public-api/rendering/geometry.h>
 #include <dali/public-api/rendering/shader.h>
+#include <dali/integration-api/adaptor-framework/shader-precompiler.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/texture-manager/texture-manager-impl.h>
index 7cc5119..4a8a6d4 100644 (file)
@@ -42,6 +42,7 @@
 #include <dali-toolkit/internal/visuals/npatch/npatch-visual.h>
 #include <dali-toolkit/internal/visuals/primitive/primitive-visual.h>
 #include <dali-toolkit/internal/visuals/svg/svg-visual.h>
+#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
 #include <dali-toolkit/internal/visuals/text-visual-shader-factory.h>
 #include <dali-toolkit/internal/visuals/text/text-visual.h>
 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
@@ -52,6 +53,7 @@
 #include <dali-toolkit/public-api/visuals/text-visual-properties.h>
 #include <dali-toolkit/public-api/visuals/visual-properties.h>
 
+
 namespace Dali
 {
 namespace Toolkit
@@ -75,6 +77,18 @@ DALI_TYPE_REGISTRATION_BEGIN_CREATE(Toolkit::VisualFactory, Dali::BaseHandle, Cr
 DALI_TYPE_REGISTRATION_END()
 const char* const BROKEN_IMAGE_FILE_NAME = "broken.png"; ///< The file name of the broken image.
 
+static constexpr auto          SHADER_TYPE_COUNT = 2u;
+const std::string_view VertexPredefines[SHADER_TYPE_COUNT]
+{
+  "", //VisualFactoryCache::COLOR_SHADER
+  "#define IS_REQUIRED_ROUNDED_CORNER\n", //VisualFactoryCache::COLOR_SHADER_ROUNDED_CORNER
+};
+const std::string_view FragmentPredefines[SHADER_TYPE_COUNT]
+{
+  "", //VisualFactoryCache::COLOR_SHADER
+  "#define IS_REQUIRED_ROUNDED_CORNER\n", //VisualFactoryCache::COLOR_SHADER_ROUNDED_CORNER
+};
+
 } // namespace
 
 VisualFactory::VisualFactory(bool debugEnabled)
@@ -84,7 +98,8 @@ VisualFactory::VisualFactory(bool debugEnabled)
   mSlotDelegate(this),
   mIdleCallback(nullptr),
   mDebugEnabled(debugEnabled),
-  mPreMultiplyOnLoad(true)
+  mPreMultiplyOnLoad(true),
+  mPrecompiledShaderRequested(false)
 {
 }
 
@@ -393,6 +408,37 @@ void VisualFactory::DiscardVisual(Toolkit::Visual::Base visual)
   RegisterDiscardCallback();
 }
 
+void VisualFactory::UsePreCompiledShader()
+{
+  if(mPrecompiledShaderRequested)
+  {
+    return;
+  }
+  mPrecompiledShaderRequested = true;
+
+  ShaderPreCompiler::Get().Enable();
+
+  // Get image shader
+  std::vector<RawShaderData> rawShaderList;
+  RawShaderData imageShaderData;
+  GetImageVisualShaderFactory().GetPreCompiledShader(imageShaderData);
+  rawShaderList.push_back(imageShaderData);
+
+  // Get text shader
+  RawShaderData textShaderData;
+  GetTextVisualShaderFactory().GetPreCompiledShader(textShaderData);
+  rawShaderList.push_back(textShaderData);
+
+  // Get color shader
+  RawShaderData colorShaderData;
+  GetPreCompiledShader(colorShaderData);
+  rawShaderList.push_back(colorShaderData);
+
+
+  // Save all shader
+  ShaderPreCompiler::Get().SavePreCompileShaderList(rawShaderList);
+}
+
 Internal::TextureManager& VisualFactory::GetTextureManager()
 {
   return GetFactoryCache().GetTextureManager();
@@ -418,6 +464,26 @@ void VisualFactory::SetBrokenImageUrl(Toolkit::StyleManager& styleManager)
   mFactoryCache->SetBrokenImageUrl(brokenImageUrl, customBrokenImageUrlList);
 }
 
+void VisualFactory::GetPreCompiledShader(RawShaderData& shaders)
+{
+  std::vector<std::string_view> vertexPrefix;
+  std::vector<std::string_view> fragmentPrefix;
+  int shaderCount = 0;
+  shaders.shaderCount = 0;
+  for(uint32_t i=0u; i< SHADER_TYPE_COUNT; ++i)
+  {
+    vertexPrefix.push_back(VertexPredefines[i]);
+    fragmentPrefix.push_back(FragmentPredefines[i]);
+    shaderCount++;
+  }
+
+  shaders.vertexPrefix = vertexPrefix;
+  shaders.fragmentPrefix = fragmentPrefix;
+  shaders.vertexShader = SHADER_COLOR_VISUAL_SHADER_VERT;
+  shaders.fragmentShader = SHADER_COLOR_VISUAL_SHADER_FRAG;
+  shaders.shaderCount = shaderCount;
+}
+
 Internal::VisualFactoryCache& VisualFactory::GetFactoryCache()
 {
   if(!mFactoryCache)
@@ -431,6 +497,7 @@ Internal::VisualFactoryCache& VisualFactory::GetFactoryCache()
     }
     SetBrokenImageUrl(styleManager);
   }
+
   return *mFactoryCache;
 }
 
index c0b95b4..76bacf9 100644 (file)
@@ -20,6 +20,7 @@
 // EXTERNAL INCLUDES
 #include <dali/public-api/common/vector-wrapper.h>
 #include <dali/public-api/object/base-object.h>
+#include <dali/integration-api/adaptor-framework/shader-precompiler.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/visual-factory/visual-base.h>
@@ -91,6 +92,11 @@ public:
   void DiscardVisual(Toolkit::Visual::Base visual);
 
   /**
+   * @copydoc Toolkit::VisualFactory::UsePreCompiledShader()
+   */
+  void UsePreCompiledShader();
+
+  /**
    * @return the reference to texture manager
    */
   Internal::TextureManager& GetTextureManager();
@@ -109,6 +115,12 @@ private:
   void SetBrokenImageUrl(Toolkit::StyleManager& styleManager);
 
   /**
+   * @brief Get the default shader source.
+   * @param[in] shaders shaderList for precompile
+   */
+  void GetPreCompiledShader(RawShaderData& shaders);
+
+  /**
    * Get the factory cache, creating it if necessary.
    */
   Internal::VisualFactoryCache& GetFactoryCache();
@@ -143,12 +155,11 @@ private:
   std::unique_ptr<TextVisualShaderFactory>  mTextVisualShaderFactory;
   SlotDelegate<VisualFactory>               mSlotDelegate;
   CallbackBase*                             mIdleCallback;
-
   using DiscardedVisualContainer = std::vector<Toolkit::Visual::Base>;
   DiscardedVisualContainer mDiscardedVisuals{};
-
-  bool mDebugEnabled : 1;
-  bool mPreMultiplyOnLoad : 1; ///< Local store for this flag
+  bool                                      mDebugEnabled : 1;
+  bool                                      mPreMultiplyOnLoad : 1; ///< Local store for this flag
+  bool                                      mPrecompiledShaderRequested : 1;
 };
 
 /**
index 0457eca..d2f735e 100644 (file)
@@ -28,8 +28,8 @@ namespace Dali
 namespace Toolkit
 {
 const unsigned int TOOLKIT_MAJOR_VERSION = 2;
-const unsigned int TOOLKIT_MINOR_VERSION = 2;
-const unsigned int TOOLKIT_MICRO_VERSION = 53;
+const unsigned int TOOLKIT_MINOR_VERSION = 3;
+const unsigned int TOOLKIT_MICRO_VERSION = 0;
 const char* const  TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index fada506..ae68e55 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali2-toolkit
 Summary:    Dali 3D engine Toolkit
-Version:    2.2.53
+Version:    2.3.0
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT
diff --git a/tools/navigation-mesh-exporter/NavigationMeshExport.py b/tools/navigation-mesh-exporter/NavigationMeshExport.py
new file mode 100644 (file)
index 0000000..16e90ef
--- /dev/null
@@ -0,0 +1,411 @@
+import bpy
+import struct
+import ctypes
+import tempfile
+import os
+import mathutils
+from mathutils import Matrix
+from mathutils import Vector
+
+def MakeVersion( maj, min ):
+    return ctypes.c_uint32((ctypes.c_uint32(maj).value << 16) | ctypes.c_uint32(min).value).value
+
+EXPORT_VERSION = MakeVersion( 1, 0 )
+
+# If BAKE_TRANSFORM is True the object transform is baked into vertices
+BAKE_TRANSFORM = False
+
+CHECKSUM = "NAVM" # 4 bytes of checksum
+
+# From GLTF addon
+def to_yup():
+    """Transform to Yup."""
+    return 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))
+    )
+
+def to_yup3():
+    """Transform to Yup."""
+    return Matrix(
+        ((1.0, 0.0, 0.0),
+         (0.0, 0.0, 1.0),
+         (0.0, -1.0, 0.0))
+    )
+
+# struct NavMeshHeader
+# version 10
+# The script writes multiple binary buffers which are concatenated at the end once
+# the offsets are resolved
+class NavMeshHeader10:
+
+    # fields of NavMeshHeader
+
+    def __init__(self, outputPath):
+        self.outputPath = outputPath
+        self.meshObject = bpy.context.selected_objects[0]
+
+        self.checksum = CHECKSUM
+        self.version = EXPORT_VERSION
+
+        # fields of version
+        self.dataOffset = 0
+
+        self.vertexCount = 0
+        self.vertexDataOffset = 0
+
+        self.edgeCount = 0
+        self.edgeDataOffset = 0
+
+        self.polyCount = 0
+        self.polyDataOffset = 0
+
+        self.mesh = self.meshObject.data
+
+        # helper fields
+        self.edgeBufferSize = 0
+        self.vertexBufferSize = 0
+        self.polyBufferSize = 0
+        self.bufferHeaderSize = 0
+        self.endianness = 0 # TODO
+
+        with tempfile.TemporaryDirectory() as temp_dir:
+            self.tempDir = temp_dir
+
+        print(temp_dir)
+        os.makedirs(temp_dir, exist_ok=True)
+        return
+
+    def Process(self):
+
+        # the data offset will be filled at later stage
+        self.polyCount = len(self.mesh.polygons)
+        self.vertexCount = len(self.mesh.vertices)
+        self.edgeCount = len(self.mesh.edges)
+        return
+
+    # vertices format
+    # N x ( f, f, f ), indexed from 0
+    def WriteVertices(self, bakeTransform=True):
+        out = open(os.path.join(self.tempDir, "myvertex-vertices-nt.bin"), "wb")
+        i = 0
+        for vert in self.mesh.vertices:
+            fmt = '@fff'
+            co = vert.co.copy()
+            # for now bake transform into the mesh (it has to be aligned properly)
+            if bakeTransform:
+                print('baking')
+                co = self.meshObject.matrix_world @ Vector(co)
+
+            out.write(struct.pack(fmt, co[0], co[1], co[2]))
+            print(f'i: {i:d}: {co[0]:f}, {co[1]:f}, {co[2]:f}')
+            i += 1
+        self.vertexBufferSize = out.tell()
+        out.close()
+        return
+
+    # This function builds vertex map after finding duplicate vertices
+    # it is essential to do it as two or more vertices may appear as one
+    # in the editor, yet they may be defined as multiple vertices due to carrying
+    # different UVs or other attributes. NavMesh needs only coordinates and
+    # two vertices with the same coordinates are considered as one.
+    def CreateEdgeMap(self):
+        mesh = self.mesh
+        vertexBuffer = {}
+        i = 0
+        for v in mesh.vertices:
+            # using string of coordinates as a key
+            key = f'{v.co}'
+
+            if key in vertexBuffer:
+                vertexBuffer[key].append(i)
+            else:
+                vertexBuffer[key] = [i]
+            i += 1
+
+        # build substitute array
+        # value at each index will be either own (no substitute)
+        # or of another vertex so the keys of edges can be substituted
+
+        vertexSubstitute = []
+        for v in mesh.vertices:
+            key = f'{v.co}'
+            verts = vertexBuffer[key]
+
+            # store always only first index of vertex
+            vertexSubstitute.append(verts[0])
+
+        #for i in range(0, len(vertexSubstitute)):
+        #    print(f'{i} = {vertexSubstitute[i]}')
+
+        # build edge map
+        # we need to remap edge keys so we can point out to a single edge
+        # end remove duplicates
+        # Blender edge key is made of vertex indices sorted
+        origKeys = []
+        for e in mesh.edges:
+            v0 = e.vertices[0]
+            v1 = e.vertices[1]
+            key = [v0, v1]
+            key.sort()
+            origKeys.append(key)
+            #print(key)
+
+        # create new keys by using vertex substitutes
+        keyMap = {}
+        edgeMap = {}
+        edgeIndex = 0
+
+        for key in origKeys:
+            newKey = [vertexSubstitute[key[0]], vertexSubstitute[key[1]]]
+            newKey.sort()
+
+            # turn newkey into hashable string
+            newKeyStr = f'{newKey}'
+
+            #print(f'{key} -> {newKey}')
+
+            if newKeyStr in keyMap:
+                keyMap[newKeyStr].append(edgeIndex)
+            else:
+                keyMap[newKeyStr] = [edgeIndex]
+
+            # turn original key into string
+            edgeMap[f'{key}'] = keyMap[newKeyStr][0]
+            edgeIndex += 1
+
+        return edgeMap
+
+
+    """
+    Edge data stores:
+    Pair of vertices (by index)
+    Pair of polygons (by index)
+
+    The polygon index is stored as uint16_t.
+    It is possible that the edge belongs to a single polygon. In such case,
+    the maximum of 0xFFFFF is stored as an index.
+    The maximum index of polygon is 0xFFFE (65534).
+
+    The pair of polygons are stored in order to speed up lookup of adjacent
+    floor faces.
+    """
+    # N x ( f, f, f ), indexed from 0
+    def WriteEdges(self):
+        out = open(os.path.join(self.tempDir, "myvertex-edges.bin"), "wb")
+
+        # add vertices to the edge
+        edgeFaceList = []
+        for edge in self.mesh.edges:
+            edgeFaceList.append([])
+            edgeFaceList[-1].append(edge.vertices[0])
+            edgeFaceList[-1].append(edge.vertices[1])
+
+        edgeMap = self.CreateEdgeMap()
+
+        # for each polygon update the edges
+        for poly in self.mesh.polygons:
+            for ek in poly.edge_keys:
+                ekArray = [ ek[0], ek[1] ]
+                edgeIndexKey = f'{ekArray}'
+                edgeIndex = edgeMap[edgeIndexKey]
+                edgeFaceList[edgeIndex].append(poly.index)
+
+        # make sure each edge contains 4 items
+        for edge in edgeFaceList:
+            if len(edge) == 2:
+                edge.append( 0xffff )
+            if len(edge) == 3:
+                edge.append( 0xffff )
+        count = 0
+        for edge in edgeFaceList:
+            if len(edge) == 4:
+                count += 1
+        if count == len(edgeFaceList):
+            print("all correct!")
+        # save the data into file
+        fmt = '@HHHH'
+        i = 0
+        for edge in edgeFaceList:
+            out.write(struct.pack(fmt, edge[0], edge[1], edge[2], edge[3]))
+            print(f'i: {i:d}: {edge[0]:d}, {edge[1]:d}, {edge[2]:d}, {edge[3]:d}')
+            i += 1
+
+        self.edgeBufferSize = out.tell()
+
+        out.close()
+        return
+
+    ###################################################################
+    """
+    Writes buffer of polygons. Polys must be triangles.
+    The data contains:
+    - vertex indices 3*u16
+    - edge indices   3*u16
+    - normal vector of poly 3*f32
+    - center 3*f32 (we may need center point for navigation)
+    """
+    def WritePolys(self):
+        out = open(os.path.join(self.tempDir, "myvertex-polys.bin"), "wb")
+
+        # for each polygon update the edges
+
+        polyIndex = 0
+
+        edgeMap = self.CreateEdgeMap()
+
+        for poly in self.mesh.polygons:
+            edges = []
+            for ek in poly.edge_keys:
+                ekArray = [ ek[0], ek[1] ]
+                edgeIndexKey = f'{ekArray}'
+                edges.append(edgeMap[edgeIndexKey])
+
+            verts = poly.vertices
+            norm = poly.normal.copy()
+
+            # transform
+            print(f'{norm.x:f}, {norm.y:f}, {norm.z:f}')
+
+            center = poly.center
+
+            # calculate normal
+
+            fmt='@HHHHHHffffff'
+
+            out.write(struct.pack(fmt,
+                                  verts[0], verts[1], verts[2],
+                                  edges[0], edges[1], edges[2],
+                                  norm.x, norm.y, norm.z,
+                                  center.x, center.y, center.z))
+
+            print('{edges[0]}, {edges[1]}, {edges[2]}')
+        self.polyBufferSize = out.tell()
+        out.close()
+        return
+
+    def WriteBinary(self):
+
+        out = open(self.outputPath, "wb")
+
+        # write common header fields
+        c = bytes(CHECKSUM, "ascii")
+        csum = ctypes.c_uint32( (c[3] << 24) | (c[2] << 16) | (c[1] << 8) | c[0] ).value
+        fmt = "@II"
+        out.write(struct.pack(fmt, csum, self.version))
+
+        # write remaining fields
+        fmt = '@IIIIIIIfff'
+        gravity = bpy.context.scene.gravity.copy().normalized()
+        out.write(struct.pack(fmt,
+                              self.dataOffset,
+                              self.vertexCount,
+                              self.vertexDataOffset,
+                              self.edgeCount,
+                              self.edgeDataOffset,
+                              self.polyCount,
+                              self.polyDataOffset,
+                              gravity.x, gravity.y, gravity.z
+                              ))
+
+        self.bufferHeaderSize = out.tell()
+
+        out.close()
+
+        return
+
+    def Finalize(self):
+
+        self.dataOffset = self.bufferHeaderSize
+        self.vertexDataOffset = 0 # relative to data offset
+        self.edgeDataOffset = self.vertexBufferSize
+        self.polyDataOffset = self.edgeDataOffset + self.edgeBufferSize
+
+        # write header again
+        self.WriteBinary()
+
+        # concatenate files
+
+        with open(self.outputPath, "ab") as out, open(os.path.join(self.tempDir, "myvertex-vertices-nt.bin"), "rb") as file2:
+            out.write(file2.read())
+
+        with open(self.outputPath, "ab") as out, open(os.path.join(self.tempDir, "myvertex-edges.bin"), "rb") as file2:
+            out.write(file2.read())
+
+        with open(self.outputPath, "ab") as out, open(os.path.join(self.tempDir, "myvertex-polys.bin"), "rb") as file2:
+            out.write(file2.read())
+
+        return
+
+
+################################################################
+# UI
+
+# Navigation Mesh Exporter
+class OBJECT_OT_CustomOperator(bpy.types.Operator):
+    bl_idname = "object.custom_operator"
+    bl_label = "Export Navigation Mesh"
+
+    def execute(self, context):
+        bpy.ops.export.some_data('INVOKE_DEFAULT')
+        return {'FINISHED'}
+
+def submenu_func(self, context):
+    layout = self.layout
+    layout.operator("object.custom_operator")
+
+def menu_func(self, context):
+    layout = self.layout
+
+    # Add a submenu
+    layout.menu("VIEW3D_MT_custom_submenu", text="DALi")
+
+class CustomSubmenu(bpy.types.Menu):
+    bl_idname = "VIEW3D_MT_custom_submenu"
+    bl_label = "DALi"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.operator("object.custom_operator")
+
+def register():
+    bpy.utils.register_class(OBJECT_OT_CustomOperator)
+    bpy.types.VIEW3D_MT_object_context_menu.append(menu_func)
+    bpy.utils.register_class(CustomSubmenu)
+    bpy.utils.register_class(ExportSomeData)
+def unregister():
+    bpy.utils.unregister_class(OBJECT_OT_CustomOperator)
+    bpy.types.VIEW3D_MT_object_context_menu.remove(menu_func)
+    bpy.utils.unregister_class(CustomSubmenu)
+    bpy.utils.unregister_class(ExportSomeData)
+
+# exporter
+class ExportSomeData(bpy.types.Operator):
+    bl_idname = "export.some_data"
+    bl_label = "Export DALi Navigation Mesh"
+
+    filepath: bpy.props.StringProperty(subtype="FILE_PATH")
+
+    @classmethod
+    def poll(cls, context):
+        return context.object is not None
+
+    def execute(self, context):
+        print(self.filepath)
+        navmesh = NavMeshHeader10( self.filepath )
+        navmesh.Process()
+        navmesh.WriteBinary()
+        navmesh.WriteVertices( False )
+        navmesh.WriteEdges()
+        navmesh.WritePolys()
+        navmesh.Finalize()
+        return {'FINISHED'}
+
+    def invoke(self, context, event):
+        context.window_manager.fileselect_add(self)
+        return {'RUNNING_MODAL'}
+
+if __name__ == "__main__":
+    register()
diff --git a/tools/navigation-mesh-exporter/README.md b/tools/navigation-mesh-exporter/README.md
new file mode 100644 (file)
index 0000000..fa8be14
--- /dev/null
@@ -0,0 +1,18 @@
+NavigationMeshExporter
+======================
+
+Script for Blender which allows exporting navigation (collision) mesh data.
+
+Register new operator:
+1. Open script in Blender (or copy paste as internal)
+2. Execute
+3. Nothing will happen but new operator will register
+
+Usage:
+
+1. Press RMB on the object to export
+2. Go to "DALi" group
+3. Select "Export Navigation Mesh"
+
+![Popup menu](screen.png)
+
diff --git a/tools/navigation-mesh-exporter/screen.png b/tools/navigation-mesh-exporter/screen.png
new file mode 100644 (file)
index 0000000..fda7c01
Binary files /dev/null and b/tools/navigation-mesh-exporter/screen.png differ