--- /dev/null
+{\r
+ "buffers":[\r
+ {\r
+ "uri":"AnimatedMorphCubeQuantized.bin",\r
+ "byteLength":1700\r
+ }\r
+ ],\r
+ "asset":{\r
+ "version":"2.0",\r
+ "generator":"gltfpack 0.13"\r
+ },\r
+ "extensionsUsed":[\r
+ "KHR_mesh_quantization"\r
+ ],\r
+ "extensionsRequired":[\r
+ "KHR_mesh_quantization"\r
+ ],\r
+ "bufferViews":[\r
+ {\r
+ "buffer":0,\r
+ "byteOffset":0,\r
+ "byteLength":288,\r
+ "byteStride":4,\r
+ "target":34962\r
+ },\r
+ {\r
+ "buffer":0,\r
+ "byteOffset":288,\r
+ "byteLength":576,\r
+ "byteStride":8,\r
+ "target":34962\r
+ },\r
+ {\r
+ "buffer":0,\r
+ "byteOffset":864,\r
+ "byteLength":72,\r
+ "target":34963\r
+ },\r
+ {\r
+ "buffer":0,\r
+ "byteOffset":936,\r
+ "byteLength":508\r
+ },\r
+ {\r
+ "buffer":0,\r
+ "byteOffset":1444,\r
+ "byteLength":254\r
+ }\r
+ ],\r
+ "accessors":[\r
+ {\r
+ "bufferView":0,\r
+ "byteOffset":0,\r
+ "componentType":5120,\r
+ "count":24,\r
+ "type":"VEC3",\r
+ "normalized":true\r
+ },\r
+ {\r
+ "bufferView":1,\r
+ "byteOffset":0,\r
+ "componentType":5123,\r
+ "count":24,\r
+ "type":"VEC3",\r
+ "min":[\r
+ 0,\r
+ 5451,\r
+ 0\r
+ ],\r
+ "max":[\r
+ 5481,\r
+ 10932,\r
+ 5481\r
+ ]\r
+ },\r
+ {\r
+ "bufferView":0,\r
+ "byteOffset":96,\r
+ "componentType":5120,\r
+ "count":24,\r
+ "type":"VEC3",\r
+ "normalized":true\r
+ },\r
+ {\r
+ "bufferView":1,\r
+ "byteOffset":192,\r
+ "componentType":5122,\r
+ "count":24,\r
+ "type":"VEC3",\r
+ "min":[\r
+ 0,\r
+ 0,\r
+ 0\r
+ ],\r
+ "max":[\r
+ 0,\r
+ 5188,\r
+ 0\r
+ ]\r
+ },\r
+ {\r
+ "bufferView":0,\r
+ "byteOffset":192,\r
+ "componentType":5120,\r
+ "count":24,\r
+ "type":"VEC3",\r
+ "normalized":true\r
+ },\r
+ {\r
+ "bufferView":1,\r
+ "byteOffset":384,\r
+ "componentType":5122,\r
+ "count":24,\r
+ "type":"VEC3",\r
+ "min":[\r
+ 0,\r
+ 0,\r
+ 0\r
+ ],\r
+ "max":[\r
+ 0,\r
+ 5451,\r
+ 0\r
+ ]\r
+ },\r
+ {\r
+ "bufferView":2,\r
+ "byteOffset":0,\r
+ "componentType":5123,\r
+ "count":36,\r
+ "type":"SCALAR"\r
+ },\r
+ {\r
+ "bufferView":3,\r
+ "byteOffset":0,\r
+ "componentType":5126,\r
+ "count":127,\r
+ "type":"SCALAR",\r
+ "min":[\r
+ 0\r
+ ],\r
+ "max":[\r
+ 4.19999981\r
+ ]\r
+ },\r
+ {\r
+ "bufferView":4,\r
+ "byteOffset":0,\r
+ "componentType":5121,\r
+ "count":254,\r
+ "type":"SCALAR",\r
+ "normalized":true\r
+ }\r
+ ],\r
+ "materials":[\r
+ {\r
+ "name":"Material",\r
+ "pbrMetallicRoughness":{\r
+ "baseColorFactor":[\r
+ 0.603827417,\r
+ 0.603827417,\r
+ 0.603827417,\r
+ 1\r
+ ],\r
+ "metallicFactor":0,\r
+ "roughnessFactor":0.5\r
+ }\r
+ }\r
+ ],\r
+ "meshes":[\r
+ {\r
+ "primitives":[\r
+ {\r
+ "attributes":{\r
+ "NORMAL":0,\r
+ "POSITION":1\r
+ },\r
+ "mode":4,\r
+ "targets":[\r
+ {\r
+ "NORMAL":2,\r
+ "POSITION":3\r
+ },\r
+ {\r
+ "NORMAL":4,\r
+ "POSITION":5\r
+ }\r
+ ],\r
+ "indices":6,\r
+ "material":0\r
+ }\r
+ ],\r
+ "weights":[\r
+ 0,\r
+ 0\r
+ ]\r
+ }\r
+ ],\r
+ "animations":[\r
+ {\r
+ "name":"Square",\r
+ "samplers":[\r
+ {\r
+ "input":7,\r
+ "output":8\r
+ }\r
+ ],\r
+ "channels":[\r
+ {\r
+ "sampler":0,\r
+ "target":{\r
+ "node":0,\r
+ "path":"weights"\r
+ }\r
+ }\r
+ ]\r
+ }\r
+ ],\r
+ "nodes":[\r
+ {\r
+ "mesh":0,\r
+ "translation":[\r
+ -0.0100000044,\r
+ -0.0298908409,\r
+ -0.00999999978\r
+ ],\r
+ "scale":[\r
+ 3.64900689e-06,\r
+ 3.64900689e-06,\r
+ 3.64900689e-06\r
+ ]\r
+ },\r
+ {\r
+ "name":"AnimatedMorphCube",\r
+ "rotation":[\r
+ 0,\r
+ 0.707106709,\r
+ -0.707106829,\r
+ 0\r
+ ],\r
+ "scale":[\r
+ 100,\r
+ 100,\r
+ 100\r
+ ],\r
+ "children":[\r
+ 0\r
+ ]\r
+ }\r
+ ],\r
+ "scenes":[\r
+ {\r
+ "nodes":[\r
+ 1\r
+ ]\r
+ }\r
+ ],\r
+ "scene":0\r
+}\r
--- /dev/null
+{\r
+ "buffers":[\r
+ {\r
+ "uri":"AvocadoQuantized.bin",\r
+ "byteLength":12212\r
+ }\r
+ ],\r
+ "asset":{\r
+ "version":"2.0",\r
+ "generator":"gltfpack 0.13"\r
+ },\r
+ "extensionsUsed":[\r
+ "KHR_mesh_quantization",\r
+ "KHR_texture_transform"\r
+ ],\r
+ "extensionsRequired":[\r
+ "KHR_mesh_quantization"\r
+ ],\r
+ "bufferViews":[\r
+ {\r
+ "buffer":0,\r
+ "byteOffset":0,\r
+ "byteLength":1624,\r
+ "byteStride":4,\r
+ "target":34962\r
+ },\r
+ {\r
+ "buffer":0,\r
+ "byteOffset":1624,\r
+ "byteLength":1624,\r
+ "byteStride":4,\r
+ "target":34962\r
+ },\r
+ {\r
+ "buffer":0,\r
+ "byteOffset":3248,\r
+ "byteLength":1624,\r
+ "byteStride":4,\r
+ "target":34962\r
+ },\r
+ {\r
+ "buffer":0,\r
+ "byteOffset":4872,\r
+ "byteLength":3248,\r
+ "byteStride":8,\r
+ "target":34962\r
+ },\r
+ {\r
+ "buffer":0,\r
+ "byteOffset":8120,\r
+ "byteLength":4092,\r
+ "target":34963\r
+ }\r
+ ],\r
+ "accessors":[\r
+ {\r
+ "bufferView":0,\r
+ "byteOffset":0,\r
+ "componentType":5123,\r
+ "count":406,\r
+ "type":"VEC2"\r
+ },\r
+ {\r
+ "bufferView":1,\r
+ "byteOffset":0,\r
+ "componentType":5120,\r
+ "count":406,\r
+ "type":"VEC3",\r
+ "normalized":true\r
+ },\r
+ {\r
+ "bufferView":2,\r
+ "byteOffset":0,\r
+ "componentType":5120,\r
+ "count":406,\r
+ "type":"VEC4",\r
+ "normalized":true\r
+ },\r
+ {\r
+ "bufferView":3,\r
+ "byteOffset":0,\r
+ "componentType":5123,\r
+ "count":406,\r
+ "type":"VEC3",\r
+ "min":[\r
+ 0,\r
+ 0,\r
+ 0\r
+ ],\r
+ "max":[\r
+ 11086,\r
+ 16383,\r
+ 7194\r
+ ]\r
+ },\r
+ {\r
+ "bufferView":4,\r
+ "byteOffset":0,\r
+ "componentType":5123,\r
+ "count":2046,\r
+ "type":"SCALAR"\r
+ }\r
+ ],\r
+ "images":[\r
+ {\r
+ "uri":"Avocado_baseColor.png"\r
+ },\r
+ {\r
+ "uri":"Avocado_roughnessMetallic.png"\r
+ },\r
+ {\r
+ "uri":"Avocado_normal.png"\r
+ }\r
+ ],\r
+ "textures":[\r
+ {\r
+ "source":0\r
+ },\r
+ {\r
+ "source":1\r
+ },\r
+ {\r
+ "source":2\r
+ }\r
+ ],\r
+ "materials":[\r
+ {\r
+ "name":"2256_Avocado_d",\r
+ "pbrMetallicRoughness":{\r
+ "baseColorTexture":{\r
+ "index":0,\r
+ "texCoord":0,\r
+ "extensions":{\r
+ "KHR_texture_transform":{\r
+ "offset":[\r
+ 0.00678020436,\r
+ 0.00298196077\r
+ ],\r
+ "scale":[\r
+ 0.000238270484,\r
+ 0.000242341906\r
+ ]\r
+ }\r
+ }\r
+ },\r
+ "metallicRoughnessTexture":{\r
+ "index":1,\r
+ "texCoord":0,\r
+ "extensions":{\r
+ "KHR_texture_transform":{\r
+ "offset":[\r
+ 0.00678020436,\r
+ 0.00298196077\r
+ ],\r
+ "scale":[\r
+ 0.000238270484,\r
+ 0.000242341906\r
+ ]\r
+ }\r
+ }\r
+ }\r
+ },\r
+ "normalTexture":{\r
+ "index":2,\r
+ "texCoord":0,\r
+ "extensions":{\r
+ "KHR_texture_transform":{\r
+ "offset":[\r
+ 0.00678020436,\r
+ 0.00298196077\r
+ ],\r
+ "scale":[\r
+ 0.000238270484,\r
+ 0.000242341906\r
+ ]\r
+ }\r
+ }\r
+ }\r
+ }\r
+ ],\r
+ "meshes":[\r
+ {\r
+ "primitives":[\r
+ {\r
+ "attributes":{\r
+ "TEXCOORD_0":0,\r
+ "NORMAL":1,\r
+ "TANGENT":2,\r
+ "POSITION":3\r
+ },\r
+ "mode":4,\r
+ "indices":4,\r
+ "material":0\r
+ }\r
+ ]\r
+ }\r
+ ],\r
+ "nodes":[\r
+ {\r
+ "mesh":0,\r
+ "translation":[\r
+ -0.0212809108,\r
+ -4.77385511e-05,\r
+ -0.0138090011\r
+ ],\r
+ "scale":[\r
+ 3.839089e-06,\r
+ 3.839089e-06,\r
+ 3.839089e-06\r
+ ]\r
+ }\r
+ ],\r
+ "scenes":[\r
+ {\r
+ "nodes":[\r
+ 0\r
+ ]\r
+ }\r
+ ],\r
+ "scene":0\r
+}\r
--- /dev/null
+{
+ "buffers": [
+ {
+ "uri": "CesiumMilkTruckQuantized.bin",
+ "byteLength": 93032
+ }
+ ],
+ "asset": {
+ "version": "2.0",
+ "generator": "gltfpack 0.18"
+ },
+ "extensionsUsed": [
+ "KHR_mesh_quantization",
+ "KHR_texture_transform"
+ ],
+ "extensionsRequired": [
+ "KHR_mesh_quantization"
+ ],
+ "bufferViews": [
+ {
+ "buffer": 0,
+ "byteOffset": 0,
+ "byteLength": 31328,
+ "byteStride": 8,
+ "target": 34962
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 31328,
+ "byteLength": 31328,
+ "byteStride": 8,
+ "target": 34962
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 62656,
+ "byteLength": 12460,
+ "byteStride": 4,
+ "target": 34962
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 75116,
+ "byteLength": 17136,
+ "target": 34963
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 92252,
+ "byteLength": 156
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 92408,
+ "byteLength": 624
+ }
+ ],
+ "accessors": [
+ {
+ "bufferView": 0,
+ "byteOffset": 0,
+ "componentType": 5123,
+ "count": 786,
+ "type": "VEC3",
+ "normalized": true,
+ "min": [
+ 105,
+ 18,
+ 113
+ ],
+ "max": [
+ 150,
+ 129,
+ 158
+ ]
+ },
+ {
+ "bufferView": 1,
+ "byteOffset": 0,
+ "componentType": 5122,
+ "count": 786,
+ "type": "VEC3",
+ "normalized": true
+ },
+ {
+ "bufferView": 2,
+ "byteOffset": 0,
+ "componentType": 5123,
+ "count": 786,
+ "type": "VEC2",
+ "normalized": true
+ },
+ {
+ "bufferView": 3,
+ "byteOffset": 0,
+ "componentType": 5123,
+ "count": 2304,
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 0,
+ "byteOffset": 6288,
+ "componentType": 5123,
+ "count": 2329,
+ "type": "VEC3",
+ "normalized": true,
+ "min": [
+ 0,
+ 0,
+ 0
+ ],
+ "max": [
+ 255,
+ 146,
+ 121
+ ]
+ },
+ {
+ "bufferView": 1,
+ "byteOffset": 6288,
+ "componentType": 5122,
+ "count": 2329,
+ "type": "VEC3",
+ "normalized": true
+ },
+ {
+ "bufferView": 2,
+ "byteOffset": 3144,
+ "componentType": 5123,
+ "count": 2329,
+ "type": "VEC2",
+ "normalized": true
+ },
+ {
+ "bufferView": 3,
+ "byteOffset": 4608,
+ "componentType": 5123,
+ "count": 5232,
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 0,
+ "byteOffset": 24920,
+ "componentType": 5123,
+ "count": 151,
+ "type": "VEC3",
+ "normalized": true,
+ "min": [
+ 139,
+ 0,
+ 12
+ ],
+ "max": [
+ 211,
+ 146,
+ 50
+ ]
+ },
+ {
+ "bufferView": 1,
+ "byteOffset": 24920,
+ "componentType": 5122,
+ "count": 151,
+ "type": "VEC3",
+ "normalized": true
+ },
+ {
+ "bufferView": 3,
+ "byteOffset": 15072,
+ "componentType": 5123,
+ "count": 168,
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 0,
+ "byteOffset": 26128,
+ "componentType": 5123,
+ "count": 650,
+ "type": "VEC3",
+ "normalized": true,
+ "min": [
+ 137,
+ 15,
+ 10
+ ],
+ "max": [
+ 212,
+ 131,
+ 52
+ ]
+ },
+ {
+ "bufferView": 1,
+ "byteOffset": 26128,
+ "componentType": 5122,
+ "count": 650,
+ "type": "VEC3",
+ "normalized": true
+ },
+ {
+ "bufferView": 3,
+ "byteOffset": 15408,
+ "componentType": 5123,
+ "count": 864,
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 0,
+ "componentType": 5126,
+ "count": 39,
+ "type": "SCALAR",
+ "min": [
+ 0
+ ],
+ "max": [
+ 1.26666677
+ ]
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 0,
+ "componentType": 5122,
+ "count": 39,
+ "type": "VEC4",
+ "normalized": true
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 312,
+ "componentType": 5122,
+ "count": 39,
+ "type": "VEC4",
+ "normalized": true
+ }
+ ],
+ "images": [
+ {
+ "uri": "CesiumMilkTruck.jpg"
+ }
+ ],
+ "textures": [
+ {
+ "source": 0
+ },
+ {
+ "source": 0
+ }
+ ],
+ "materials": [
+ {
+ "name": "wheels",
+ "pbrMetallicRoughness": {
+ "baseColorTexture": {
+ "index": 0,
+ "extensions": {
+ "KHR_texture_transform": {
+ "offset": [
+ 0.605093002,
+ 0.00905001163
+ ],
+ "scale": [
+ 99.8609467,
+ 251.995087
+ ]
+ }
+ }
+ },
+ "metallicFactor": 0
+ }
+ },
+ {
+ "name": "truck",
+ "pbrMetallicRoughness": {
+ "baseColorTexture": {
+ "index": 1,
+ "extensions": {
+ "KHR_texture_transform": {
+ "offset": [
+ 0.00295638992,
+ 0.0156720281
+ ],
+ "scale": [
+ 229.629913,
+ 252.264313
+ ]
+ }
+ }
+ },
+ "metallicFactor": 0
+ }
+ },
+ {
+ "name": "glass",
+ "pbrMetallicRoughness": {
+ "baseColorFactor": [
+ 0,
+ 0.0405062996,
+ 0.0212407,
+ 1
+ ],
+ "metallicFactor": 0
+ }
+ },
+ {
+ "name": "window_trim",
+ "pbrMetallicRoughness": {
+ "baseColorFactor": [
+ 0.064000003,
+ 0.064000003,
+ 0.064000003,
+ 1
+ ],
+ "metallicFactor": 0
+ }
+ }
+ ],
+ "meshes": [
+ {
+ "primitives": [
+ {
+ "attributes": {
+ "POSITION": 0,
+ "NORMAL": 1,
+ "TEXCOORD_0": 2
+ },
+ "indices": 3,
+ "material": 0
+ }
+ ]
+ },
+ {
+ "primitives": [
+ {
+ "attributes": {
+ "POSITION": 4,
+ "NORMAL": 5,
+ "TEXCOORD_0": 6
+ },
+ "indices": 7,
+ "material": 1
+ },
+ {
+ "attributes": {
+ "POSITION": 8,
+ "NORMAL": 9
+ },
+ "indices": 10,
+ "material": 2
+ },
+ {
+ "attributes": {
+ "POSITION": 11,
+ "NORMAL": 12
+ },
+ "indices": 13,
+ "material": 3
+ }
+ ]
+ }
+ ],
+ "animations": [
+ {
+ "name": "Wheels",
+ "samplers": [
+ {
+ "input": 14,
+ "output": 15
+ },
+ {
+ "input": 14,
+ "output": 16
+ }
+ ],
+ "channels": [
+ {
+ "sampler": 0,
+ "target": {
+ "node": 3,
+ "path": "rotation"
+ }
+ },
+ {
+ "sampler": 1,
+ "target": {
+ "node": 5,
+ "path": "rotation"
+ }
+ }
+ ]
+ }
+ ],
+ "nodes": [
+ {
+ "mesh": 0,
+ "translation": [
+ -2.43091011,
+ -1.39600003,
+ -2.5843699
+ ],
+ "scale": [
+ 1251.30994,
+ 1251.30994,
+ 1251.30994
+ ]
+ },
+ {
+ "mesh": 0,
+ "translation": [
+ -2.43091011,
+ -1.39600003,
+ -2.5843699
+ ],
+ "scale": [
+ 1251.30994,
+ 1251.30994,
+ 1251.30994
+ ]
+ },
+ {
+ "mesh": 1,
+ "translation": [
+ -2.43091011,
+ -1.39600003,
+ -2.5843699
+ ],
+ "scale": [
+ 1251.30994,
+ 1251.30994,
+ 1251.30994
+ ]
+ },
+ {
+ "name": "Wheels",
+ "rotation": [
+ 0,
+ 0.0884858891,
+ 0,
+ -0.996077418
+ ],
+ "children": [
+ 0
+ ]
+ },
+ {
+ "name": "Node",
+ "translation": [
+ 1.43267,
+ 0,
+ -0.427722007
+ ],
+ "children": [
+ 3
+ ]
+ },
+ {
+ "name": "Wheels.001",
+ "rotation": [
+ 0,
+ 0.0884858891,
+ 0,
+ -0.996077418
+ ],
+ "children": [
+ 1
+ ]
+ },
+ {
+ "name": "Node.001",
+ "translation": [
+ -1.35232997,
+ 0,
+ -0.427722007
+ ],
+ "children": [
+ 5
+ ]
+ },
+ {
+ "name": "Cesium_Milk_Truck",
+ "children": [
+ 4,
+ 6,
+ 2
+ ]
+ },
+ {
+ "name": "Yup2Zup",
+ "rotation": [
+ 0.49999997,
+ -0.5,
+ 0.5,
+ 0.49999997
+ ],
+ "children": [
+ 7
+ ]
+ }
+ ],
+ "scenes": [
+ {
+ "name": "Scene",
+ "nodes": [
+ 8
+ ]
+ }
+ ],
+ "scene": 0
+}
--- /dev/null
+{
+ "buffers": [
+ {
+ "uri": "MorphPrimitivesTestQuantized.bin",
+ "byteLength": 912
+ }
+ ],
+ "asset": {
+ "version": "2.0",
+ "generator": "gltfpack 0.18",
+ "extras": {
+ "title": "multiple_primitives",
+ "author": "ft-lab",
+ "license": "CC BY-4.0 (https://creativecommons.org/licenses/by/4.0/)"
+ }
+ },
+ "extensionsUsed": [
+ "KHR_mesh_quantization",
+ "KHR_texture_transform"
+ ],
+ "extensionsRequired": [
+ "KHR_mesh_quantization"
+ ],
+ "bufferViews": [
+ {
+ "buffer": 0,
+ "byteOffset": 0,
+ "byteLength": 240,
+ "byteStride": 8,
+ "target": 34962
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 240,
+ "byteLength": 240,
+ "byteStride": 8,
+ "target": 34962
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 480,
+ "byteLength": 120,
+ "byteStride": 4,
+ "target": 34962
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 600,
+ "byteLength": 120,
+ "byteStride": 4,
+ "target": 34962
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 720,
+ "byteLength": 192,
+ "target": 34963
+ }
+ ],
+ "accessors": [
+ {
+ "bufferView": 0,
+ "byteOffset": 0,
+ "componentType": 5122,
+ "count": 21,
+ "type": "VEC3",
+ "normalized": true
+ },
+ {
+ "bufferView": 1,
+ "byteOffset": 0,
+ "componentType": 5123,
+ "count": 21,
+ "type": "VEC3",
+ "min": [
+ 0,
+ 0,
+ 0
+ ],
+ "max": [
+ 1,
+ 0,
+ 1
+ ]
+ },
+ {
+ "bufferView": 2,
+ "byteOffset": 0,
+ "componentType": 5123,
+ "count": 21,
+ "type": "VEC2",
+ "normalized": true
+ },
+ {
+ "bufferView": 3,
+ "byteOffset": 0,
+ "componentType": 5120,
+ "count": 21,
+ "type": "VEC3",
+ "min": [
+ 0,
+ 0,
+ 0
+ ],
+ "max": [
+ 0,
+ 0,
+ 0
+ ]
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 0,
+ "componentType": 5123,
+ "count": 72,
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 1,
+ "byteOffset": 168,
+ "componentType": 5123,
+ "count": 9,
+ "type": "VEC3",
+ "min": [
+ 1,
+ 0,
+ 0
+ ],
+ "max": [
+ 1,
+ 0,
+ 1
+ ]
+ },
+ {
+ "bufferView": 0,
+ "byteOffset": 168,
+ "componentType": 5122,
+ "count": 9,
+ "type": "VEC3",
+ "normalized": true
+ },
+ {
+ "bufferView": 2,
+ "byteOffset": 84,
+ "componentType": 5123,
+ "count": 9,
+ "type": "VEC2",
+ "normalized": true
+ },
+ {
+ "bufferView": 3,
+ "byteOffset": 84,
+ "componentType": 5120,
+ "count": 9,
+ "type": "VEC3",
+ "min": [
+ 0,
+ 0,
+ 0
+ ],
+ "max": [
+ 0,
+ 0,
+ 0
+ ]
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 144,
+ "componentType": 5123,
+ "count": 24,
+ "type": "SCALAR"
+ }
+ ],
+ "samplers": [
+ {
+ "minFilter": 9729
+ }
+ ],
+ "images": [
+ {
+ "uri": "uv_texture.jpg"
+ }
+ ],
+ "textures": [
+ {
+ "sampler": 0,
+ "source": 0
+ }
+ ],
+ "materials": [
+ {
+ "name": "red",
+ "pbrMetallicRoughness": {
+ "baseColorFactor": [
+ 1,
+ 0,
+ 0,
+ 1
+ ],
+ "baseColorTexture": {
+ "index": 0,
+ "extensions": {
+ "KHR_texture_transform": {
+ "offset": [
+ 0,
+ 0
+ ],
+ "scale": [
+ 65535,
+ 65535
+ ]
+ }
+ }
+ },
+ "metallicFactor": 0
+ }
+ },
+ {
+ "name": "green",
+ "pbrMetallicRoughness": {
+ "baseColorFactor": [
+ 0,
+ 1,
+ 0,
+ 1
+ ],
+ "baseColorTexture": {
+ "index": 0,
+ "extensions": {
+ "KHR_texture_transform": {
+ "offset": [
+ 0,
+ 0
+ ],
+ "scale": [
+ 32767.5,
+ 32767.5
+ ]
+ }
+ }
+ },
+ "metallicFactor": 0
+ }
+ }
+ ],
+ "meshes": [
+ {
+ "primitives": [
+ {
+ "attributes": {
+ "NORMAL": 0,
+ "POSITION": 1,
+ "TEXCOORD_0": 2
+ },
+ "targets": [
+ {
+ "POSITION": 3
+ }
+ ],
+ "indices": 4,
+ "material": 0
+ },
+ {
+ "attributes": {
+ "POSITION": 5,
+ "NORMAL": 6,
+ "TEXCOORD_0": 7
+ },
+ "targets": [
+ {
+ "POSITION": 8
+ }
+ ],
+ "indices": 9,
+ "material": 1
+ }
+ ],
+ "weights": [
+ 0.5
+ ]
+ }
+ ],
+ "nodes": [
+ {
+ "mesh": 0,
+ "translation": [
+ -0.5,
+ -0.400000006,
+ -0.5
+ ],
+ "scale": [
+ 1,
+ 1,
+ 1
+ ]
+ },
+ {
+ "name": "ルートパート",
+ "children": [
+ 2
+ ]
+ },
+ {
+ "name": "mesh",
+ "children": [
+ 0
+ ]
+ }
+ ],
+ "scenes": [
+ {
+ "name": "Scene",
+ "nodes": [
+ 1
+ ]
+ }
+ ],
+ "scene": 0
+}
--- /dev/null
+{\r
+ "scene" : 0,\r
+ "scenes" : [\r
+ {\r
+ "nodes" : [ 0, 1]\r
+ }\r
+ ],\r
+ "nodes" : [\r
+ {\r
+ "mesh" : 0\r
+ },\r
+ {\r
+ "mesh" : 0,\r
+ "translation" : [ 1.0, 0.0, 0.0 ]\r
+ }\r
+ ],\r
+\r
+ "meshes" : [\r
+ {\r
+ "primitives" : [ {\r
+ "attributes" : {\r
+ "POSITION" : 1,\r
+ "NORMAL" : 2\r
+ },\r
+ "indices" : 0\r
+ } ]\r
+ }\r
+ ],\r
+\r
+ "buffers" : [\r
+ {\r
+ "uri" : "UnsupportedExtension.bin",\r
+ "byteLength" : 80\r
+ }\r
+ ],\r
+ "bufferViews" : [\r
+ {\r
+ "buffer" : 0,\r
+ "byteOffset" : 0,\r
+ "byteLength" : 6,\r
+ "target" : 34963\r
+ },\r
+ {\r
+ "buffer" : 0,\r
+ "byteOffset" : 8,\r
+ "byteLength" : 72,\r
+ "byteStride" : 12,\r
+ "target" : 34962\r
+ }\r
+ ],\r
+ "accessors" : [\r
+ {\r
+ "bufferView" : 0,\r
+ "byteOffset" : 0,\r
+ "componentType" : 5123,\r
+ "count" : 3,\r
+ "type" : "SCALAR",\r
+ "max" : [ 2 ],\r
+ "min" : [ 0 ]\r
+ },\r
+ {\r
+ "bufferView" : 1,\r
+ "byteOffset" : 0,\r
+ "componentType" : 5126,\r
+ "count" : 3,\r
+ "type" : "VEC3",\r
+ "max" : [ 1.0, 1.0, 0.0 ],\r
+ "min" : [ 0.0, 0.0, 0.0 ]\r
+ },\r
+ {\r
+ "bufferView" : 1,\r
+ "byteOffset" : 36,\r
+ "componentType" : 5126,\r
+ "count" : 3,\r
+ "type" : "VEC3",\r
+ "max" : [ 0.0, 0.0, 1.0 ],\r
+ "min" : [ 0.0, 0.0, 1.0 ]\r
+ }\r
+ ],\r
+ "asset" : {\r
+ "version" : "2.0"\r
+ },\r
+ "extensionsUsed": [\r
+ "KHR_invalid_extension"\r
+ ],\r
+ "extensionsRequired": [\r
+ "KHR_invalid_extension"\r
+ ]\r
+}\r
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
// Enable debug log for test coverage
#define DEBUG_ENABLED 1
-#include "dali-scene3d/internal/loader/gltf2-asset.h"
#include <dali-test-suite-utils.h>
#include <string>
+#include "dali-scene3d/internal/loader/gltf2-asset.h"
using namespace Dali;
using namespace Dali::Scene3D::Loader;
}
#define FROM_STRING_HELPER(x) FromString(#x, strlen(#x))
+#define TARGET_FROM_STRING_HELPER(x) TargetFromString(#x, strlen(#x))
+#define HASH_FROM_STRING_HELPER(x) HashFromString(#x, strlen(#x))
-#define STRING_CHECK(type, x) DALI_TEST_EQUAL(gltf2::type:: FROM_STRING_HELPER(x), gltf2::type::x)
+#define STRING_CHECK(type, x) DALI_TEST_EQUAL(gltf2::type::FROM_STRING_HELPER(x), gltf2::type::x)
+#define TARGET_STRING_CHECK(type, x) DALI_TEST_EQUAL(gltf2::type::TARGET_FROM_STRING_HELPER(x), gltf2::type::x)
+#define HASH_STRING_CHECK(type, x, y, z) DALI_TEST_EQUAL(gltf2::type::HASH_FROM_STRING_HELPER(x), gltf2::type::ToHash(gltf2::type::y, true, z))
int UtcDaliGltf2AssetAccessorType(void)
{
int UtcDaliGltf2AssetAttribute(void)
{
- STRING_CHECK(Attribute, POSITION);
- STRING_CHECK(Attribute, NORMAL);
- STRING_CHECK(Attribute, TANGENT);
- STRING_CHECK(Attribute, TEXCOORD_0);
- STRING_CHECK(Attribute, TEXCOORD_1);
- STRING_CHECK(Attribute, COLOR_0);
- STRING_CHECK(Attribute, JOINTS_0);
- STRING_CHECK(Attribute, WEIGHTS_0);
- DALI_TEST_EQUAL(gltf2::Attribute::FROM_STRING_HELPER(VISCOSITY), gltf2::Attribute::INVALID);
+ TARGET_STRING_CHECK(Attribute, POSITION);
+ TARGET_STRING_CHECK(Attribute, NORMAL);
+ TARGET_STRING_CHECK(Attribute, TANGENT);
+ HASH_STRING_CHECK(Attribute, TEXCOORD_0, TEXCOORD_N, 0);
+ HASH_STRING_CHECK(Attribute, TEXCOORD_1, TEXCOORD_N, 1);
+ HASH_STRING_CHECK(Attribute, COLOR_0, COLOR_N, 0);
+ HASH_STRING_CHECK(Attribute, COLOR_1, COLOR_N, 1);
+ HASH_STRING_CHECK(Attribute, JOINTS_0, JOINTS_N, 0);
+ HASH_STRING_CHECK(Attribute, JOINTS_1, JOINTS_N, 1);
+ HASH_STRING_CHECK(Attribute, JOINTS_2, JOINTS_N, 2);
+ HASH_STRING_CHECK(Attribute, WEIGHTS_0, WEIGHTS_N, 0);
+ HASH_STRING_CHECK(Attribute, WEIGHTS_1, WEIGHTS_N, 1);
+ HASH_STRING_CHECK(Attribute, WEIGHTS_2, WEIGHTS_N, 2);
+ DALI_TEST_EQUAL(gltf2::Attribute::TARGET_FROM_STRING_HELPER(VISCOSITY), gltf2::Attribute::INVALID);
END_TEST;
}
std::vector<gltf2::BufferView> bufferViews;
- gltf2::Accessor::Sparse sparse{ 256u };
- sparse.mIndices.mBufferView = gltf2::Ref<gltf2::BufferView>(bufferViews, 5u);
+ gltf2::Accessor::Sparse sparse{256u};
+ sparse.mIndices.mBufferView = gltf2::Ref<gltf2::BufferView>(bufferViews, 5u);
sparse.mIndices.mComponentType = gltf2::Component::FLOAT;
- sparse.mValues.mBufferView = gltf2::Ref<gltf2::BufferView>(bufferViews, 284u);
- sparse.mValues.mByteOffset = 16532;
+ sparse.mValues.mBufferView = gltf2::Ref<gltf2::BufferView>(bufferViews, 284u);
+ sparse.mValues.mByteOffset = 16532;
acc.SetSparse(sparse);
DALI_TEST_EQUAL(acc.mSparse->mCount, sparse.mCount);
END_TEST;
}
-
{
struct Context
{
- ResourceBundle::PathProvider pathProvider = [](ResourceType::Value type)
- {
+ ResourceBundle::PathProvider pathProvider = [](ResourceType::Value type) {
return TEST_RESOURCE_DIR "/";
};
} // namespace
-int UtcDaliGltfLoaderFailedToLoad(void)
+int UtcDaliGltfLoaderFailedToLoad1(void)
{
Context ctx;
END_TEST;
}
+int UtcDaliGltfLoaderFailedToLoad2(void)
+{
+ Context ctx;
+
+ try
+ {
+ DALI_TEST_EQUAL(ctx.loader.LoadModel(TEST_RESOURCE_DIR "/UnsupportedExtension.gltf", ctx.loadResult), false);
+ }
+ catch(...)
+ {
+ printf("Unsupported glTF extension required.\n");
+ }
+
+ DALI_TEST_EQUAL(0, ctx.scene.GetRoots().size());
+ DALI_TEST_EQUAL(0, ctx.scene.GetNodeCount());
+
+ DALI_TEST_EQUAL(0, ctx.resources.mEnvironmentMaps.size());
+ DALI_TEST_EQUAL(0, ctx.resources.mMaterials.size());
+ DALI_TEST_EQUAL(0, ctx.resources.mMeshes.size());
+ DALI_TEST_EQUAL(0, ctx.resources.mShaders.size());
+ DALI_TEST_EQUAL(0, ctx.resources.mSkeletons.size());
+
+ DALI_TEST_EQUAL(0, ctx.cameras.size());
+ DALI_TEST_EQUAL(0, ctx.lights.size());
+ DALI_TEST_EQUAL(0, ctx.animations.size());
+ DALI_TEST_EQUAL(0, ctx.animationGroups.size());
+
+ END_TEST;
+}
+
int UtcDaliGltfLoaderFailedToParse(void)
{
Context ctx;
auto& materials = ctx.resources.mMaterials;
DALI_TEST_EQUAL(2u, materials.size());
const MaterialDefinition materialGroundTruth[]{
- {
- nullptr,
- MaterialDefinition::ALBEDO | MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION |
- MaterialDefinition::NORMAL | MaterialDefinition::SPECULAR | MaterialDefinition::SPECULAR_COLOR |
- MaterialDefinition::GLTF_CHANNELS | (0x80 << MaterialDefinition::ALPHA_CUTOFF_SHIFT),
- 0,
- Color::WHITE,
- 1.f,
- 0.f,
- Vector4(1.000, 0.766, 0.336, 1.0),
- 1.f,
- 1.f,
- Vector3(0.2, 0.1, 0.0),
- 1.0f,
- 0.0f,
- 0.5f,
- Vector3(0, 0, 1),
- true,
- false,
- true,
- false,
- Scene3D::Material::AlphaModeType::MASK,
- true,
- true,
- true,
- {
- {
- MaterialDefinition::ALBEDO,
- {
- "AnimatedCube_BaseColor.png",
- SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
- ImageDimensions(256, 256),
- SamplingMode::BOX_THEN_NEAREST,
- },
- },
- {
- MaterialDefinition::NORMAL,
- {
- "AnimatedCube_BaseColor.png",
- SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
- ImageDimensions(256, 256),
- SamplingMode::BOX_THEN_NEAREST,
- },
- },
- {
- MaterialDefinition::OCCLUSION,
- {
- "AnimatedCube_BaseColor.png",
- SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
- ImageDimensions(256, 256),
- SamplingMode::BOX_THEN_NEAREST,
- },
- },
- {
- MaterialDefinition::EMISSIVE,
- {
- "AnimatedCube_BaseColor.png",
- SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
- ImageDimensions(256, 256),
- SamplingMode::BOX_THEN_NEAREST,
- },
- },
- {
- MaterialDefinition::SPECULAR,
- {
- "AnimatedCube_BaseColor.png",
- SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
- ImageDimensions(256, 256),
- SamplingMode::BOX_THEN_NEAREST,
- },
- },
- {
- MaterialDefinition::SPECULAR_COLOR,
- {
- "AnimatedCube_BaseColor.png",
- SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
- ImageDimensions(256, 256),
- SamplingMode::BOX_THEN_NEAREST,
- },
- },
- },
- nullptr
- },
+ {nullptr,
+ MaterialDefinition::ALBEDO | MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION |
+ MaterialDefinition::NORMAL | MaterialDefinition::SPECULAR | MaterialDefinition::SPECULAR_COLOR |
+ MaterialDefinition::GLTF_CHANNELS | (0x80 << MaterialDefinition::ALPHA_CUTOFF_SHIFT),
+ 0,
+ Color::WHITE,
+ 1.f,
+ 0.f,
+ Vector4(1.000, 0.766, 0.336, 1.0),
+ 1.f,
+ 1.f,
+ Vector3(0.2, 0.1, 0.0),
+ 1.0f,
+ 0.0f,
+ 0.5f,
+ Vector3(0, 0, 1),
+ true,
+ false,
+ true,
+ false,
+ Scene3D::Material::AlphaModeType::MASK,
+ true,
+ true,
+ true,
+ {
+ {
+ MaterialDefinition::ALBEDO,
+ {
+ "AnimatedCube_BaseColor.png",
+ SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
+ ImageDimensions(256, 256),
+ SamplingMode::BOX_THEN_NEAREST,
+ },
+ },
+ {
+ MaterialDefinition::NORMAL,
+ {
+ "AnimatedCube_BaseColor.png",
+ SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
+ ImageDimensions(256, 256),
+ SamplingMode::BOX_THEN_NEAREST,
+ },
+ },
+ {
+ MaterialDefinition::OCCLUSION,
+ {
+ "AnimatedCube_BaseColor.png",
+ SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
+ ImageDimensions(256, 256),
+ SamplingMode::BOX_THEN_NEAREST,
+ },
+ },
+ {
+ MaterialDefinition::EMISSIVE,
+ {
+ "AnimatedCube_BaseColor.png",
+ SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
+ ImageDimensions(256, 256),
+ SamplingMode::BOX_THEN_NEAREST,
+ },
+ },
+ {
+ MaterialDefinition::SPECULAR,
+ {
+ "AnimatedCube_BaseColor.png",
+ SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
+ ImageDimensions(256, 256),
+ SamplingMode::BOX_THEN_NEAREST,
+ },
+ },
+ {
+ MaterialDefinition::SPECULAR_COLOR,
+ {
+ "AnimatedCube_BaseColor.png",
+ SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
+ ImageDimensions(256, 256),
+ SamplingMode::BOX_THEN_NEAREST,
+ },
+ },
+ },
+ nullptr},
{
nullptr,
MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS |
using Blob = MeshDefinition::Blob;
using Accessor = MeshDefinition::Accessor;
- const MeshDefinition meshGroundTruth[]{
+ MeshDefinition meshGroundTruth[]{
{
nullptr,
0,
Accessor{Blob{0, 0}, {}},
Accessor{Blob{0, 0}, {}},
Accessor{Blob{0, 0}, {}},
- Accessor{Blob{0, 0}, {}},
- Accessor{Blob{0, 0}, {}},
},
{
nullptr,
Accessor{Blob{0, 0}, {}},
Accessor{Blob{0, 0}, {}},
Accessor{Blob{0, 0}, {}},
- Accessor{Blob{0, 0}, {}},
- Accessor{Blob{0, 0}, {}},
},
};
+ meshGroundTruth[0].mColors.push_back(Accessor{Blob{0, 0}, {}});
+ meshGroundTruth[0].mTexCoords.push_back(Accessor{Blob{0, 0}, {}});
+ meshGroundTruth[1].mColors.push_back(Accessor{Blob{0, 0}, {}});
+ meshGroundTruth[1].mTexCoords.push_back(Accessor{Blob{0, 0}, {}});
auto iMesh = meshes.begin();
for(auto& m : meshGroundTruth)
auto& md = iMesh->first;
DALI_TEST_EQUAL(md.mFlags, m.mFlags);
DALI_TEST_EQUAL(md.mPrimitiveType, m.mPrimitiveType);
- for(auto mp : {
- &MeshDefinition::mIndices,
- &MeshDefinition::mPositions,
- &MeshDefinition::mNormals,
- &MeshDefinition::mTexCoords,
- &MeshDefinition::mColors,
- &MeshDefinition::mTangents,
- &MeshDefinition::mJoints0,
- &MeshDefinition::mWeights0})
- {
- DALI_TEST_EQUAL((md.*mp).IsDefined(), (m.*mp).IsDefined());
- DALI_TEST_EQUAL((md.*mp).mBlob.IsDefined(), (m.*mp).mBlob.IsDefined());
- }
+
+ DALI_TEST_EQUAL((md.mIndices).IsDefined(), (m.mIndices).IsDefined());
+ DALI_TEST_EQUAL((md.mIndices).mBlob.IsDefined(), (m.mIndices).mBlob.IsDefined());
+
+ DALI_TEST_EQUAL((md.mPositions).IsDefined(), (m.mPositions).IsDefined());
+ DALI_TEST_EQUAL((md.mPositions).mBlob.IsDefined(), (m.mPositions).mBlob.IsDefined());
+
+ DALI_TEST_EQUAL((md.mNormals).IsDefined(), (m.mNormals).IsDefined());
+ DALI_TEST_EQUAL((md.mNormals).mBlob.IsDefined(), (m.mNormals).mBlob.IsDefined());
+
+ DALI_TEST_EQUAL((md.mTangents).IsDefined(), (m.mTangents).IsDefined());
+ DALI_TEST_EQUAL((md.mTangents).mBlob.IsDefined(), (m.mTangents).mBlob.IsDefined());
+
+ DALI_TEST_EQUAL(md.mTexCoords.empty(), m.mTexCoords.empty());
+ DALI_TEST_EQUAL(md.mColors.empty(), m.mColors.empty());
+
+ DALI_TEST_EQUAL(md.mJoints.empty(), (m.mJoints.empty()));
+ DALI_TEST_EQUAL(md.mWeights.empty(), (m.mWeights.empty()));
DALI_TEST_EQUAL(md.mBlendShapeHeader.IsDefined(), m.mBlendShapeHeader.IsDefined());
int UtcDaliGltfLoaderSuccess2(void)
{
- Context ctx;
+ Context ctx;
ctx.loader.LoadModel(TEST_RESOURCE_DIR "/AnimatedCubeStride.gltf", ctx.loadResult);
TestApplication app;
const std::string resourcePath = TEST_RESOURCE_DIR "/";
- auto pathProvider = [resourcePath](ResourceType::Value)
- {
+ auto pathProvider = [resourcePath](ResourceType::Value) {
return resourcePath;
};
"MRendererTest",
"SimpleSparseAccessor",
"AnimatedCube",
+ /**
+ * 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
+ */
+ "AvocadoQuantized",
+ /**
+ * For the AnimatedMorphCube glTF file and its Assets
+ * Donated by Microsoft for glTF testing
+ * Take from https://github.com/KhronosGroup/glTF-Sample-Models/blob/master/2.0/AnimatedMorphCube/glTF-Quantized
+ */
+ "AnimatedMorphCubeQuantized",
+ /**
+ * For the MorphPrimitivesTest glTF file and its Assets
+ * Created by @ft-lab
+ * Licensed under the terms of the CC BY 4.0 license: https://creativecommons.org/licenses/by/4.0/
+ * Take from https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/MorphPrimitivesTest/glTF
+ * Modified using gltfpack 0.18.
+ */
+ "MorphPrimitivesTestQuantized",
+ /**
+ * For the CesiumMilkTruck glTF file and its Assets
+ * Donated by Cesium for glTF testing
+ * Licensed under the terms of the CC BY 4.0 license: http://creativecommons.org/licenses/by/4.0/
+ * Take from https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/CesiumMilkTruck/glTF
+ * Modified using gltfpack 0.18.
+ */
+ "CesiumMilkTruckQuantized",
})
{
Context ctx;
int UtcDaliGltfLoaderMRendererTest(void)
{
Context ctx;
- auto& resources = ctx.resources;
+ auto& resources = ctx.resources;
ctx.loader.LoadModel(TEST_RESOURCE_DIR "/MRendererTest.gltf", ctx.loadResult);
DALI_TEST_EQUAL(scene.GetNodeCount(), 1u);
Scene3D::Loader::ShaderManagerPtr shaderManager = new Scene3D::Loader::ShaderManager();
- ViewProjection viewProjection;
- Transforms xforms{
+ ViewProjection viewProjection;
+ Transforms xforms{
MatrixStack{},
viewProjection};
NodeDefinition::CreateParams nodeParams{
int UtcDaliGltfLoaderAnimationLoadingTest(void)
{
TestApplication app;
- Context ctx;
+ Context ctx;
auto& resources = ctx.resources;
DALI_TEST_EQUAL(roots.size(), 1u);
Scene3D::Loader::ShaderManagerPtr shaderManager = new Scene3D::Loader::ShaderManager();
- ViewProjection viewProjection;
- Transforms xforms{
+ ViewProjection viewProjection;
+ Transforms xforms{
MatrixStack{},
viewProjection};
NodeDefinition::CreateParams nodeParams{
DALI_TEST_EQUAL(roots.size(), 1u);
Scene3D::Loader::ShaderManagerPtr shaderManager = new Scene3D::Loader::ShaderManager();
- ViewProjection viewProjection;
- Transforms xforms{
+ ViewProjection viewProjection;
+ Transforms xforms{
MatrixStack{},
viewProjection};
NodeDefinition::CreateParams nodeParams{
DALI_TEST_EQUAL(roots.size(), 1u);
Scene3D::Loader::ShaderManagerPtr shaderManager = new Scene3D::Loader::ShaderManager();
- ViewProjection viewProjection;
- Transforms xforms{
+ ViewProjection viewProjection;
+ Transforms xforms{
MatrixStack{},
viewProjection};
NodeDefinition::CreateParams nodeParams{
END_TEST;
}
+
+int UtcDaliGltfLoaderQuantizedMesh(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());
+
+ auto& roots = scene.GetRoots();
+ DALI_TEST_EQUAL(roots.size(), 1u);
+
+ Scene3D::Loader::ShaderManagerPtr shaderManager = new Scene3D::Loader::ShaderManager();
+ ViewProjection viewProjection;
+ Transforms xforms{
+ MatrixStack{},
+ viewProjection};
+ NodeDefinition::CreateParams nodeParams{
+ resources,
+ xforms,
+ shaderManager,
+ };
+
+ Customization::Choices choices;
+
+ TestApplication app;
+
+ Actor root = Actor::New();
+ SetActorCentered(root);
+ for(auto iRoot : roots)
+ {
+ auto resourceRefs = resources.CreateRefCounter();
+ scene.CountResourceRefs(iRoot, choices, resourceRefs);
+ resources.mReferenceCounts = std::move(resourceRefs);
+ resources.CountEnvironmentReferences();
+ resources.LoadResources(ctx.pathProvider);
+ if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
+ {
+ scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
+ scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
+ root.Add(actor);
+ }
+ }
+
+ auto& meshes = ctx.resources.mMeshes;
+ DALI_TEST_EQUAL(1u, meshes.size());
+
+ auto& md = meshes[0u].first;
+
+ DALI_TEST_EQUAL(MeshDefinition::Flags::U16_POSITION | MeshDefinition::Flags::S8_NORMAL | MeshDefinition::Flags::S8_TANGENT | MeshDefinition::Flags::U16_TEXCOORD, md.mFlags);
+
+ DALI_TEST_EQUAL(true, md.mPositions.IsDefined());
+ DALI_TEST_EQUAL(false, md.mPositions.mNormalized);
+ DALI_TEST_EQUAL(sizeof(uint16_t) * 3, md.mPositions.mBlob.mElementSizeHint);
+ DALI_TEST_EQUAL(true, md.mPositions.mBlob.IsDefined());
+ DALI_TEST_EQUAL(2436, md.mPositions.mBlob.mLength);
+ DALI_TEST_EQUAL(3u, md.mPositions.mBlob.mMin.size());
+ DALI_TEST_EQUAL(0.0f, md.mPositions.mBlob.mMin[0]);
+ DALI_TEST_EQUAL(0.0f, md.mPositions.mBlob.mMin[1]);
+ DALI_TEST_EQUAL(0.0f, md.mPositions.mBlob.mMin[2]);
+ DALI_TEST_EQUAL(3u, md.mPositions.mBlob.mMax.size());
+ DALI_TEST_EQUAL(11086.0f, md.mPositions.mBlob.mMax[0]);
+ DALI_TEST_EQUAL(16383.0f, md.mPositions.mBlob.mMax[1]);
+ DALI_TEST_EQUAL(7194.0f, md.mPositions.mBlob.mMax[2]);
+
+ DALI_TEST_EQUAL(true, md.mNormals.IsDefined());
+ DALI_TEST_EQUAL(true, md.mNormals.mNormalized);
+ DALI_TEST_EQUAL(sizeof(int8_t) * 3, md.mNormals.mBlob.mElementSizeHint);
+ DALI_TEST_EQUAL(true, md.mNormals.mBlob.IsDefined());
+ DALI_TEST_EQUAL(1218, md.mNormals.mBlob.mLength);
+ DALI_TEST_EQUAL(0u, md.mNormals.mBlob.mMin.size());
+ DALI_TEST_EQUAL(0u, md.mNormals.mBlob.mMax.size());
+
+ DALI_TEST_EQUAL(true, md.mTangents.IsDefined());
+ DALI_TEST_EQUAL(true, md.mTangents.mNormalized);
+ DALI_TEST_EQUAL(Property::VECTOR4, md.mTangentType);
+ DALI_TEST_EQUAL(sizeof(int8_t) * 4, md.mTangents.mBlob.mElementSizeHint);
+ DALI_TEST_EQUAL(true, md.mTangents.mBlob.IsDefined());
+ DALI_TEST_EQUAL(1624, md.mTangents.mBlob.mLength);
+ DALI_TEST_EQUAL(0u, md.mTangents.mBlob.mMin.size());
+ DALI_TEST_EQUAL(0u, md.mTangents.mBlob.mMax.size());
+
+ DALI_TEST_EQUAL(false, md.mTexCoords.empty());
+ DALI_TEST_EQUAL(true, md.mTexCoords[0].IsDefined());
+ DALI_TEST_EQUAL(false, md.mTexCoords[0].mNormalized);
+ DALI_TEST_EQUAL(sizeof(uint16_t) * 2, md.mTexCoords[0].mBlob.mElementSizeHint);
+ DALI_TEST_EQUAL(true, md.mTexCoords[0].mBlob.IsDefined());
+ DALI_TEST_EQUAL(1624, md.mTexCoords[0].mBlob.mLength);
+ DALI_TEST_EQUAL(0u, md.mTexCoords[0].mBlob.mMin.size());
+ DALI_TEST_EQUAL(0u, md.mTexCoords[0].mBlob.mMax.size());
+
+ END_TEST;
+}
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <vector>
-#include <dali-scene3d/public-api/loader/mesh-definition.h>
#include <dali-scene3d/public-api/loader/buffer-definition.h>
+#include <dali-scene3d/public-api/loader/mesh-definition.h>
#include <dali-test-suite-utils.h>
using namespace Dali;
{
using Container = std::vector<float>;
- Container buffer = { 4.0f, 6.0f, 8.0f, 10.0f, 12.0f };
- Container minValues = { 5.0f };
- Container maxValues = { 10.0f };
- Container result = {5.0f, 6.0f, 8.0f, 10.0f, 10.0f};
+ Container buffer = {4.0f, 6.0f, 8.0f, 10.0f, 12.0f};
+ Container minValues = {5.0f};
+ Container maxValues = {10.0f};
+ Container result = {5.0f, 6.0f, 8.0f, 10.0f, 10.0f};
MeshDefinition::Blob::ApplyMinMax(minValues, maxValues, 5, buffer.data());
- for( auto i = 0u; i < result.size(); ++i)
+ for(auto i = 0u; i < result.size(); ++i)
{
DALI_TEST_EQUALS(buffer[i], result[i], TEST_LOCATION);
}
{
using Container = std::vector<float>;
- Container buffer = { 4.0f, 6.0f, 8.0f, 10.0f, 12.0f };
- Container minValues = { 5.0f };
+ Container buffer = {4.0f, 6.0f, 8.0f, 10.0f, 12.0f};
+ Container minValues = {5.0f};
Container maxValues = {};
- Container result = {5.0f, 6.0f, 8.0f, 10.0f, 12.0f};
+ Container result = {5.0f, 6.0f, 8.0f, 10.0f, 12.0f};
MeshDefinition::Blob::ApplyMinMax(minValues, maxValues, 5, buffer.data());
- for( auto i = 0u; i < result.size(); ++i)
+ for(auto i = 0u; i < result.size(); ++i)
{
DALI_TEST_EQUALS(buffer[i], result[i], TEST_LOCATION);
}
{
using Container = std::vector<float>;
- Container buffer = { 4.0f, 6.0f, 8.0f, 10.0f, 12.0f };
- Container minValues = { };
- Container maxValues = { 10.0f };
- Container result = {4.0f, 6.0f, 8.0f, 10.0f, 10.0f};
+ Container buffer = {4.0f, 6.0f, 8.0f, 10.0f, 12.0f};
+ Container minValues = {};
+ Container maxValues = {10.0f};
+ Container result = {4.0f, 6.0f, 8.0f, 10.0f, 10.0f};
MeshDefinition::Blob::ApplyMinMax(minValues, maxValues, 5, buffer.data());
- for( auto i = 0u; i < result.size(); ++i)
+ for(auto i = 0u; i < result.size(); ++i)
{
DALI_TEST_EQUALS(buffer[i], result[i], TEST_LOCATION);
}
{
using Container = std::vector<float>;
- Container buffer = { 4.0f, 6.0f, 8.0f, 10.0f, 12.0f };
+ Container buffer = {4.0f, 6.0f, 8.0f, 10.0f, 12.0f};
Container minValues;
Container maxValues;
Container result = {4.0f, 6.0f, 8.0f, 10.0f, 12.0f};
MeshDefinition::Blob::ApplyMinMax(minValues, maxValues, 5, buffer.data());
- for( auto i = 0u; i < result.size(); ++i)
+ for(auto i = 0u; i < result.size(); ++i)
{
DALI_TEST_EQUALS(buffer[i], result[i], TEST_LOCATION);
}
meshDefinition.mPositions =
MeshDefinition::Accessor{
std::move(MeshDefinition::Blob{0, 12, 0, (uint16_t)12, std::vector<float>(), std::vector<float>()}), std::move(sparseBlob), 0};
- meshDefinition.mJoints0 =
+ meshDefinition.mJoints.push_back(
MeshDefinition::Accessor{
- std::move(MeshDefinition::Blob{0, 16, 0, (uint16_t)16, std::vector<float>(), std::vector<float>()}), std::move(sparseBlob), 0};
- meshDefinition.mWeights0 =
+ std::move(MeshDefinition::Blob{0, 16, 0, (uint16_t)16, std::vector<float>(), std::vector<float>()}), std::move(sparseBlob), 0});
+ meshDefinition.mWeights.push_back(
MeshDefinition::Accessor{
- std::move(MeshDefinition::Blob{0, 8, 0, (uint16_t)8, std::vector<float>(), std::vector<float>()}), std::move(sparseBlob), 0};
+ std::move(MeshDefinition::Blob{0, 8, 0, (uint16_t)8, std::vector<float>(), std::vector<float>()}), std::move(sparseBlob), 0});
MeshDefinition::RawData rawData = meshDefinition.LoadRaw("", buffers);
DALI_TEST_EQUALS(rawData.mAttribs.size(), 4, TEST_LOCATION);
- DALI_TEST_EQUALS(rawData.mAttribs[3].mName, "aWeights", TEST_LOCATION);
+ DALI_TEST_EQUALS(rawData.mAttribs[3].mName, "aWeights0", TEST_LOCATION);
DALI_TEST_EQUALS(rawData.mAttribs[3].mNumElements, 2, TEST_LOCATION);
float* value = reinterpret_cast<float*>(rawData.mAttribs[3].mData.data());
for(uint32_t i = 0; i < rawData.mAttribs[3].mNumElements * 4; ++i)
int UtcDaliMeshDefinitionShortSkinWeight(void)
{
- float data8[8] = {0.062516, 0.098634, 0.749752, 0.936492, 0.741207, 0.379873, 0.392386, 0.380468};
+ float data8[8] = {0.062516, 0.098634, 0.749752, 0.936492, 0.741207, 0.379873, 0.392386, 0.380468};
BufferDefinition bufferDefinition;
bufferDefinition.mUri = "data:application/base64,ARBAGe+/ve+/vT9hc2RmYXNkZmFzZGZhc2RmYXNkZmE=";
meshDefinition.mPositions =
MeshDefinition::Accessor{
std::move(MeshDefinition::Blob{0, 12, 0, (uint16_t)12, std::vector<float>(), std::vector<float>()}), std::move(sparseBlob), 0};
- meshDefinition.mJoints0 =
+ meshDefinition.mJoints.push_back(
MeshDefinition::Accessor{
- std::move(MeshDefinition::Blob{0, 16, 0, (uint16_t)16, std::vector<float>(), std::vector<float>()}), std::move(sparseBlob), 0};
- meshDefinition.mWeights0 =
+ std::move(MeshDefinition::Blob{0, 16, 0, (uint16_t)16, std::vector<float>(), std::vector<float>()}), std::move(sparseBlob), 0});
+ meshDefinition.mWeights.push_back(
MeshDefinition::Accessor{
- std::move(MeshDefinition::Blob{0, 16, 0, (uint16_t)16, std::vector<float>(), std::vector<float>()}), std::move(sparseBlob), 0};
+ std::move(MeshDefinition::Blob{0, 16, 0, (uint16_t)16, std::vector<float>(), std::vector<float>()}), std::move(sparseBlob), 0});
MeshDefinition::RawData rawData = meshDefinition.LoadRaw("", buffers);
DALI_TEST_EQUALS(rawData.mAttribs.size(), 4, TEST_LOCATION);
- DALI_TEST_EQUALS(rawData.mAttribs[3].mName, "aWeights", TEST_LOCATION);
+ DALI_TEST_EQUALS(rawData.mAttribs[3].mName, "aWeights0", TEST_LOCATION);
DALI_TEST_EQUALS(rawData.mAttribs[3].mNumElements, 2, TEST_LOCATION);
float* value = reinterpret_cast<float*>(rawData.mAttribs[3].mData.data());
for(uint32_t i = 0; i < rawData.mAttribs[3].mNumElements * 4; ++i)
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Permutation permutations[]{
{
+ //0
[](ShaderParameters& p) {},
{},
RendererState::DEPTH_TEST | RendererState::CULL_BACK,
},
{
- [](ShaderParameters& p)
- {
+ //1
+ [](ShaderParameters& p) {
p.materialDefinition.mFlags |= MaterialDefinition::TRANSPARENCY;
},
{ShaderOption::Type::THREE_TEXTURE},
RendererState::ALPHA_BLEND,
},
- {[](ShaderParameters& p)
- {
+ {//2
+ [](ShaderParameters& p) {
p.materialDefinition.mFlags |= MaterialDefinition::ALBEDO;
p.materialDefinition.mTextureStages.push_back({MaterialDefinition::ALBEDO, {}});
},
{ShaderOption::Type::THREE_TEXTURE, ShaderOption::Type::BASE_COLOR_TEXTURE}},
- {[](ShaderParameters& p)
- {
+ {//3
+ [](ShaderParameters& p) {
p.materialDefinition.mTextureStages.push_back({MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS, {}});
},
{ShaderOption::Type::THREE_TEXTURE, ShaderOption::Type::METALLIC_ROUGHNESS_TEXTURE}},
- {[](ShaderParameters& p)
- {
+ {//4
+ [](ShaderParameters& p) {
p.materialDefinition.mFlags |= MaterialDefinition::NORMAL;
p.materialDefinition.mTextureStages.push_back({MaterialDefinition::NORMAL, {}});
},
{ShaderOption::Type::THREE_TEXTURE, ShaderOption::Type::NORMAL_TEXTURE}},
- {[](ShaderParameters& p)
- {
+ {//5
+ [](ShaderParameters& p) {
p.materialDefinition.mFlags |= MaterialDefinition::SUBSURFACE;
},
{ShaderOption::Type::SUBSURFACE}},
- {[](ShaderParameters& p)
- {
+ {//6
+ [](ShaderParameters& p) {
p.materialDefinition.SetAlphaCutoff(.5f);
},
{ShaderOption::Type::ALPHA_TEST}},
- {[](ShaderParameters& p)
- {
+ {//7
+ [](ShaderParameters& p) {
p.materialDefinition.SetAlphaCutoff(1.f);
},
{ShaderOption::Type::ALPHA_TEST}},
- {[](ShaderParameters& p)
- {
+ {//8
+ [](ShaderParameters& p) {
p.materialDefinition.mFlags |= MaterialDefinition::GLTF_CHANNELS;
},
{ShaderOption::Type::GLTF_CHANNELS}},
- {[](ShaderParameters& p)
- {
- p.meshDefinition.mJoints0.mBlob.mOffset = 0;
- p.meshDefinition.mWeights0.mBlob.mOffset = 0;
+ {//9
+ [](ShaderParameters& p) {
+ p.meshDefinition.mJoints[0].mBlob.mOffset = 0;
+ p.meshDefinition.mWeights[0].mBlob.mOffset = 0;
},
{ShaderOption::Type::SKINNING}},
- {[](ShaderParameters& p)
- {
+ {//10
+ [](ShaderParameters& p) {
p.meshDefinition.mFlags |= MeshDefinition::FLIP_UVS_VERTICAL;
},
{ShaderOption::Type::FLIP_UVS_VERTICAL}},
{
- [](ShaderParameters& p)
- {
+ //11
+ [](ShaderParameters& p) {
p.meshDefinition.mBlendShapes.push_back({});
},
},
- {[](ShaderParameters& p)
- {
+ {//12
+ [](ShaderParameters& p) {
p.meshDefinition.mBlendShapes.back().deltas.mBlob.mOffset = 0;
},
{ShaderOption::Type::MORPH_POSITION}},
- {[](ShaderParameters& p)
- {
+ {//13
+ [](ShaderParameters& p) {
p.meshDefinition.mBlendShapes.back().normals.mBlob.mOffset = 0;
},
{ShaderOption::Type::MORPH_NORMAL}},
- {[](ShaderParameters& p)
- {
+ {//14
+ [](ShaderParameters& p) {
p.meshDefinition.mBlendShapes.back().tangents.mBlob.mOffset = 0;
},
{ShaderOption::Type::MORPH_TANGENT}},
- {[](ShaderParameters& p)
- {
+ {//15
+ [](ShaderParameters& p) {
auto& blendShapes = p.meshDefinition.mBlendShapes;
DALI_ASSERT_ALWAYS(!blendShapes.empty() &&
(blendShapes.back().deltas.mBlob.mOffset != MeshDefinition::INVALID ||
},
{ShaderOption::Type::MORPH_VERSION_2_0}},
- {[](ShaderParameters& p)
- {
+ {//16
+ [](ShaderParameters& p) {
p.materialDefinition.mFlags |= MaterialDefinition::OCCLUSION;
},
{ShaderOption::Type::OCCLUSION}},
- {[](ShaderParameters& p)
- {
- p.meshDefinition.mColors.mBlob.mOffset = 0;
+ {//17
+ [](ShaderParameters& p) {
+ p.meshDefinition.mColors[0].mBlob.mOffset = 0;
},
{ShaderOption::Type::COLOR_ATTRIBUTE}},
- {[](ShaderParameters& p)
- {
+ {//18
+ [](ShaderParameters& p) {
p.meshDefinition.mTangentType = Property::VECTOR4;
},
{ShaderOption::Type::VEC4_TANGENT}},
MeshDefinition meshDefinition;
MaterialDefinition materialDefinition;
ShaderParameters shaderParameter{meshDefinition, materialDefinition, nodeDefinition};
-
+ // Only define skinning accessors for skinning test...
+ if(permutationSet.permutations.size() > 1)
+ {
+ auto& checkP = permutationSet.permutations[1];
+ if(auto search = checkP->options.find(ShaderOption::Type::SKINNING);
+ search != checkP->options.end())
+ {
+ meshDefinition.mJoints.push_back(MeshDefinition::Accessor{MeshDefinition::Blob{0, 0}, {}});
+ meshDefinition.mWeights.push_back(MeshDefinition::Accessor{MeshDefinition::Blob{0, 0}, {}});
+ }
+ }
std::set<std::string> defines;
- ShaderOption option;
+ ShaderOption option1;
RendererState::Type rendererState = 0;
for(auto permutation : permutationSet.permutations)
{
permutation->configureFn(shaderParameter);
if(materialDefinition.mFlags & MaterialDefinition::TRANSPARENCY)
{
- option.SetTransparency();
+ option1.SetTransparency();
}
for(auto&& optionType : permutation->options)
{
- option.AddOption(optionType);
+ option1.AddOption(optionType);
}
rendererState = (rendererState | permutation->rendererStateSet) & ~permutation->rendererStateClear;
}
- option.AddOption(ShaderOption::Type::THREE_TEXTURE);
+ option1.AddOption(ShaderOption::Type::THREE_TEXTURE);
- Shader shaderFromMeshAndMaterial = shaderManager.ProduceShader(materialDefinition, meshDefinition);
- Shader shaderFromOption = shaderManager.ProduceShader(option);
- DALI_TEST_EQUAL(shaderFromMeshAndMaterial, shaderFromOption);
+ ShaderOption option2 = shaderManager.ProduceShaderOption(materialDefinition, meshDefinition);
+
+ Shader shaderFromOption1 = shaderManager.ProduceShader(option1);
+ Shader shaderFromOption2 = shaderManager.ProduceShader(option2);
+ DALI_TEST_EQUAL(option1.GetOptionHash(), option2.GetOptionHash());
+ DALI_TEST_EQUAL(shaderFromOption1, shaderFromOption2);
RendererState::Type rendererStateFromMaterialDefinition = shaderManager.GetRendererState(materialDefinition);
DALI_TEST_EQUAL(rendererStateFromMaterialDefinition, rendererState);
DALI_TEST_EQUALS(shader1.GetProperty<int>(shader1.GetPropertyIndex("uLightCount")), 1, TEST_LOCATION);
DALI_TEST_EQUALS(shader2.GetProperty<int>(shader2.GetPropertyIndex("uLightCount")), 1, TEST_LOCATION);
-
+
ShaderOption option3;
option3.AddOption(ShaderOption::Type::METALLIC_ROUGHNESS_TEXTURE);
Dali::Shader shader3 = shaderManager.ProduceShader(option3);
const char* TEST_IMAGE_4_FILE_NAME = TEST_RESOURCE_DIR "/application-icon-20.png";
const char* TEST_MASK_FILE_NAME = TEST_RESOURCE_DIR "/mask.png";
+const char* TEST_SVG_FILE_NAME = TEST_RESOURCE_DIR "/svg1.svg";
+const char* TEST_ANIMATED_VECTOR_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/insta_camera.json";
+
class TestObserver : public Dali::Toolkit::TextureUploadObserver
{
public:
std::string url1 = textureManager.AddEncodedImageBuffer(buffer1);
std::string url2 = textureManager.AddEncodedImageBuffer(buffer1);
- std::string url3 = VisualUrl::CreateBufferUrl(""); ///< Impossible Buffer URL. for coverage
+ std::string url3 = VisualUrl::CreateBufferUrl("", ""); ///< Impossible Buffer URL. for coverage
// Check if same EncodedImageBuffer get same url
DALI_TEST_CHECK(url1 == url2);
END_TEST;
}
+int UtcTextureManagerEncodedImageBufferWithImageType(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcTextureManagerEncodedImageBufferWithImageType");
+
+ auto visualFactory = Toolkit::VisualFactory::Get();
+ auto& textureManager = GetImplementation(visualFactory).GetTextureManager(); // Use VisualFactory's texture manager
+
+ // Get encoded raw-buffer image and generate url
+ EncodedImageBuffer buffer1 = ConvertFileToEncodedImageBuffer(TEST_SVG_FILE_NAME);
+ EncodedImageBuffer buffer2 = ConvertFileToEncodedImageBuffer(TEST_ANIMATED_VECTOR_IMAGE_FILE_NAME);
+
+ std::string url1 = textureManager.AddEncodedImageBuffer(buffer1);
+ std::string url2 = textureManager.AddEncodedImageBuffer(buffer1);
+
+ // Check if same EncodedImageBuffer get same url
+ DALI_TEST_CHECK(url1 == url2);
+ // Reduce reference count
+ textureManager.RemoveEncodedImageBuffer(url1);
+ // Check whethere url1 still valid
+ DALI_TEST_CHECK(textureManager.GetEncodedImageBuffer(url1));
+
+ url2 = textureManager.AddEncodedImageBuffer(buffer2);
+ // Check if difference EncodedImageBuffer get difference url
+ DALI_TEST_CHECK(url1 != url2);
+
+ buffer1.SetImageType(EncodedImageBuffer::ImageType::VECTOR_IMAGE);
+ buffer2.SetImageType(EncodedImageBuffer::ImageType::ANIMATED_VECTOR_IMAGE);
+
+ std::string url1AfterType = textureManager.AddEncodedImageBuffer(buffer1);
+ std::string url2AfterType = textureManager.AddEncodedImageBuffer(buffer2);
+
+ // Check if EncodedImageBuffer with imagetype get difference url.
+ DALI_TEST_CHECK(url1 != url1AfterType);
+ DALI_TEST_CHECK(url2 != url2AfterType);
+ DALI_TEST_CHECK(url1AfterType != url2AfterType);
+
+ int bufferId = std::atoi(VisualUrl::GetLocationWithoutExtension(url1AfterType).c_str());
+ auto urlFromBuffer = textureManager.GetVisualUrl(bufferId);
+
+ // Check url from buffer id is equal with what we know.
+ DALI_TEST_CHECK(url1AfterType == urlFromBuffer.GetUrl());
+
+ // Reduce reference count
+ textureManager.RemoveEncodedImageBuffer(url1AfterType);
+ // Check whethere url1 still valid
+ DALI_TEST_CHECK(textureManager.GetEncodedImageBuffer(url1AfterType));
+
+ // Reduce reference count
+ textureManager.RemoveEncodedImageBuffer(url1AfterType);
+ // Check whethere url1 is invalid
+ DALI_TEST_CHECK(!textureManager.GetEncodedImageBuffer(url1AfterType));
+
+ // Reduce reference count
+ textureManager.RemoveEncodedImageBuffer(url2);
+ // Check whethere url2 is still valid
+ DALI_TEST_CHECK(textureManager.GetEncodedImageBuffer(url2));
+
+ // Reduce reference count
+ textureManager.RemoveEncodedImageBuffer(url2);
+ // Check whethere url2 is invalid
+ DALI_TEST_CHECK(!textureManager.GetEncodedImageBuffer(url2));
+
+ END_TEST;
+}
+
int UtcTextureManagerExternalTexture(void)
{
ToolkitTestApplication application;
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
END_TEST;
}
+int UtcDaliVisualUrlGetLocationWithoutExtensionP(void)
+{
+ tet_infoline("UtcDaliVisualUrl GetLocationWithoutExtension Positive");
+
+ DALI_TEST_EQUAL("a", VisualUrl("http://a.png").GetLocationWithoutExtension());
+ DALI_TEST_EQUAL("1", VisualUrl("dali://1.jpg").GetLocationWithoutExtension());
+ DALI_TEST_EQUAL("4", VisualUrl("enbuf://4.svg").GetLocationWithoutExtension());
+ DALI_TEST_EQUAL("", VisualUrl("ftp://.png").GetLocationWithoutExtension());
+ DALI_TEST_EQUAL("http://a.jpg", VisualUrl("http://http://a.jpg.jpg").GetLocationWithoutExtension());
+
+ END_TEST;
+}
+
int UtcDaliVisualUrlGetLocationN(void)
{
tet_infoline("UtcDaliVisualUrl GetLocation Negative");
END_TEST;
}
+int UtcDaliVisualUrlGetLocationWithoutExtensionN(void)
+{
+ tet_infoline("UtcDaliVisualUrl GetLocationWithoutExtension Negative");
+
+ DALI_TEST_EQUAL("", VisualUrl("").GetLocationWithoutExtension());
+ DALI_TEST_EQUAL("a", VisualUrl("a").GetLocationWithoutExtension());
+ DALI_TEST_EQUAL("dali:/1.jpg", VisualUrl("dali:/1.jpg").GetLocationWithoutExtension());
+ DALI_TEST_EQUAL("dali//1.jpg", VisualUrl("dali//1.jpg").GetLocationWithoutExtension());
+ DALI_TEST_EQUAL("enbuf:/2.png", VisualUrl("enbuf:/2.png").GetLocationWithoutExtension());
+ DALI_TEST_EQUAL("a.jpg", VisualUrl("http:/http://a.jpg.jpngif").GetLocationWithoutExtension());
+
+ END_TEST;
+}
+
int UtcDaliVisualUrlCreateTextureUrl(void)
{
tet_infoline("UtcDaliVisualUrl CreateTextureUrl");
{
tet_infoline("UtcDaliVisualUrl CreateBufferUrl");
- DALI_TEST_EQUAL("enbuf://a", VisualUrl::CreateBufferUrl("a"));
- DALI_TEST_EQUAL("enbuf://1234", VisualUrl::CreateBufferUrl("1234"));
- DALI_TEST_EQUAL("enbuf://", VisualUrl::CreateBufferUrl(""));
+ DALI_TEST_EQUAL("enbuf://a", VisualUrl::CreateBufferUrl("a", ""));
+ DALI_TEST_EQUAL("enbuf://1234", VisualUrl::CreateBufferUrl("1234", ""));
+ DALI_TEST_EQUAL("enbuf://", VisualUrl::CreateBufferUrl("", ""));
+
+ END_TEST;
+}
+
+int UtcDaliVisualUrlCreateBufferUrlWithExtension(void)
+{
+ tet_infoline("UtcDaliVisualUrl CreateBufferUrl with extension");
+
+ DALI_TEST_EQUAL("enbuf://a.jpg", VisualUrl::CreateBufferUrl("a", ".jpg"));
+ DALI_TEST_EQUAL("enbuf://1234567", VisualUrl::CreateBufferUrl("1234", "567"));
+ DALI_TEST_EQUAL("enbuf://b", VisualUrl::CreateBufferUrl("", "b"));
END_TEST;
}
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
namespace Dali
{
-EncodedImageBuffer ConvertFileToEncodedImageBuffer(const char* url)
+EncodedImageBuffer ConvertFileToEncodedImageBuffer(const char* url, EncodedImageBuffer::ImageType imageType)
{
EncodedImageBuffer buffer;
- FILE *fp;
+ FILE* fp;
fp = fopen(url, "rb");
if(fp != NULL)
{
fseek(fp, 0, SEEK_END);
- size_t size = ftell(fp);
+ size_t size = ftell(fp);
Dali::Vector<uint8_t> data;
data.Resize(size);
fseek(fp, 0, SEEK_SET);
size_t realSize = fread(data.Begin(), sizeof(uint8_t), size, fp);
fclose(fp);
data.Resize(realSize);
- buffer = EncodedImageBuffer::New(data);
+ buffer = EncodedImageBuffer::New(data, imageType);
}
return buffer;
}
#define TEST_ENCODED_IMAGE_BUFFER_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
namespace Dali
{
-
// util function to convert local file to EncodedImageBuffer
-EncodedImageBuffer ConvertFileToEncodedImageBuffer(const char* url);
+EncodedImageBuffer ConvertFileToEncodedImageBuffer(const char* url, EncodedImageBuffer::ImageType imageType = EncodedImageBuffer::ImageType::DEFAULT);
} // namespace Dali
}
mProgramCache.emplace_back();
- mProgramCache.back().programImpl = new TestGraphicsProgramImpl(mGl, programCreateInfo, mVertexFormats, mCustomUniforms, mCustomUniformBlocks);
+ mProgramCache.back().programImpl = new TestGraphicsProgramImpl(*this, mGl, programCreateInfo, mVertexFormats, mCustomUniforms, mCustomUniformBlocks);
for(auto& shader : *(programCreateInfo.shaderState))
{
Graphics::UniquePtr<Graphics::Texture> ReleaseTextureFromResourceId(uint32_t resourceId) override;
public: // Test Functions
+ void SetAutoAttrCreation(bool v)
+ {
+ mAutoAttrCreation = v;
+ }
+ bool AutoAttrCreation()
+ {
+ return mAutoAttrCreation;
+ }
+
void SetVertexFormats(Property::Array& vfs)
{
mVertexFormats = vfs;
TestGraphicsSyncImplementation mGraphicsSyncImpl;
TestGlContextHelperAbstraction mGlContextHelperAbstraction;
- bool isDiscardQueueEmptyResult{true};
- bool isDrawOnResumeRequiredResult{true};
-
+ bool isDiscardQueueEmptyResult{true};
+ bool isDrawOnResumeRequiredResult{true};
+ bool mAutoAttrCreation{true};
Property::Array mVertexFormats;
struct ProgramCache
namespace Dali
{
-TestGraphicsProgramImpl::TestGraphicsProgramImpl(TestGlAbstraction& gl, const Graphics::ProgramCreateInfo& createInfo, Property::Array& vertexFormats, std::vector<UniformData>& customUniforms, std::vector<TestGraphicsReflection::TestUniformBlockInfo>& customUniformBlocks)
-: mGl(gl),
+TestGraphicsProgramImpl::TestGraphicsProgramImpl(TestGraphicsController& controller, TestGlAbstraction& gl, const Graphics::ProgramCreateInfo& createInfo, Property::Array& vertexFormats, std::vector<UniformData>& customUniforms, std::vector<TestGraphicsReflection::TestUniformBlockInfo>& customUniformBlocks)
+: mController(controller),
+ mGl(gl),
mId(gl.CreateProgram()),
mCreateInfo(createInfo),
- mReflection(gl, mId, vertexFormats, createInfo, customUniforms, customUniformBlocks)
+ mReflection(controller, gl, mId, vertexFormats, createInfo, customUniforms, customUniformBlocks)
{
// Ensure active sampler uniforms are set
mGl.SetCustomUniforms(customUniforms);
namespace Dali
{
+class TestGraphicsController;
+
class TestGraphicsProgramImpl
{
public:
- TestGraphicsProgramImpl(TestGlAbstraction& gl, const Graphics::ProgramCreateInfo& createInfo, Property::Array& vertexFormats, std::vector<UniformData>& customUniforms, std::vector<TestGraphicsReflection::TestUniformBlockInfo>& customUniformBlocks);
+ TestGraphicsProgramImpl(TestGraphicsController& controller, TestGlAbstraction& gl, const Graphics::ProgramCreateInfo& createInfo, Property::Array& vertexFormats, std::vector<UniformData>& customUniforms, std::vector<TestGraphicsReflection::TestUniformBlockInfo>& customUniformBlocks);
// For API
const TestGraphicsReflection& GetReflection() const
bool GetParameter(uint32_t parameterId, void* outData);
public:
+ TestGraphicsController& mController;
TestGlAbstraction& mGl;
uint32_t mId;
Graphics::ProgramCreateInfo mCreateInfo;
*/
#include "test-graphics-reflection.h"
+#include "test-graphics-controller.h"
#include "test-graphics-shader.h"
#include <dali/public-api/object/property-map.h>
} // namespace
-TestGraphicsReflection::TestGraphicsReflection(TestGlAbstraction& gl, uint32_t programId, Property::Array& vfs, const Graphics::ProgramCreateInfo& createInfo, std::vector<UniformData>& customUniforms, std::vector<TestGraphicsReflection::TestUniformBlockInfo>& customUniformBlocks)
-: mGl(gl),
+TestGraphicsReflection::TestGraphicsReflection(TestGraphicsController& controller, TestGlAbstraction& gl, uint32_t programId, Property::Array& vfs, const Graphics::ProgramCreateInfo& createInfo, std::vector<UniformData>& customUniforms, std::vector<TestGraphicsReflection::TestUniformBlockInfo>& customUniformBlocks)
+: mController(controller),
+ mGl(gl),
mCustomUniforms(customUniforms)
{
for(Property::Array::SizeType i = 0; i < vfs.Count(); ++i)
uint32_t TestGraphicsReflection::GetVertexAttributeLocation(const std::string& name) const
{
- // Automatically assign locations to named attributes when requested
auto iter = std::find(mAttributes.begin(), mAttributes.end(), name);
if(iter != mAttributes.end())
{
return iter - mAttributes.begin();
}
- else
+ else if(mController.AutoAttrCreation())
{
uint32_t location = mAttributes.size();
mAttributes.push_back(name);
return location;
}
- return 0u;
+
+ return -1;
}
Dali::Graphics::VertexInputAttributeFormat TestGraphicsReflection::GetVertexAttributeFormat(uint32_t location) const
namespace Dali
{
+class TestGraphicsController;
+
class TestGraphicsReflection : public Graphics::Reflection
{
public:
class TestUniformBlockInfo;
- TestGraphicsReflection(TestGlAbstraction& gl, uint32_t program_id, Property::Array& vertexFormats, const Graphics::ProgramCreateInfo& createInfo, std::vector<UniformData>& customUniforms, std::vector<TestUniformBlockInfo>& customUniformBlocks);
+ TestGraphicsReflection(TestGraphicsController& controller, TestGlAbstraction& gl, uint32_t program_id, Property::Array& vertexFormats, const Graphics::ProgramCreateInfo& createInfo, std::vector<UniformData>& customUniforms, std::vector<TestUniformBlockInfo>& customUniformBlocks);
uint32_t GetVertexAttributeLocation(const std::string& name) const override;
Dali::Graphics::VertexInputAttributeFormat GetVertexAttributeFormat(uint32_t location) const override;
return mUniformBlocks[index];
}
+ TestGraphicsController& mController;
TestGlAbstraction& mGl;
mutable std::vector<std::string> mAttributes;
std::vector<UniformData> mCustomUniforms;
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <dali/devel-api/adaptor-framework/vector-animation-renderer.h>
#include <dali/devel-api/threading/mutex.h>
#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/object/property-array.h>
#include <toolkit-application.h>
#include <toolkit-event-thread-callback.h>
#include <toolkit-vector-animation-renderer.h>
return Internal::Adaptor::GetImplementation(*this).GetMarkerInfo(marker, startFrame, endFrame);
}
+void VectorAnimationRenderer::GetMarkerInfo(Property::Map& map) const
+{
+ map.Add(VECTOR_ANIMATION_MARKER_NAME_1, Property::Array({VECTOR_ANIMATION_MARKER_START_FRAME_1, VECTOR_ANIMATION_MARKER_END_FRAME_1}));
+ map.Add(VECTOR_ANIMATION_MARKER_NAME_2, Property::Array({VECTOR_ANIMATION_MARKER_START_FRAME_2, VECTOR_ANIMATION_MARKER_END_FRAME_2}));
+}
+
void VectorAnimationRenderer::InvalidateBuffer()
{
return Internal::Adaptor::GetImplementation(*this).InvalidateBuffer();
value = resultMap.Find(DevelImageVisual::Property::CONTENT_INFO, Property::MAP);
DALI_TEST_CHECK(value);
+ value = resultMap.Find(DevelImageVisual::Property::MARKER_INFO, Property::MAP);
+ DALI_TEST_CHECK(value);
+
value = resultMap.Find(DevelImageVisual::Property::REDRAW_IN_SCALING_DOWN, Property::BOOLEAN);
DALI_TEST_CHECK(value);
DALI_TEST_CHECK(value->Get<bool>() == true); // Check default value
END_TEST;
}
+int UtcDaliAnimatedVectorImageVisualMarkerInfo(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliAnimatedVectorImageVisualMarkerInfo");
+
+ Property::Map propertyMap;
+ propertyMap.Add(Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE)
+ .Add(ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME)
+ .Add(ImageVisual::Property::SYNCHRONOUS_LOADING, false);
+
+ Visual::Base visual = VisualFactory::Get().CreateVisual(propertyMap);
+ DALI_TEST_CHECK(visual);
+
+ DummyControl actor = DummyControl::New(true);
+ DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+ dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, visual);
+
+ Vector2 controlSize(20.f, 30.f);
+ actor.SetProperty(Actor::Property::SIZE, controlSize);
+
+ application.GetScene().Add(actor);
+
+ Property::Map attributes;
+ DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes);
+
+ application.SendNotification();
+ application.Render();
+
+ // Trigger count is 2 - load & render a frame
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+
+ // renderer is added to actor
+ DALI_TEST_CHECK(actor.GetRendererCount() == 1u);
+ Renderer renderer = actor.GetRendererAt(0u);
+ DALI_TEST_CHECK(renderer);
+
+ Property::Map map = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
+ Property::Value* value = map.Find(DevelImageVisual::Property::MARKER_INFO);
+
+ DALI_TEST_CHECK(value);
+
+ Property::Map* result = value->GetMap();
+ DALI_TEST_CHECK(result);
+
+ std::string resultMarkerName;
+ int resultStartFrame, resultEndFrame;
+ DALI_TEST_EQUALS(2u, result->Count(), TEST_LOCATION);
+
+ for(uint32_t i = 0u; i < result->Count(); ++i)
+ {
+ if(result->GetKeyAt(i).stringKey == VECTOR_ANIMATION_MARKER_NAME_1)
+ {
+ Property::Array* frameArray = result->GetValue(i).GetArray();
+ DALI_TEST_CHECK(frameArray);
+ frameArray->GetElementAt(0).Get(resultStartFrame);
+ frameArray->GetElementAt(1).Get(resultEndFrame);
+
+ DALI_TEST_EQUALS(VECTOR_ANIMATION_MARKER_START_FRAME_1, resultStartFrame, TEST_LOCATION);
+ DALI_TEST_EQUALS(VECTOR_ANIMATION_MARKER_END_FRAME_1, resultEndFrame, TEST_LOCATION);
+ }
+ else if(result->GetKeyAt(i).stringKey == VECTOR_ANIMATION_MARKER_NAME_2)
+ {
+ Property::Array* frameArray = result->GetValue(i).GetArray();
+ DALI_TEST_CHECK(frameArray);
+ frameArray->GetElementAt(0).Get(resultStartFrame);
+ frameArray->GetElementAt(1).Get(resultEndFrame);
+
+ DALI_TEST_EQUALS(VECTOR_ANIMATION_MARKER_START_FRAME_2, resultStartFrame, TEST_LOCATION);
+ DALI_TEST_EQUALS(VECTOR_ANIMATION_MARKER_END_FRAME_2, resultEndFrame, TEST_LOCATION);
+ }
+ else
+ {
+ DALI_TEST_CHECK(false);
+ }
+ }
+
+ END_TEST;
+}
+
int UtcDaliAnimatedVectorImageVisualAnimationFinishedSignal(void)
{
ToolkitTestApplication application;
END_TEST;
}
+int UtcDaliImageViewEncodedBufferWithSvg(void)
+{
+ ToolkitTestApplication application;
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ const std::vector<GLuint>& textures = gl.GetBoundTextures();
+ size_t numTextures = textures.size();
+
+ // Get encoded raw-buffer svg image and generate url
+ EncodedImageBuffer buffer = ConvertFileToEncodedImageBuffer(TEST_SVG_FILE_NAME, EncodedImageBuffer::ImageType::VECTOR_IMAGE);
+ ImageUrl url = Toolkit::Image::GenerateUrl(buffer);
+
+ // Async loading, no atlasing for big size image
+ ImageView imageView = ImageView::New(url.GetUrl());
+
+ // By default, Aysnc loading is used
+ application.GetScene().Add(imageView);
+ imageView.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
+ imageView.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+ application.SendNotification();
+ application.Render(16);
+
+ // Load svg image + rasterize.
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render(16);
+ application.SendNotification();
+
+ const std::vector<GLuint>& textures2 = gl.GetBoundTextures();
+ DALI_TEST_GREATER(textures2.size(), numTextures, TEST_LOCATION);
+
+ // Remove visual, for line coverage.
+ imageView.Unparent();
+ application.SendNotification();
+ application.Render(16);
+
+ END_TEST;
+}
+
+int UtcDaliImageViewEncodedBufferWithAnimatedVectorImage(void)
+{
+ ToolkitTestApplication application;
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ const std::vector<GLuint>& textures = gl.GetBoundTextures();
+ size_t numTextures = textures.size();
+
+ // Get encoded raw-buffer lottie image and generate url
+ EncodedImageBuffer buffer = ConvertFileToEncodedImageBuffer(TEST_ANIMATED_VECTOR_IMAGE_FILE_NAME, EncodedImageBuffer::ImageType::ANIMATED_VECTOR_IMAGE);
+ ImageUrl url = Toolkit::Image::GenerateUrl(buffer);
+
+ // Async loading, no atlasing for big size image
+ ImageView imageView = ImageView::New(url.GetUrl());
+
+ // By default, Aysnc loading is used
+ application.GetScene().Add(imageView);
+ imageView.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
+ imageView.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+ application.SendNotification();
+ application.Render(16);
+
+ // Load lottie image is sync. Only wait rasterize.
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render(16);
+ application.SendNotification();
+
+ const std::vector<GLuint>& textures2 = gl.GetBoundTextures();
+ DALI_TEST_GREATER(textures2.size(), numTextures, TEST_LOCATION);
+
+ // Remove visual, for line coverage.
+ imageView.Unparent();
+ application.SendNotification();
+ application.Render(16);
+
+ END_TEST;
+}
+
int UtcDaliImageViewAddedTexture(void)
{
ToolkitTestApplication application;
END_TEST;
}
+int UtcDaliImageViewLoadRemoteLottie(void)
+{
+ tet_infoline("Test load from a remote server. (Note we don't support real download now. Just for line coverage)");
+
+ ToolkitTestApplication application;
+
+ {
+ Toolkit::ImageView imageView;
+ imageView = Toolkit::ImageView::New();
+ imageView.SetImage("https://lottie.json");
+ imageView.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+ imageView.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ imageView.SetProperty(Actor::Property::SIZE, Vector2(300, 300));
+ imageView.SetProperty(Actor::Property::POSITION, Vector3(150.0f, 150.0f, 0.0f));
+
+ application.GetScene().Add(imageView);
+
+ DALI_TEST_CHECK(imageView);
+
+ application.SendNotification();
+ application.Render();
+
+ // Do not check anything for here.
+ }
+
+ END_TEST;
+}
+
int UtcDaliImageViewSyncSVGLoading(void)
{
ToolkitTestApplication application;
}
}
+void OnResourceReadySignal11(Control control)
+{
+ gResourceReadySignalCounter++;
+
+ if(!gImageView2)
+ {
+ auto scene = gImageView1.GetParent();
+
+ // Try to load animated image visual here which is already cached, and then ignore forcely.
+
+ Property::Map map1;
+ map1[Toolkit::ImageVisual::Property::URL] = TEST_GIF_FILE_NAME;
+
+ gImageView2 = ImageView::New();
+ gImageView2.SetProperty(Toolkit::ImageView::Property::IMAGE, map1);
+
+ gImageView3 = ImageView::New();
+ gImageView3.SetProperty(Toolkit::ImageView::Property::IMAGE, map1);
+
+ scene.Add(gImageView2);
+ gImageView2.Unparent();
+
+ scene.Add(gImageView3);
+ gImageView3.Unparent();
+ gImageView3.Reset(); // Destroy visual
+ }
+}
+
} // namespace
int UtcDaliImageViewSetImageOnResourceReadySignal01(void)
END_TEST;
}
+int UtcDaliImageViewSetImageOnResourceReadySignal11(void)
+{
+ tet_infoline("Test ResourceReady Add AnimatedImageVisual and then Remove immediately.");
+
+ ToolkitTestApplication application;
+
+ gResourceReadySignalCounter = 0;
+
+ // Clear image view for clear test
+
+ if(gImageView1)
+ {
+ gImageView1.Reset();
+ }
+ if(gImageView2)
+ {
+ gImageView2.Reset();
+ }
+ if(gImageView3)
+ {
+ gImageView3.Reset();
+ }
+
+ try
+ {
+ gImageView1 = ImageView::New();
+ gImageView1.SetProperty(Toolkit::ImageView::Property::IMAGE, TEST_GIF_FILE_NAME);
+ gImageView1.ResourceReadySignal().Connect(&OnResourceReadySignal11);
+ application.GetScene().Add(gImageView1); // It will call resourceReady signal 1 time.
+
+ tet_printf("ResourceReady called %d times\n", gResourceReadySignalCounter);
+
+ DALI_TEST_EQUALS(gResourceReadySignalCounter, 0, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render();
+
+ // Load gImageView1
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+ tet_printf("ResourceReady called %d times\n", gResourceReadySignalCounter);
+
+ DALI_TEST_EQUALS(gResourceReadySignalCounter, 1, TEST_LOCATION);
+
+ DALI_TEST_CHECK(true);
+ }
+ catch(...)
+ {
+ // Exception should not happened
+ DALI_TEST_CHECK(false);
+ }
+
+ // Clear cache.
+ application.SendNotification();
+ application.Render();
+
+ gResourceReadySignalCounter = 0;
+
+ // Clear image view for clear test
+
+ if(gImageView1)
+ {
+ gImageView1.Reset();
+ }
+ if(gImageView2)
+ {
+ gImageView2.Reset();
+ }
+ if(gImageView3)
+ {
+ gImageView3.Reset();
+ }
+
+ END_TEST;
+}
+
int UtcDaliImageViewUseSameUrlWithAnimatedImageVisual(void)
{
tet_infoline("Test multiple views with same image in animated image visual");
#define MORPH defined(MORPH_POSITION) || defined(MORPH_NORMAL) || defined(MORPH_TANGENT)
+// If needed, define these strings in code, insert after each.
+#define ADD_EXTRA_SKINNING_ATTRIBUTES
+#define ADD_EXTRA_WEIGHTS
+
#ifdef HIGHP
precision highp float;
#else
in vec4 aVertexColor;
+#ifdef SKINNING
+in vec4 aJoints0;
+in vec4 aWeights0;
+ADD_EXTRA_SKINNING_ATTRIBUTES;
+#endif
+
#ifdef MORPH
uniform highp sampler2D sBlendShapeGeometry;
#endif
uniform mat4 uProjection;
#ifdef SKINNING
- in vec4 aJoints;
- in vec4 aWeights;
- #define MAX_BONES 80
- uniform mat4 uBone[MAX_BONES];
- uniform mediump vec3 uYDirection;
+
+#define MAX_BONES 256
+layout(std140) uniform Bones
+{
+ mat4 uBone[MAX_BONES];
+};
+
+uniform mediump vec3 uYDirection;
#endif
#ifdef MORPH
#endif
+
+
+
#ifdef SKINNING
- highp mat4 bone = uBone[int(aJoints.x)] * aWeights.x +
- uBone[int(aJoints.y)] * aWeights.y +
- uBone[int(aJoints.z)] * aWeights.z +
- uBone[int(aJoints.w)] * aWeights.w;
+ highp mat4 bone =
+ uBone[int(aJoints0.x)] * aWeights0.x +
+ uBone[int(aJoints0.y)] * aWeights0.y +
+ uBone[int(aJoints0.z)] * aWeights0.z +
+ uBone[int(aJoints0.w)] * aWeights0.w;
+
+ ADD_EXTRA_WEIGHTS;
+
position = bone * position;
normal = uYDirection * (bone * vec4(normal, 0.0)).xyz;
tangent = uYDirection * (bone * vec4(tangent, 0.0)).xyz;
#else
highp vec4 positionW = uModelMatrix * position;
#endif
+
highp vec4 positionV = uViewMatrix * positionW;
vPositionToCamera = transpose(mat3(uViewMatrix)) * -vec3(positionV.xyz / positionV.w);
#version 300 es
+#define ADD_EXTRA_SKINNING_ATTRIBUTES
+#define ADD_EXTRA_WEIGHTS
+
precision highp float;
in vec3 aPosition;
in vec2 aTexCoord;
in vec4 aVertexColor;
+#ifdef SKINNING
+in vec4 aJoints0;
+in vec4 aWeights0;
+ADD_EXTRA_SKINNING_ATTRIBUTES;
+#endif
+
out mediump vec2 vUV;
out lowp vec4 vColor;
uniform highp mat4 uProjection;
#ifdef SKINNING
- in vec4 aJoints;
- in vec4 aWeights;
- #define MAX_BONES 64
- uniform mat4 uBone[MAX_BONES];
- uniform mediump vec3 uYDirection;
+#define MAX_BONES 256
+layout(std140) uniform Bones
+{
+ mat4 uBone[MAX_BONES];
+};
+uniform mediump vec3 uYDirection;
#endif
#ifdef MORPH
#endif
#ifdef SKINNING
- highp mat4 bone = uBone[int(aJoints.x)] * aWeights.x +
- uBone[int(aJoints.y)] * aWeights.y +
- uBone[int(aJoints.z)] * aWeights.z +
- uBone[int(aJoints.w)] * aWeights.w;
- position = bone * position;
+ highp mat4 bone = uBone[int(aJoints0.x)] * aWeights0.x +
+ uBone[int(aJoints0.y)] * aWeights0.y +
+ uBone[int(aJoints0.z)] * aWeights0.z +
+ uBone[int(aJoints0.w)] * aWeights0.w;
+ ADD_EXTRA_WEIGHTS;
+
+ position = bone * position;
highp vec4 positionW = position;
#else
highp vec4 positionW = uModelMatrix * position;
auto& node = (*i0).second;
ShaderDefinition shaderDef;
ReadStringVector(node.GetChild("defines"), shaderDef.mDefines);
- auto sssIter = std::find_if(shaderDef.mDefines.begin(), shaderDef.mDefines.end(), [](std::string& item)
- { return (item == "SSS"); });
+ auto sssIter = std::find_if(shaderDef.mDefines.begin(), shaderDef.mDefines.end(), [](std::string& item) { return (item == "SSS"); });
if(sssIter != shaderDef.mDefines.end())
{
shaderDef.mDefines.erase(sssIter);
mOnError(FormatString("mesh %d: Failed to read %s.", resources.mMeshes.size(), "normals"));
}
- if(MaskMatch(attributes, MeshDefinition::TEX_COORDS) &&
- !ReadAttribAccessor(node.GetChild("textures"), meshDef.mTexCoords))
+ if(MaskMatch(attributes, MeshDefinition::TEX_COORDS))
{
- mOnError(FormatString("mesh %d: Failed to read %s.", resources.mMeshes.size(), "textures"));
+ meshDef.mTexCoords.emplace_back(MeshDefinition::Accessor{});
+ if(!ReadAttribAccessor(node.GetChild("textures"), meshDef.mTexCoords[0]))
+ {
+ mOnError(FormatString("mesh %d: Failed to read %s.", resources.mMeshes.size(), "textures"));
+ }
}
if(MaskMatch(attributes, MeshDefinition::TANGENTS) &&
mOnError(FormatString("mesh %d: Expected joints0 / weights0 attribute(s) missing.",
resources.mMeshes.size()));
}
- else if(!ReadAttribAccessor(node.GetChild("joints0"), meshDef.mJoints0) ||
- !ReadAttribAccessor(node.GetChild("weights0"), meshDef.mWeights0))
+ else
{
- mOnError(FormatString("mesh %d: Failed to read skinning information.",
- resources.mMeshes.size()));
+ meshDef.mJoints.emplace_back(MeshDefinition::Accessor{});
+ meshDef.mWeights.emplace_back(MeshDefinition::Accessor{});
+ if(!ReadAttribAccessor(node.GetChild("joints0"), meshDef.mJoints[0]) ||
+ !ReadAttribAccessor(node.GetChild("weights0"), meshDef.mWeights[0]))
+ {
+ mOnError(FormatString("mesh %d: Failed to read skinning information.",
+ resources.mMeshes.size()));
+ }
}
}
materialDef.mFlags |= semantic;
}
-/// @TODO : Some dli shader don't implement this subsurfaceMp usage.
-/// To make visual test pass, Skip subsurfaceMap texture using
-/// until dli shaders are support it.
-// if(ReadString(node.GetChild("subsurfaceMap"), texturePath))
-// {
-// ToUnixFileSeparators(texturePath);
-//
-// const auto semantic = MaterialDefinition::SUBSURFACE;
-// materialDef.mTextureStages.push_back({semantic, TextureDefinition{std::move(texturePath)}});
-// materialDef.mFlags |= semantic;
-// }
+ /// @TODO : Some dli shader don't implement this subsurfaceMp usage.
+ /// To make visual test pass, Skip subsurfaceMap texture using
+ /// until dli shaders are support it.
+ // if(ReadString(node.GetChild("subsurfaceMap"), texturePath))
+ // {
+ // ToUnixFileSeparators(texturePath);
+ //
+ // const auto semantic = MaterialDefinition::SUBSURFACE;
+ // materialDef.mTextureStages.push_back({semantic, TextureDefinition{std::move(texturePath)}});
+ // materialDef.mFlags |= semantic;
+ // }
if(ReadString(node.GetChild("occlusionMap"), texturePath))
{
iAnim != iAnimEnd;
++iAnim)
{
- const TreeNode& tnAnim = (*iAnim).second;
- uint32_t animationPropertyIndex = 0;
+ const TreeNode& tnAnim = (*iAnim).second;
+ uint32_t animationPropertyIndex = 0;
AnimationDefinition animDef;
- std::string animationName;
+ std::string animationName;
ReadString(tnAnim.GetChild(NAME), animationName);
animDef.SetName(animationName);
return ALPHA_MODE_TYPES;
}
-const std::map<std::string_view, Attribute::Type>& GetAttributeTypes()
-{
- static const std::map<std::string_view, Attribute::Type> ATTRIBUTE_TYPES{
- ENUM_STRING_MAPPING(Attribute::Type, POSITION),
- ENUM_STRING_MAPPING(Attribute::Type, NORMAL),
- ENUM_STRING_MAPPING(Attribute::Type, TANGENT),
- ENUM_STRING_MAPPING(Attribute::Type, TEXCOORD_0),
- ENUM_STRING_MAPPING(Attribute::Type, TEXCOORD_1),
- ENUM_STRING_MAPPING(Attribute::Type, COLOR_0),
- ENUM_STRING_MAPPING(Attribute::Type, JOINTS_0),
- ENUM_STRING_MAPPING(Attribute::Type, WEIGHTS_0),
- };
- return ATTRIBUTE_TYPES;
-}
-
const std::map<std::string_view, Animation::Sampler::Interpolation::Type>& GetAnimationSamplerInterpolation()
{
static const std::map<std::string_view, Animation::Sampler::Interpolation::Type> ANIMATION_SAMPLER_INTERPOLATION{
ENUM_TYPE_FROM_STRING(AccessorType, GetAccessorTypes())
ENUM_TYPE_FROM_STRING(AlphaMode, GetAlphaModeTypes())
-ENUM_TYPE_FROM_STRING(Attribute, GetAttributeTypes())
ENUM_TYPE_FROM_STRING(Animation::Sampler::Interpolation, GetAnimationSamplerInterpolation())
ENUM_TYPE_FROM_STRING(Animation::Channel::Target, GetAnimationChannelTargetPathTypes())
+const std::map<std::string_view, Attribute::Type>& GetTargetTypes()
+{
+ static const std::map<std::string_view, Attribute::Type> TARGET_TYPES{
+ ENUM_STRING_MAPPING(Attribute::Type, POSITION),
+ ENUM_STRING_MAPPING(Attribute::Type, TANGENT),
+ ENUM_STRING_MAPPING(Attribute::Type, NORMAL),
+ };
+ return TARGET_TYPES;
+}
+
+const std::map<Attribute::Type, const char*>& GetAttributeSetTypes()
+{
+ static const std::map<Attribute::Type, const char*> ATTRIBUTE_SET_TYPES{
+ {Attribute::Type::TEXCOORD_N, "TEXCOORD_%u"},
+ {Attribute::Type::COLOR_N, "COLOR_%u"},
+ {Attribute::Type::JOINTS_N, "JOINTS_%u"},
+ {Attribute::Type::WEIGHTS_N, "WEIGHTS_%u"},
+ };
+ return ATTRIBUTE_SET_TYPES;
+}
+
+uint32_t Attribute::HashFromString(const char* token, size_t length)
+{
+ auto& table1 = GetTargetTypes();
+ auto& table2 = GetAttributeSetTypes();
+
+ std::string target(token, length);
+ std::transform(target.begin(), target.end(), target.begin(), ::toupper);
+
+ auto iFind = table1.find(std::string_view(target.c_str(), length));
+ if(iFind != table1.end())
+ {
+ return Attribute::ToHash(iFind->second, false, 0);
+ }
+
+ uint32_t hash = Attribute::ToHash(Attribute::INVALID, false, 0);
+ for(const auto& [key, match] : table2)
+ {
+ int setIndex;
+ if(sscanf(target.c_str(), match, &setIndex) > 0)
+ {
+ hash = Attribute::ToHash(key, true, setIndex);
+ break;
+ }
+ }
+ return hash;
+}
+
+Attribute::Type Attribute::TargetFromString(const char* token, size_t length)
+{
+ std::string target(token, length);
+ std::transform(target.begin(), target.end(), target.begin(), ::toupper);
+
+ auto iFind = GetTargetTypes().find(std::string_view(target.c_str(), length));
+ if(iFind != GetTargetTypes().end())
+ {
+ return iFind->second;
+ }
+ return Attribute::INVALID;
+}
+
bool Component::IsUnsigned(Type t)
{
return t == UNSIGNED_BYTE || t == UNSIGNED_SHORT || t == UNSIGNED_INT;
// INTERNAL INCLUDES
#include <dali-scene3d/internal/loader/json-reader.h>
#include <dali-scene3d/public-api/loader/index.h>
+#include <dali-scene3d/public-api/loader/utils.h>
#define ENUM_STRING_MAPPING(t, x) \
{ \
POSITION,
NORMAL,
TANGENT,
- TEXCOORD_0,
- TEXCOORD_1,
- COLOR_0,
- JOINTS_0,
- WEIGHTS_0,
+ TEXCOORD_N,
+ COLOR_N,
+ JOINTS_N,
+ WEIGHTS_N,
INVALID
};
- static Type FromString(const char* s, size_t len);
+ using HashType = uint32_t;
+
+ // Hash bit layout
+ // +--+--+--+--+--+--+--+
+ // |31|30|29|28|27|..| 0| bit index
+ // +--+--+--+--+--+--+--+
+ // \_/ - Set is used
+ // \______/ - Type enum
+ // \_______/ - Set ID
+ static const HashType SET_SHIFT{31};
+ static const HashType TYPE_SHIFT{28};
+ static const HashType SET_MASK{0x01u << SET_SHIFT};
+ static const HashType TYPE_MASK{0x07 << TYPE_SHIFT};
+ static const HashType SET_ID_MASK{0x0fffffff};
+
+ static HashType ToHash(Type type, bool set, HashType setIndex)
+ {
+ return ((set << SET_SHIFT) & SET_MASK) | ((static_cast<HashType>(type) << TYPE_SHIFT) & TYPE_MASK) | (setIndex & SET_ID_MASK);
+ }
+
+ static Attribute::Type TypeFromHash(HashType hash)
+ {
+ return static_cast<Type>((hash & TYPE_MASK) >> TYPE_SHIFT);
+ }
+
+ static bool SetFromHash(HashType hash)
+ {
+ return (hash & SET_SHIFT) != 0;
+ }
+
+ static HashType SetIdFromHash(HashType hash)
+ {
+ return (hash & SET_ID_MASK);
+ }
+
+ /**
+ * Convert to Type + setIndex, where setIndex is N for that attr, e.g. "JOINTS_1" => {JOINTS_N, 1}
+ */
+ static HashType HashFromString(const char* s, size_t len);
+
+ /**
+ * Convert to type only, there is no set for POSITION, NORMALS or TANGENT.
+ */
+ static Attribute::Type TargetFromString(const char* s, size_t len);
Attribute() = delete;
};
INVALID
};
- std::map<Attribute::Type, Ref<Accessor>> mAttributes;
+ std::map<Attribute::HashType, Ref<Accessor>> mAttributes;
std::vector<std::map<Attribute::Type, Ref<Accessor>>> mTargets;
Ref<Accessor> mIndices;
Ref<Material> mMaterial;
std::vector<Ref<Node>> mNodes;
};
+enum ExtensionFlags : uint32_t
+{
+ NONE = Dali::Scene3D::Loader::NthBit(0),
+ KHR_MESH_QUANTIZATION = Dali::Scene3D::Loader::NthBit(1), // See https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_texture_transform
+ KHR_TEXTURE_TRANSFORM = Dali::Scene3D::Loader::NthBit(2), // See https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_mesh_quantization
+ KHR_MATERIALS_IOR = Dali::Scene3D::Loader::NthBit(3), // See https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_ior
+ KHR_MATERIALS_SPECULAR = Dali::Scene3D::Loader::NthBit(4), // See https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_specular
+
+};
+
struct Document
{
Asset mAsset;
std::vector<Animation> mAnimations;
+ std::vector<std::string_view> mExtensionsUsed;
+ std::vector<std::string_view> mExtensionsRequired;
+
+ uint32_t mExtensionFlags{0};
+
std::vector<Scene> mScenes;
Ref<Scene> mScene;
#include <dali-scene3d/internal/loader/gltf2-util.h>
// EXTERNAL INCLUDES
+#include <dali-scene3d/public-api/loader/utils.h>
+#include <dali/devel-api/scripting/scripting.h>
#include <dali/devel-api/threading/mutex.h>
#include <dali/integration-api/debug.h>
#include <limits> ///< for std::numeric_limits
Geometry::TRIANGLE_STRIP,
Geometry::TRIANGLE_FAN}; //...because Dali swaps the last two.
-static struct AttributeMapping
-{
- gltf2::Attribute::Type mType;
- MeshDefinition::Accessor MeshDefinition::*mAccessor;
- uint16_t mElementSizeRequired;
-} ATTRIBUTE_MAPPINGS[]{
- {gltf2::Attribute::NORMAL, &MeshDefinition::mNormals, sizeof(Vector3)},
- {gltf2::Attribute::TANGENT, &MeshDefinition::mTangents, sizeof(Vector3)},
- {gltf2::Attribute::TEXCOORD_0, &MeshDefinition::mTexCoords, sizeof(Vector2)},
- {gltf2::Attribute::COLOR_0, &MeshDefinition::mColors, sizeof(Vector4)},
- {gltf2::Attribute::JOINTS_0, &MeshDefinition::mJoints0, sizeof(Vector4)},
- {gltf2::Attribute::WEIGHTS_0, &MeshDefinition::mWeights0, sizeof(Vector4)},
+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},
};
+static const unsigned int EXTENSION_STRING_TABLE_COUNT = sizeof(EXTENSION_STRING_TABLE) / sizeof(EXTENSION_STRING_TABLE[0]);
std::vector<gltf2::Animation> ReadAnimationArray(const json_value_s& j)
{
.Register(*new json::Property<gltf2::Accessor, gltf2::Ref<gltf2::BufferView>>("bufferView",
gltf2::RefReader<gltf2::Document>::Read<gltf2::BufferView, &gltf2::Document::mBufferViews>,
&gltf2::Accessor::mBufferView))
- .Register(*new json::Property<gltf2::Accessor, uint32_t>("byteOffset",
- json::Read::Number<uint32_t>,
- &gltf2::Accessor::mByteOffset))
+ .Register(*new json::Property<gltf2::Accessor, uint32_t>("byteOffset", json::Read::Number<uint32_t>, &gltf2::Accessor::mByteOffset))
.Register(*new json::Property<gltf2::Accessor, gltf2::Component::Type>("componentType",
json::Read::Enum<gltf2::Component::Type>,
&gltf2::Accessor::mComponentType))
return MATERIAL_READER;
}
-std::map<gltf2::Attribute::Type, gltf2::Ref<gltf2::Accessor>> ReadMeshPrimitiveAttributes(const json_value_s& j)
+std::map<gltf2::Attribute::HashType, gltf2::Ref<gltf2::Accessor>> ReadMeshPrimitiveAttributes(const json_value_s& j)
+{
+ auto& jsonObject = json::Cast<json_object_s>(j);
+ std::map<gltf2::Attribute::HashType, gltf2::Ref<gltf2::Accessor>> result;
+
+ auto element = jsonObject.start;
+ while(element)
+ {
+ auto jsonString = *element->name;
+
+ gltf2::Attribute::HashType hash = gltf2::Attribute::HashFromString(jsonString.string, jsonString.string_size);
+
+ result[hash] =
+ gltf2::RefReader<gltf2::Document>::Read<gltf2::Accessor, &gltf2::Document::mAccessors>(*element->value);
+ element = element->next;
+ }
+ return result;
+}
+
+std::map<gltf2::Attribute::Type, gltf2::Ref<gltf2::Accessor>> ReadMeshPrimitiveAttributes2(const json_value_s& j)
{
auto& jsonObject = json::Cast<json_object_s>(j);
std::map<gltf2::Attribute::Type, gltf2::Ref<gltf2::Accessor>> result;
auto element = jsonObject.start;
while(element)
{
- auto jsonString = *element->name;
- result[gltf2::Attribute::FromString(jsonString.string, jsonString.string_size)] = gltf2::RefReader<gltf2::Document>::Read<gltf2::Accessor, &gltf2::Document::mAccessors>(*element->value);
- element = element->next;
+ auto jsonString = *element->name;
+
+ result[gltf2::Attribute::TargetFromString(jsonString.string, jsonString.string_size)] = gltf2::RefReader<gltf2::Document>::Read<gltf2::Accessor, &gltf2::Document::mAccessors>(*element->value);
+
+ element = element->next;
}
return result;
}
auto element = jsonObject.start;
while(element)
{
- result.push_back(std::move(ReadMeshPrimitiveAttributes(*element->value)));
+ result.push_back(std::move(ReadMeshPrimitiveAttributes2(*element->value)));
element = element->next;
}
.Register(*json::MakeProperty("animations",
ReadAnimationArray,
&gltf2::Document::mAnimations))
+ .Register(*json::MakeProperty("extensionsRequired",
+ json::Read::Array<std::string_view, json::Read::StringView>,
+ &gltf2::Document::mExtensionsRequired))
+ .Register(*json::MakeProperty("extensionsUsed",
+ json::Read::Array<std::string_view, json::Read::StringView>,
+ &gltf2::Document::mExtensionsUsed))
.Register(*json::MakeProperty("scenes",
json::Read::Array<gltf2::Scene, json::ObjectReader<gltf2::Scene>::Read>,
&gltf2::Document::mScenes))
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.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::Accessor* accessorDest{nullptr};
+
+ switch(gltf2::Attribute::TypeFromHash(attributeHash))
+ {
+ case gltf2::Attribute::POSITION:
+ {
+ accessorDest = &meshDefinition.mPositions;
+ break;
+ }
+ case gltf2::Attribute::NORMAL:
+ {
+ accessorDest = &meshDefinition.mNormals;
+ needNormals = false;
+ break;
+ }
+ case gltf2::Attribute::TANGENT:
+ {
+ accessorDest = &meshDefinition.mTangents;
+ needTangents = false;
+ break;
+ }
+ case gltf2::Attribute::TEXCOORD_N:
+ {
+ meshDefinition.mTexCoords.emplace_back(MeshDefinition::Accessor{});
+ accessorDest = &meshDefinition.mTexCoords.back();
+ break;
+ }
+ case gltf2::Attribute::COLOR_N:
+ {
+ meshDefinition.mColors.emplace_back(MeshDefinition::Accessor{});
+ accessorDest = &meshDefinition.mColors.back();
+ break;
+ }
+ case gltf2::Attribute::JOINTS_N:
+ {
+ if(meshDefinition.mJoints.size() < MeshDefinition::MAX_NUMBER_OF_JOINT_SETS)
+ {
+ meshDefinition.mJoints.emplace_back(MeshDefinition::Accessor{});
+ accessorDest = &meshDefinition.mJoints.back();
+ }
+ break;
+ }
+ case gltf2::Attribute::WEIGHTS_N:
+ {
+ if(meshDefinition.mWeights.size() < MeshDefinition::MAX_NUMBER_OF_JOINT_SETS)
+ {
+ meshDefinition.mWeights.emplace_back(MeshDefinition::Accessor{});
+ accessorDest = &meshDefinition.mWeights.back();
+ }
+ break;
+ }
+ case gltf2::Attribute::INVALID:
+ {
+ accessorDest = nullptr;
+ break;
+ }
+ }
+ return accessorDest;
+}
+
+void SetFlagsFromComponentType(const gltf2::Accessor& accessor,
+ gltf2::Attribute::HashType attributeHash,
+ MeshDefinition& meshDefinition,
+ bool isQuantized)
+{
+ switch(gltf2::Attribute::TypeFromHash(attributeHash))
+ {
+ case gltf2::Attribute::POSITION:
+ {
+ if(isQuantized)
+ {
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_POSITION;
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_POSITION;
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_POSITION;
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_POSITION;
+ }
+ DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_POSITION) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_POSITION) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_POSITION) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_POSITION))) || accessor.mComponentType == gltf2::Component::FLOAT);
+ break;
+ }
+ case gltf2::Attribute::NORMAL:
+ {
+ if(isQuantized)
+ {
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_NORMAL;
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_NORMAL;
+ }
+
+ DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_NORMAL) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_NORMAL))) || accessor.mComponentType == gltf2::Component::FLOAT);
+ break;
+ }
+ case gltf2::Attribute::TANGENT:
+ {
+ if(isQuantized)
+ {
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_TANGENT;
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_TANGENT;
+ }
+
+ DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_TANGENT) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_TANGENT))) || accessor.mComponentType == gltf2::Component::FLOAT);
+ break;
+ }
+ case gltf2::Attribute::TEXCOORD_N:
+ {
+ if(isQuantized)
+ {
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_TEXCOORD;
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_TEXCOORD;
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_TEXCOORD;
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_TEXCOORD;
+ }
+ DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_TEXCOORD) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_TEXCOORD) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_TEXCOORD) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_TEXCOORD))) || accessor.mComponentType == gltf2::Component::FLOAT);
+ break;
+ }
+ case gltf2::Attribute::COLOR_N:
+ {
+ break;
+ }
+ case gltf2::Attribute::JOINTS_N:
+ {
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_JOINT_IDS;
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_JOINT_IDS;
+ DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_JOINT_IDS) ||
+ MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_JOINT_IDS) ||
+ accessor.mComponentType == gltf2::Component::FLOAT);
+ break;
+ }
+ case gltf2::Attribute::WEIGHTS_N:
+ {
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_WEIGHT;
+ meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_WEIGHT;
+ DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_WEIGHT) ||
+ MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_WEIGHT) ||
+ accessor.mComponentType == gltf2::Component::FLOAT);
+
+ break;
+ }
+ case gltf2::Attribute::INVALID:
+ {
+ break;
+ }
+ }
}
void ConvertMeshes(const gltf2::Document& document, ConversionContext& context)
{
+ bool isQuantized = MaskMatch(document.mExtensionFlags, gltf2::ExtensionFlags::KHR_MESH_QUANTIZATION);
+
uint32_t meshCount = 0;
context.mMeshIds.reserve(document.mMeshes.size());
for(auto& mesh : document.mMeshes)
auto& attribs = primitive.mAttributes;
meshDefinition.mPrimitiveType = GLTF2_TO_DALI_PRIMITIVES[primitive.mMode];
- auto positionIter = attribs.find(gltf2::Attribute::POSITION);
-
+ auto positionIter = attribs.find(gltf2::Attribute::ToHash(gltf2::Attribute::POSITION, false, 0));
if(positionIter == attribs.end())
{
DALI_LOG_ERROR("Primitive mesh dosn't have POSITION atrributes!");
continue;
}
- auto& accPositions = *positionIter->second;
- meshDefinition.mPositions = ConvertMeshPrimitiveAccessor(accPositions);
+ auto& positionsAccessor = *positionIter->second;
+
// glTF2 support vector4 tangent for mesh.
// https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#meshes-overview
meshDefinition.mTangentType = Property::VECTOR4;
- const bool needNormalsTangents = accPositions.mType == gltf2::AccessorType::VEC3;
- for(auto& attributeMapping : ATTRIBUTE_MAPPINGS)
+ bool needNormals = (positionsAccessor.mType == gltf2::AccessorType::VEC3);
+ bool needTangents = (positionsAccessor.mType == gltf2::AccessorType::VEC3);
+
+ for(const auto& [attributeHash, accessor] : attribs)
{
- auto iFind = attribs.find(attributeMapping.mType);
- if(iFind != attribs.end())
+ MeshDefinition::Accessor* accessorDest = GetAccessorFromAttribute(attributeHash, meshDefinition, needNormals, needTangents);
+ if(accessorDest == nullptr)
{
- auto& accessor = meshDefinition.*(attributeMapping.mAccessor);
- accessor = ConvertMeshPrimitiveAccessor(*iFind->second);
-
- if(iFind->first == gltf2::Attribute::JOINTS_0)
- {
- meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_JOINT_IDS;
- meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_JOINT_IDS;
- DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_JOINT_IDS) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_JOINT_IDS) || iFind->second->mComponentType == gltf2::Component::FLOAT);
- }
- if(iFind->first == gltf2::Attribute::WEIGHTS_0)
- {
- meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_WEIGHT;
- meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_WEIGHT;
- DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_WEIGHT) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_WEIGHT) || iFind->second->mComponentType == gltf2::Component::FLOAT);
- }
+ continue;
}
- else if(needNormalsTangents)
- {
- switch(attributeMapping.mType)
- {
- case gltf2::Attribute::NORMAL:
- meshDefinition.RequestNormals();
- break;
-
- case gltf2::Attribute::TANGENT:
- meshDefinition.RequestTangents();
- break;
+ *accessorDest = ConvertMeshPrimitiveAccessor(*accessor);
+ SetFlagsFromComponentType(*accessor, attributeHash, meshDefinition, isQuantized);
+ }
- default:
- break;
- }
- }
+ if(needNormals)
+ {
+ meshDefinition.RequestNormals();
+ }
+ if(needTangents)
+ {
+ meshDefinition.RequestTangents();
}
if(primitive.mIndices)
auto it = target.find(gltf2::Attribute::POSITION);
if(it != endIt)
{
- blendShape.deltas = ConvertMeshPrimitiveAccessor(*it->second);
+ blendShape.deltas = ConvertMeshPrimitiveAccessor(*it->second);
+ blendShape.deltas.mNormalized = it->second->mNormalized;
+
+ if(isQuantized)
+ {
+ blendShape.mFlags |= (it->second->mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_POSITION;
+ blendShape.mFlags |= (it->second->mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_POSITION;
+ }
+
+ DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(blendShape.mFlags, MeshDefinition::S8_POSITION) || MaskMatch(blendShape.mFlags, MeshDefinition::U8_POSITION) || MaskMatch(blendShape.mFlags, MeshDefinition::S16_POSITION) || MaskMatch(blendShape.mFlags, MeshDefinition::U16_POSITION))) || it->second->mComponentType == gltf2::Component::FLOAT);
}
it = target.find(gltf2::Attribute::NORMAL);
if(it != endIt)
{
- blendShape.normals = ConvertMeshPrimitiveAccessor(*it->second);
+ blendShape.normals = ConvertMeshPrimitiveAccessor(*it->second);
+ blendShape.normals.mNormalized = it->second->mNormalized;
+
+ if(isQuantized)
+ {
+ blendShape.mFlags |= (it->second->mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_NORMAL;
+ blendShape.mFlags |= (it->second->mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_NORMAL;
+ }
+
+ DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(blendShape.mFlags, MeshDefinition::S8_NORMAL) || MaskMatch(blendShape.mFlags, MeshDefinition::S16_NORMAL))) || it->second->mComponentType == gltf2::Component::FLOAT);
}
it = target.find(gltf2::Attribute::TANGENT);
if(it != endIt)
{
- blendShape.tangents = ConvertMeshPrimitiveAccessor(*it->second);
+ blendShape.tangents = ConvertMeshPrimitiveAccessor(*it->second);
+ blendShape.tangents.mNormalized = it->second->mNormalized;
+
+ if(isQuantized)
+ {
+ blendShape.mFlags |= (it->second->mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_TANGENT;
+ blendShape.mFlags |= (it->second->mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_TANGENT;
+ }
+
+ DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(blendShape.mFlags, MeshDefinition::S8_TANGENT) || MaskMatch(blendShape.mFlags, MeshDefinition::S16_TANGENT))) || it->second->mComponentType == gltf2::Component::FLOAT);
}
if(!mesh.mWeights.empty())
void ConvertGltfToContext(gt::Document& document, Gltf2Util::ConversionContext& context, bool isMRendererModel)
{
+ for(auto& extension : document.mExtensionsRequired)
+ {
+ gltf2::ExtensionFlags flag;
+ if(Dali::Scripting::GetEnumeration<gltf2::ExtensionFlags>(extension.data(), EXTENSION_STRING_TABLE, EXTENSION_STRING_TABLE_COUNT, flag))
+ {
+ document.mExtensionFlags |= flag;
+ }
+ else
+ {
+ DALI_LOG_ERROR("Unsupported glTF extension required: %s\n", extension.data());
+ DALI_ASSERT_DEBUG(false && "Unsupported glTF extension required");
+ }
+ }
+
Gltf2Util::ConvertBuffers(document, context);
Gltf2Util::ConvertMaterials(document, context);
Gltf2Util::ConvertMeshes(document, context);
return static_cast<uint32_t>(mModelPrimitiveContainer.size());
}
-void ModelNode::AddModelPrimitive(Dali::Scene3D::ModelPrimitive modelPrimitive)
+void ModelNode::AddModelPrimitive(Dali::Scene3D::ModelPrimitive modelPrimitive, Loader::ShaderOption::HashType hash)
{
for(auto&& primitive : mModelPrimitiveContainer)
{
GetImplementation(modelPrimitive).SetImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor, mSpecularMipmapLevels);
}
- GetImplementation(modelPrimitive).UpdateShader(mShaderManager);
+ GetImplementation(modelPrimitive).UpdateShader(mShaderManager, hash);
Dali::Renderer renderer = GetImplementation(modelPrimitive).GetRenderer();
if(renderer)
return;
}
- GetImplementation(mModelPrimitiveContainer[index]).UpdateShader(nullptr);
+ GetImplementation(mModelPrimitiveContainer[index]).UpdateShader(nullptr, 0u);
Actor self = Self();
GetImplementation(mModelPrimitiveContainer[index]).RemovePrimitiveObserver(this);
mShaderManager = shaderManager;
for(auto&& primitive : mModelPrimitiveContainer)
{
- GetImplementation(primitive).UpdateShader(mShaderManager);
+ GetImplementation(primitive).UpdateShader(mShaderManager, 0u);
}
}
}
#include <dali-scene3d/public-api/light/light.h>
#include <dali-scene3d/public-api/loader/mesh-definition.h>
#include <dali-scene3d/public-api/loader/shader-manager.h>
+#include <dali-scene3d/public-api/loader/shader-option.h>
#include <dali-scene3d/public-api/loader/skinning-details.h>
#include <dali-scene3d/public-api/model-components/model-node.h>
#include <dali-scene3d/public-api/model-components/model-primitive.h>
/**
* @copydoc Dali::Scene3D::ModelNode::AddModelPrimitive()
*/
- void AddModelPrimitive(Dali::Scene3D::ModelPrimitive modelPrimitive);
+ void AddModelPrimitive(Dali::Scene3D::ModelPrimitive modelPrimitive, Loader::ShaderOption::HashType hash);
/**
* @copydoc Dali::Scene3D::ModelNode::RemoveModelPrimitive(Dali::Scene3D::ModelPrimitive modelPrimitive)
Scene3D::Loader::ShaderManagerPtr mShaderManager;
ModelPrimitiveContainer mModelPrimitiveContainer; ///< List of model primitives
BoneDataContainer mBoneDataContainer;
- BlendShapeIndexMap mBlendShapeIndexMap; ///< Index of blend shape by name
+ BlendShapeIndexMap mBlendShapeIndexMap; ///< Index of blend shape by name
Dali::Texture mShadowMapTexture;
Dali::Texture mSpecularTexture;
Dali::Texture mDiffuseTexture;
#include <dali-scene3d/public-api/loader/environment-definition.h>
#include <dali/integration-api/debug.h>
+#include <dali/public-api/object/property-array.h>
+#include <dali/public-api/object/property-map.h>
+
+#if defined(DEBUG_ENABLED)
+#include <sys/types.h>
+#include <unistd.h>
+#include <filesystem>
+namespace fs = std::filesystem;
+#endif
namespace Dali
{
{
namespace
{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_SCENE3D_MODEL_PRIMITIVE");
+
+std::string tmpFilename(std::string prefix, std::string suffix)
+{
+ static int id = 0;
+ id++;
+ std::ostringstream oss;
+ oss << prefix << getpid() << "_" << std::setfill('0') << std::setw(4) << id << suffix;
+ return oss.str();
+}
+
+#define DALI_LOG_WRITE_FILE(filename, stream) \
+ { \
+ fs::path tmp = fs::temp_directory_path(); \
+ tmp /= filename; \
+ std::ofstream ostrm(tmp, std::ios::out); \
+ ostrm << stream; \
+ ostrm.flush(); \
+ }
+
+inline Property::Map GetMap(Shader shader)
+{
+ Property::Value program = shader[Shader::Property::PROGRAM];
+ Property::Map* map{nullptr};
+ if(program.GetType() == Property::ARRAY)
+ {
+ Property::Array* array = program.GetArray();
+ if(array)
+ {
+ Property::Value& value = array->GetElementAt(0);
+ if(value.GetType() == Property::MAP)
+ {
+ map = value.GetMap();
+ }
+ }
+ }
+ else if(program.GetType() == Property::MAP)
+ {
+ map = program.GetMap();
+ }
+ if(map)
+ {
+ return *map;
+ }
+ return Property::Map();
+}
+
+#endif
/**
* Creates control through type registry
*/
}
}
-void ModelPrimitive::UpdateShader(Scene3D::Loader::ShaderManagerPtr shaderManager)
+void ModelPrimitive::UpdateShader(Scene3D::Loader::ShaderManagerPtr shaderManager, Loader::ShaderOption::HashType hash)
{
if(mShaderManager != shaderManager)
{
mShaderManager = (shaderManager) ? shaderManager : new Scene3D::Loader::ShaderManager();
if(mMaterial && GetImplementation(mMaterial).IsResourceReady())
{
- ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag::SHADER);
+ ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag::SHADER, hash);
}
}
}
mBlendShapeVersion = version;
}
-void ModelPrimitive::SetSkinned(bool isSkinned)
+void ModelPrimitive::SetSkinned(bool isSkinned, uint32_t numberOfJointSets)
{
- mHasSkinning = isSkinned;
+ mHasSkinning = isSkinned;
+ mNumberOfJointSets = numberOfJointSets;
+}
+
+void ModelPrimitive::SetVertexColor(bool hasVertexColor)
+{
+ mHasVertexColor = hasVertexColor;
}
// From MaterialModifyObserver
ApplyMaterialToRenderer(flag);
}
-void ModelPrimitive::ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag flag)
+void ModelPrimitive::ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag flag, Loader::ShaderOption::HashType oldHash)
{
if(!mMaterial)
{
if(mHasSkinning)
{
shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::SKINNING);
+ shaderOption.AddJointMacros(mNumberOfJointSets);
+ }
+ if(mHasVertexColor)
+ {
+ shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::COLOR_ATTRIBUTE);
}
if(mHasPositions || mHasNormals || mHasTangents)
{
}
}
- mShader.Reset();
- mShader = mShaderManager->ProduceShader(shaderOption);
+ Shader newShader = mShaderManager->ProduceShader(shaderOption);
+ if(mShader != newShader)
+ {
+ DALI_LOG_INFO(gLogFilter, Debug::General, "Warning! Model primitive shader changed: OldHash:%x NewHash:%x\n", oldHash, shaderOption.GetOptionHash());
+
+#if defined(DEBUG_ENABLED)
+ if(mShader)
+ {
+ Property::Map oldMap = GetMap(mShader);
+ DALI_LOG_WRITE_FILE(tmpFilename("oldShader", ".txt"), "Vertex Shader:\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");
+ }
+#endif
+ }
+ mShader = newShader;
if(!mRenderer)
{
* @brief Updates shaders by using current material
*
* @param[in] shaderManager Shader manager to create shader.
+ * @param[in] hash of old shader option
*/
- void UpdateShader(Scene3D::Loader::ShaderManagerPtr shaderManager);
+ void UpdateShader(Scene3D::Loader::ShaderManagerPtr shaderManager, Loader::ShaderOption::HashType hash);
/**
* @brief Sets the blend shape data for this model primitive.
* @brief Sets whether or not this model primitive is skinned.
*
* @param[in] isSkinned Whether or not this model primitive is skinned.
+ * @param[in] numberOfJointSets How many joint sets the mesh expects in the shader
*/
- void SetSkinned(bool isSkinned);
+ void SetSkinned(bool isSkinned, uint32_t numberOfJointSets);
+
+ /**
+ * @brief Set whether this model primitve has vertex color attributes
+ *
+ * @param[in] hasVertexColor Whether or not this model primitive has vertex color attributes
+ */
+ void SetVertexColor(bool hasVertexColor);
private: // From MaterialModifyObserver
/**
/**
* @brief Apply materials data into renderer.
*/
- void ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag flag = MaterialModifyObserver::ModifyFlag::NONE);
+ void ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag flag = MaterialModifyObserver::ModifyFlag::NONE,
+ Loader::ShaderOption::HashType oldHash = 0u);
/**
* @brief Updates the uniform of renderer.
private:
// Delete copy & move operator
- ModelPrimitive(const ModelPrimitive&) = delete;
- ModelPrimitive(ModelPrimitive&&) = delete;
- ModelPrimitive& operator=(const ModelPrimitive& rhs) = delete;
+ ModelPrimitive(const ModelPrimitive&) = delete;
+ ModelPrimitive(ModelPrimitive&&) = delete;
+ ModelPrimitive& operator=(const ModelPrimitive& rhs) = delete;
ModelPrimitive& operator=(ModelPrimitive&& rhs) noexcept = delete;
private:
float mIblScaleFactor{1.0f};
uint32_t mSpecularMipmapLevels{1u};
+ // For skinning
+ uint32_t mNumberOfJointSets{0};
+
// For blend shape
Scene3D::Loader::BlendShapes::BlendShapeData mBlendShapeData;
Dali::Texture mBlendShapeGeometry;
bool mHasSkinning = false;
+ bool mHasVertexColor = false;
bool mHasPositions = false;
bool mHasNormals = false;
bool mHasTangents = false;
}
template<typename T>
-void ReadJointAccessor(MeshDefinition::RawData& raw, const MeshDefinition::Accessor& accessor, std::istream& source, const std::string& meshPath)
+void ReadJointAccessor(MeshDefinition::RawData& raw, const MeshDefinition::Accessor& accessor, std::istream& source, const std::string& meshPath, const std::string& name)
{
constexpr auto sizeofBlobUnit = sizeof(T) * 4;
++floats;
}
}
- raw.mAttribs.push_back({"aJoints", Property::VECTOR4, static_cast<uint32_t>(outBufferSize / sizeof(Vector4)), std::move(buffer)});
+ 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)
+void ReadWeightAccessor(MeshDefinition::RawData& raw, const MeshDefinition::Accessor& accessor, std::istream& source, const std::string& meshPath, const std::string& name)
{
constexpr auto sizeofBlobUnit = sizeof(T) * 4;
++floats;
}
}
- raw.mAttribs.push_back({"aWeights", Property::VECTOR4, static_cast<uint32_t>(outBufferSize / sizeof(Vector4)), std::move(buffer)});
+ 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);
+ }
}
template<bool use32BitsIndices, typename IndexProviderType = IndexProvider<use32BitsIndices>>
textureHeight = 1u << powHeight;
}
-void CalculateGltf2BlendShapes(uint8_t* geometryBuffer, const std::vector<MeshDefinition::BlendShape>& blendShapes, uint32_t numberOfVertices, float& blendShapeUnnormalizeFactor, BufferDefinition::Vector& buffers)
+template<typename T>
+float GetNormalizedScale()
+{
+ return 1.0f / (std::numeric_limits<T>::max());
+}
+
+template<typename T>
+void DequantizeData(std::vector<uint8_t>& buffer, float* dequantizedValues, uint32_t numValues, bool normalized)
+{
+ // see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_mesh_quantization#encoding-quantized-data
+
+ T* values = reinterpret_cast<T*>(buffer.data());
+
+ for(uint32_t i = 0; i < numValues; ++i)
+ {
+ *dequantizedValues = normalized ? std::max((*values) * GetNormalizedScale<T>(), -1.0f) : *values;
+
+ values++;
+ dequantizedValues++;
+ }
+}
+
+void GetDequantizedData(std::vector<uint8_t>& buffer, uint32_t numComponents, uint32_t count, uint32_t flags, bool normalized)
+{
+ bool dequantized = false;
+
+ std::vector<uint8_t> dequantizedBuffer(count * numComponents * sizeof(float));
+ float* dequantizedValues = reinterpret_cast<float*>(dequantizedBuffer.data());
+
+ if(MaskMatch(flags, MeshDefinition::Flags::S8_POSITION) || MaskMatch(flags, MeshDefinition::Flags::S8_NORMAL) || MaskMatch(flags, MeshDefinition::Flags::S8_TANGENT) || MaskMatch(flags, MeshDefinition::Flags::S8_TEXCOORD))
+ {
+ DequantizeData<int8_t>(buffer, dequantizedValues, numComponents * count, normalized);
+ dequantized = true;
+ }
+ else if(MaskMatch(flags, MeshDefinition::Flags::U8_POSITION) || MaskMatch(flags, MeshDefinition::Flags::U8_TEXCOORD))
+ {
+ DequantizeData<uint8_t>(buffer, dequantizedValues, numComponents * count, normalized);
+ dequantized = true;
+ }
+ else if(MaskMatch(flags, MeshDefinition::Flags::S16_POSITION) || MaskMatch(flags, MeshDefinition::Flags::S16_NORMAL) || MaskMatch(flags, MeshDefinition::Flags::S16_TANGENT) || MaskMatch(flags, MeshDefinition::Flags::S16_TEXCOORD))
+ {
+ DequantizeData<int16_t>(buffer, dequantizedValues, numComponents * count, normalized);
+ dequantized = true;
+ }
+ else if(MaskMatch(flags, MeshDefinition::Flags::U16_POSITION) || MaskMatch(flags, MeshDefinition::Flags::U16_TEXCOORD))
+ {
+ DequantizeData<uint16_t>(buffer, dequantizedValues, numComponents * count, normalized);
+ dequantized = true;
+ }
+
+ if(dequantized)
+ {
+ buffer = std::move(dequantizedBuffer);
+ }
+}
+
+void GetDequantizedMinMax(std::vector<float>& min, std::vector<float>& max, uint32_t flags)
+{
+ float scale = 1.0f;
+
+ if(MaskMatch(flags, MeshDefinition::Flags::S8_POSITION) || MaskMatch(flags, MeshDefinition::Flags::S8_NORMAL) || MaskMatch(flags, MeshDefinition::Flags::S8_TANGENT) || MaskMatch(flags, MeshDefinition::Flags::S8_TEXCOORD))
+ {
+ scale = GetNormalizedScale<int8_t>();
+ }
+ else if(MaskMatch(flags, MeshDefinition::Flags::U8_POSITION) || MaskMatch(flags, MeshDefinition::Flags::U8_TEXCOORD))
+ {
+ scale = GetNormalizedScale<uint8_t>();
+ }
+ else if(MaskMatch(flags, MeshDefinition::Flags::S16_POSITION) || MaskMatch(flags, MeshDefinition::Flags::S16_NORMAL) || MaskMatch(flags, MeshDefinition::Flags::S16_TANGENT) || MaskMatch(flags, MeshDefinition::Flags::S16_TEXCOORD))
+ {
+ scale = GetNormalizedScale<int16_t>();
+ }
+ else if(MaskMatch(flags, MeshDefinition::Flags::U16_POSITION) || MaskMatch(flags, MeshDefinition::Flags::U16_TEXCOORD))
+ {
+ scale = GetNormalizedScale<uint16_t>();
+ }
+
+ if(scale != 1.0f)
+ {
+ for(float& value : min)
+ {
+ value = std::max(value * scale, -1.0f);
+ }
+
+ for(float& value : max)
+ {
+ value = std::min(value * scale, 1.0f);
+ }
+ }
+}
+
+void CalculateGltf2BlendShapes(uint8_t* geometryBuffer, std::vector<MeshDefinition::BlendShape>& blendShapes, uint32_t numberOfVertices, float& blendShapeUnnormalizeFactor, BufferDefinition::Vector& buffers)
{
uint32_t geometryBufferIndex = 0u;
float maxDistanceSquared = 0.f;
Vector3* geometryBufferV3 = reinterpret_cast<Vector3*>(geometryBuffer);
- for(const auto& blendShape : blendShapes)
+ for(auto& blendShape : blendShapes)
{
if(blendShape.deltas.IsDefined())
{
- DALI_ASSERT_ALWAYS(((blendShape.deltas.mBlob.mLength % sizeof(Vector3) == 0u) ||
- blendShape.deltas.mBlob.mStride >= sizeof(Vector3)) &&
- "Blend Shape position buffer length not a multiple of element size");
+ const auto bufferSize = blendShape.deltas.mBlob.GetBufferSize();
+ uint32_t numVector3;
+
+ if(MaskMatch(blendShape.mFlags, MeshDefinition::S8_POSITION))
+ {
+ DALI_ASSERT_ALWAYS(((blendShape.deltas.mBlob.mLength % (sizeof(uint8_t) * 3) == 0) ||
+ blendShape.deltas.mBlob.mStride >= (sizeof(uint8_t) * 3)) &&
+ "Blend Shape position buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(uint8_t) * 3));
+ }
+ else if(MaskMatch(blendShape.mFlags, MeshDefinition::S16_POSITION))
+ {
+ DALI_ASSERT_ALWAYS(((blendShape.deltas.mBlob.mLength % (sizeof(uint16_t) * 3) == 0) ||
+ blendShape.deltas.mBlob.mStride >= (sizeof(uint16_t) * 3)) &&
+ "Blend Shape position buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(uint16_t) * 3));
+ }
+ else
+ {
+ DALI_ASSERT_ALWAYS(((blendShape.deltas.mBlob.mLength % sizeof(Vector3) == 0) ||
+ blendShape.deltas.mBlob.mStride >= sizeof(Vector3)) &&
+ "Blend Shape position buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / sizeof(Vector3));
+ }
- const auto bufferSize = blendShape.deltas.mBlob.GetBufferSize();
std::vector<uint8_t> buffer(bufferSize);
std::vector<uint32_t> sparseIndices{};
if(ReadAccessor(blendShape.deltas, buffers[blendShape.deltas.mBufferIdx].GetBufferStream(), buffer.data(), &sparseIndices))
{
- blendShape.deltas.mBlob.ApplyMinMax(static_cast<uint32_t>(bufferSize / sizeof(Vector3)), reinterpret_cast<float*>(buffer.data()), &sparseIndices);
+ GetDequantizedData(buffer, 3u, numVector3, blendShape.mFlags & MeshDefinition::POSITIONS_MASK, blendShape.deltas.mNormalized);
+
+ if(blendShape.deltas.mNormalized)
+ {
+ GetDequantizedMinMax(blendShape.deltas.mBlob.mMin, blendShape.deltas.mBlob.mMax, blendShape.mFlags & MeshDefinition::POSITIONS_MASK);
+ }
+
+ blendShape.deltas.mBlob.ApplyMinMax(numVector3, reinterpret_cast<float*>(buffer.data()), &sparseIndices);
// Calculate the difference with the original mesh.
// Find the max distance to normalize the deltas.
if(blendShape.normals.IsDefined())
{
- DALI_ASSERT_ALWAYS(((blendShape.normals.mBlob.mLength % sizeof(Vector3) == 0u) ||
- blendShape.normals.mBlob.mStride >= sizeof(Vector3)) &&
- "Blend Shape normals buffer length not a multiple of element size");
+ const auto bufferSize = blendShape.normals.mBlob.GetBufferSize();
+ uint32_t numVector3;
+
+ if(MaskMatch(blendShape.mFlags, MeshDefinition::S8_NORMAL))
+ {
+ DALI_ASSERT_ALWAYS(((blendShape.normals.mBlob.mLength % (sizeof(int8_t) * 3) == 0) ||
+ blendShape.normals.mBlob.mStride >= (sizeof(int8_t) * 3)) &&
+ "Blend Shape normals buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(int8_t) * 3));
+ }
+ else if(MaskMatch(blendShape.mFlags, MeshDefinition::S16_NORMAL))
+ {
+ DALI_ASSERT_ALWAYS(((blendShape.normals.mBlob.mLength % (sizeof(int16_t) * 3) == 0) ||
+ blendShape.normals.mBlob.mStride >= (sizeof(int16_t) * 3)) &&
+ "Blend Shape normals buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(int16_t) * 3));
+ }
+ else
+ {
+ DALI_ASSERT_ALWAYS(((blendShape.normals.mBlob.mLength % sizeof(Vector3) == 0) ||
+ blendShape.normals.mBlob.mStride >= sizeof(Vector3)) &&
+ "Blend Shape normals buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / sizeof(Vector3));
+ }
- const auto bufferSize = blendShape.normals.mBlob.GetBufferSize();
std::vector<uint8_t> buffer(bufferSize);
std::vector<uint32_t> sparseIndices;
if(ReadAccessor(blendShape.normals, buffers[blendShape.normals.mBufferIdx].GetBufferStream(), buffer.data(), &sparseIndices))
{
- blendShape.normals.mBlob.ApplyMinMax(static_cast<uint32_t>(bufferSize / sizeof(Vector3)), reinterpret_cast<float*>(buffer.data()), &sparseIndices);
+ GetDequantizedData(buffer, 3u, numVector3, blendShape.mFlags & MeshDefinition::NORMALS_MASK, blendShape.normals.mNormalized);
+
+ if(blendShape.normals.mNormalized)
+ {
+ GetDequantizedMinMax(blendShape.normals.mBlob.mMin, blendShape.normals.mBlob.mMax, blendShape.mFlags & MeshDefinition::NORMALS_MASK);
+ }
+
+ blendShape.normals.mBlob.ApplyMinMax(numVector3, reinterpret_cast<float*>(buffer.data()), &sparseIndices);
// Calculate the difference with the original mesh, and translate to make all values positive.
const Vector3* const deltasBuffer = reinterpret_cast<const Vector3* const>(buffer.data());
if(blendShape.tangents.IsDefined())
{
- DALI_ASSERT_ALWAYS(((blendShape.tangents.mBlob.mLength % sizeof(Vector3) == 0u) ||
- blendShape.tangents.mBlob.mStride >= sizeof(Vector3)) &&
- "Blend Shape tangents buffer length not a multiple of element size");
+ const auto bufferSize = blendShape.tangents.mBlob.GetBufferSize();
+
+ uint32_t numVector3;
+
+ if(MaskMatch(blendShape.mFlags, MeshDefinition::S8_TANGENT))
+ {
+ DALI_ASSERT_ALWAYS(((blendShape.tangents.mBlob.mLength % (sizeof(int8_t) * 3) == 0) ||
+ blendShape.tangents.mBlob.mStride >= (sizeof(int8_t) * 3)) &&
+ "Blend Shape tangents buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(int8_t) * 3));
+ }
+ else if(MaskMatch(blendShape.mFlags, MeshDefinition::S16_TANGENT))
+ {
+ DALI_ASSERT_ALWAYS(((blendShape.tangents.mBlob.mLength % (sizeof(int16_t) * 3) == 0) ||
+ blendShape.tangents.mBlob.mStride >= (sizeof(int16_t) * 3)) &&
+ "Blend Shape tangents buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(int16_t) * 3));
+ }
+ else
+ {
+ DALI_ASSERT_ALWAYS(((blendShape.tangents.mBlob.mLength % sizeof(Vector3) == 0) ||
+ blendShape.tangents.mBlob.mStride >= sizeof(Vector3)) &&
+ "Blend Shape tangents buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / sizeof(Vector3));
+ }
- const auto bufferSize = blendShape.tangents.mBlob.GetBufferSize();
std::vector<uint8_t> buffer(bufferSize);
std::vector<uint32_t> sparseIndices;
if(ReadAccessor(blendShape.tangents, buffers[blendShape.tangents.mBufferIdx].GetBufferStream(), buffer.data(), &sparseIndices))
{
- blendShape.tangents.mBlob.ApplyMinMax(static_cast<uint32_t>(bufferSize / sizeof(Vector3)), reinterpret_cast<float*>(buffer.data()), &sparseIndices);
+ GetDequantizedData(buffer, 3u, numVector3, blendShape.mFlags & MeshDefinition::TANGENTS_MASK, blendShape.tangents.mNormalized);
+
+ if(blendShape.tangents.mNormalized)
+ {
+ GetDequantizedMinMax(blendShape.tangents.mBlob.mMin, blendShape.tangents.mBlob.mMax, blendShape.mFlags & MeshDefinition::TANGENTS_MASK);
+ }
+
+ blendShape.tangents.mBlob.ApplyMinMax(numVector3, reinterpret_cast<float*>(buffer.data()), &sparseIndices);
// Calculate the difference with the original mesh, and translate to make all values positive.
const Vector3* const deltasBuffer = reinterpret_cast<const Vector3* const>(buffer.data());
MeshDefinition::Accessor::Accessor(const MeshDefinition::Blob& blob,
const MeshDefinition::SparseBlob& sparse,
- Index bufferIndex)
+ Index bufferIndex,
+ bool normalized)
: mBlob{blob},
mSparse{(sparse.mIndices.IsDefined() && sparse.mValues.IsDefined()) ? new SparseBlob{sparse} : nullptr},
- mBufferIdx(bufferIndex)
+ mBufferIdx(bufferIndex),
+ mNormalized(normalized)
{
}
MeshDefinition::Accessor::Accessor(MeshDefinition::Blob&& blob,
MeshDefinition::SparseBlob&& sparse,
- Index bufferIndex)
+ Index bufferIndex,
+ bool normalized)
: mBlob{std::move(blob)},
mSparse{(sparse.mIndices.IsDefined() && sparse.mValues.IsDefined()) ? new SparseBlob{std::move(sparse)} : nullptr},
- mBufferIdx(bufferIndex)
+ mBufferIdx(bufferIndex),
+ mNormalized(normalized)
{
}
bool MeshDefinition::IsSkinned() const
{
- return mJoints0.IsDefined() && mWeights0.IsDefined();
+ 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
}
}
+ uint32_t numberOfVertices = 0u;
+
std::vector<Vector3> positions;
if(mPositions.IsDefined())
{
- DALI_ASSERT_ALWAYS(((mPositions.mBlob.mLength % sizeof(Vector3) == 0) ||
- mPositions.mBlob.mStride >= sizeof(Vector3)) &&
- "Position buffer length not a multiple of element size");
- const auto bufferSize = mPositions.mBlob.GetBufferSize();
+ const auto bufferSize = mPositions.mBlob.GetBufferSize();
+ uint32_t numVector3;
+
+ if(MaskMatch(mFlags, S8_POSITION) || MaskMatch(mFlags, U8_POSITION))
+ {
+ DALI_ASSERT_ALWAYS(((mPositions.mBlob.mLength % (sizeof(uint8_t) * 3) == 0) ||
+ mPositions.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))
+ {
+ DALI_ASSERT_ALWAYS(((mPositions.mBlob.mLength % (sizeof(uint16_t) * 3) == 0) ||
+ mPositions.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)) &&
+ "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;
ExceptionFlinger(ASSERT_LOCATION) << "Failed to read positions from '" << path << "'.";
}
- uint32_t numVector3 = static_cast<uint32_t>(bufferSize / sizeof(Vector3));
+ GetDequantizedData(buffer, 3u, numVector3, mFlags & POSITIONS_MASK, mPositions.mNormalized);
+
+ if(mPositions.mNormalized)
+ {
+ GetDequantizedMinMax(mPositions.mBlob.mMin, mPositions.mBlob.mMax, mFlags & POSITIONS_MASK);
+ }
+
if(mPositions.mBlob.mMin.size() != 3u || mPositions.mBlob.mMax.size() != 3u)
{
mPositions.mBlob.ComputeMinMax(3u, numVector3, reinterpret_cast<float*>(buffer.data()));
auto hasNormals = mNormals.IsDefined();
if(hasNormals)
{
- DALI_ASSERT_ALWAYS(((mNormals.mBlob.mLength % sizeof(Vector3) == 0) ||
- mNormals.mBlob.mStride >= sizeof(Vector3)) &&
- "Normal buffer length not a multiple of element size");
- const auto bufferSize = mNormals.mBlob.GetBufferSize();
+ const auto bufferSize = mNormals.mBlob.GetBufferSize();
+ uint32_t numVector3;
+
+ if(MaskMatch(mFlags, S8_NORMAL))
+ {
+ DALI_ASSERT_ALWAYS(((mNormals.mBlob.mLength % (sizeof(int8_t) * 3) == 0) ||
+ mNormals.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))
+ {
+ DALI_ASSERT_ALWAYS(((mNormals.mBlob.mLength % (sizeof(int16_t) * 3) == 0) ||
+ mNormals.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)) &&
+ "Normal buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / sizeof(Vector3));
+ }
+
std::vector<uint8_t> buffer(bufferSize);
std::string path;
ExceptionFlinger(ASSERT_LOCATION) << "Failed to read normals from '" << path << "'.";
}
- mNormals.mBlob.ApplyMinMax(static_cast<uint32_t>(bufferSize / sizeof(Vector3)), reinterpret_cast<float*>(buffer.data()));
+ GetDequantizedData(buffer, 3u, numVector3, mFlags & NORMALS_MASK, mNormals.mNormalized);
- raw.mAttribs.push_back({"aNormal", Property::VECTOR3, static_cast<uint32_t>(bufferSize / sizeof(Vector3)), std::move(buffer)});
+ if(mNormals.mNormalized)
+ {
+ GetDequantizedMinMax(mNormals.mBlob.mMin, mNormals.mBlob.mMax, mFlags & NORMALS_MASK);
+ }
+
+ mNormals.mBlob.ApplyMinMax(numVector3, reinterpret_cast<float*>(buffer.data()));
+
+ raw.mAttribs.push_back({"aNormal", Property::VECTOR3, numVector3, std::move(buffer)});
}
else if(mNormals.mBlob.mLength != 0 && isTriangles)
{
}
}
- const auto hasUvs = mTexCoords.IsDefined();
- if(hasUvs)
+ if(!mTexCoords.empty() && mTexCoords[0].IsDefined())
{
- DALI_ASSERT_ALWAYS(((mTexCoords.mBlob.mLength % sizeof(Vector2) == 0) ||
- mTexCoords.mBlob.mStride >= sizeof(Vector2)) &&
- "Normal buffer length not a multiple of element size");
- const auto bufferSize = mTexCoords.mBlob.GetBufferSize();
+ auto& texCoords = mTexCoords[0];
+ const auto bufferSize = texCoords.mBlob.GetBufferSize();
+ uint32_t uvCount;
+
+ if(MaskMatch(mFlags, S8_TEXCOORD) || MaskMatch(mFlags, 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))
+ {
+ DALI_ASSERT_ALWAYS(((texCoords.mBlob.mLength % (sizeof(uint16_t) * 2) == 0) ||
+ texCoords.mBlob.mStride >= (sizeof(uint16_t) * 2)) &&
+ "TexCoords buffer length not a multiple of element size");
+ uvCount = static_cast<uint32_t>(bufferSize / (sizeof(uint16_t) * 2));
+ }
+ else
+ {
+ DALI_ASSERT_ALWAYS(((texCoords.mBlob.mLength % sizeof(Vector2) == 0) ||
+ texCoords.mBlob.mStride >= sizeof(Vector2)) &&
+ "TexCoords buffer length not a multiple of element size");
+ uvCount = static_cast<uint32_t>(bufferSize / sizeof(Vector2));
+ }
+
std::vector<uint8_t> buffer(bufferSize);
std::string path;
- auto& stream = GetAvailableData(fileStream, meshPath, buffers[mTexCoords.mBufferIdx], path);
- if(!ReadAccessor(mTexCoords, stream, buffer.data()))
+ auto& stream = GetAvailableData(fileStream, meshPath, buffers[texCoords.mBufferIdx], path);
+ if(!ReadAccessor(texCoords, stream, buffer.data()))
{
ExceptionFlinger(ASSERT_LOCATION) << "Failed to read uv-s from '" << path << "'.";
}
- const auto uvCount = bufferSize / sizeof(Vector2);
+ GetDequantizedData(buffer, 2u, uvCount, mFlags & TEXCOORDS_MASK, texCoords.mNormalized);
+
if(MaskMatch(mFlags, FLIP_UVS_VERTICAL))
{
auto uv = reinterpret_cast<Vector2*>(buffer.data());
}
}
- mTexCoords.mBlob.ApplyMinMax(static_cast<uint32_t>(uvCount), reinterpret_cast<float*>(buffer.data()));
+ if(texCoords.mNormalized)
+ {
+ GetDequantizedMinMax(texCoords.mBlob.mMin, texCoords.mBlob.mMax, mFlags & 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)});
}
if(mTangents.IsDefined())
{
- uint32_t propertySize = static_cast<uint32_t>((mTangentType == Property::VECTOR4) ? sizeof(Vector4) : sizeof(Vector3));
- DALI_ASSERT_ALWAYS(((mTangents.mBlob.mLength % propertySize == 0) ||
- mTangents.mBlob.mStride >= propertySize) &&
- "Tangents buffer length not a multiple of element size");
- const auto bufferSize = mTangents.mBlob.GetBufferSize();
+ const auto bufferSize = mTangents.mBlob.GetBufferSize();
+
+ uint32_t propertySize = static_cast<uint32_t>((mTangentType == Property::VECTOR4) ? sizeof(Vector4) : sizeof(Vector3));
+ uint32_t componentCount = static_cast<uint32_t>(propertySize / sizeof(float));
+
+ uint32_t numTangents;
+
+ if(MaskMatch(mFlags, S8_TANGENT))
+ {
+ DALI_ASSERT_ALWAYS(((mTangents.mBlob.mLength % (sizeof(int8_t) * componentCount) == 0) ||
+ mTangents.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))
+ {
+ DALI_ASSERT_ALWAYS(((mTangents.mBlob.mLength % (sizeof(int16_t) * componentCount) == 0) ||
+ mTangents.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) &&
+ "Tangents buffer length not a multiple of element size");
+ numTangents = static_cast<uint32_t>(bufferSize / propertySize);
+ }
+
std::vector<uint8_t> buffer(bufferSize);
std::string path;
{
ExceptionFlinger(ASSERT_LOCATION) << "Failed to read tangents from '" << path << "'.";
}
- mTangents.mBlob.ApplyMinMax(bufferSize / propertySize, reinterpret_cast<float*>(buffer.data()));
- raw.mAttribs.push_back({"aTangent", mTangentType, static_cast<uint32_t>(bufferSize / propertySize), std::move(buffer)});
+ GetDequantizedData(buffer, componentCount, numTangents, mFlags & TANGENTS_MASK, mTangents.mNormalized);
+
+ if(mTangents.mNormalized)
+ {
+ GetDequantizedMinMax(mTangents.mBlob.mMin, mTangents.mBlob.mMax, mFlags & TANGENTS_MASK);
+ }
+
+ mTangents.mBlob.ApplyMinMax(numTangents, reinterpret_cast<float*>(buffer.data()));
+
+ raw.mAttribs.push_back({"aTangent", mTangentType, static_cast<uint32_t>(numTangents), std::move(buffer)});
}
else if(mTangents.mBlob.mLength != 0 && hasNormals && isTriangles)
{
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);
if(!generateSuccessed)
{
}
}
- if(mColors.IsDefined())
+ // Only support 1 vertex color
+ if(!mColors.empty() && mColors[0].IsDefined())
{
- uint32_t propertySize = mColors.mBlob.mElementSizeHint;
+ uint32_t propertySize = mColors[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.mBlob.mLength % propertySize == 0) ||
- mColors.mBlob.mStride >= propertySize) &&
+ DALI_ASSERT_ALWAYS(((mColors[0].mBlob.mLength % propertySize == 0) ||
+ mColors[0].mBlob.mStride >= propertySize) &&
"Colors buffer length not a multiple of element size");
- const auto bufferSize = mColors.mBlob.GetBufferSize();
+ const auto bufferSize = mColors[0].mBlob.GetBufferSize();
std::vector<uint8_t> buffer(bufferSize);
std::string path;
- auto& stream = GetAvailableData(fileStream, meshPath, buffers[mColors.mBufferIdx], path);
- if(!ReadAccessor(mColors, stream, buffer.data()))
+ auto& stream = GetAvailableData(fileStream, meshPath, buffers[mColors[0].mBufferIdx], path);
+ if(!ReadAccessor(mColors[0], stream, buffer.data()))
{
ExceptionFlinger(ASSERT_LOCATION) << "Failed to read colors from '" << path << "'.";
}
- mColors.mBlob.ApplyMinMax(bufferSize / propertySize, reinterpret_cast<float*>(buffer.data()));
+ mColors[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)});
}
if(IsSkinned())
{
- std::string pathJoint;
- auto& streamJoint = GetAvailableData(fileStream, meshPath, buffers[mJoints0.mBufferIdx], pathJoint);
- if(MaskMatch(mFlags, U16_JOINT_IDS))
- {
- ReadJointAccessor<uint16_t>(raw, mJoints0, streamJoint, pathJoint);
- }
- else if(MaskMatch(mFlags, U8_JOINT_IDS))
- {
- ReadJointAccessor<uint8_t>(raw, mJoints0, streamJoint, pathJoint);
- }
- else
- {
- ReadJointAccessor<float>(raw, mJoints0, streamJoint, pathJoint);
- }
-
- std::string pathWeight;
- auto& streamWeight = GetAvailableData(fileStream, meshPath, buffers[mWeights0.mBufferIdx], pathWeight);
- if(MaskMatch(mFlags, U16_WEIGHT))
- {
- ReadWeightAccessor<uint16_t>(raw, mWeights0, streamWeight, pathWeight);
- }
- else if(MaskMatch(mFlags, U8_WEIGHT))
+ int setIndex = 0;
+ for(auto& accessor : mJoints)
{
- ReadWeightAccessor<uint8_t>(raw, mWeights0, streamWeight, pathWeight);
+ 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());
}
- else
+ setIndex = 0;
+ for(auto& accessor : mWeights)
{
- ReadWeightAccessor<float>(raw, mWeights0, streamWeight, pathWeight);
+ 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());
}
}
blendShapesBlob.mOffset = std::numeric_limits<unsigned int>::max();
blendShapesBlob.mLength = 0u;
- for(const auto& blendShape : mBlendShapes)
- {
- for(auto i : {&blendShape.deltas, &blendShape.normals, &blendShape.tangents})
+ uint32_t totalTextureSize(0u);
+
+ auto processAccessor = [&](const Accessor& accessor, uint32_t vector3Size) {
+ if(accessor.IsDefined())
{
- if(i->IsDefined())
- {
- blendShapesBlob.mOffset = std::min(blendShapesBlob.mOffset, i->mBlob.mOffset);
- blendShapesBlob.mLength += i->mBlob.mLength;
- }
+ blendShapesBlob.mOffset = std::min(blendShapesBlob.mOffset, accessor.mBlob.mOffset);
+ blendShapesBlob.mLength += accessor.mBlob.mLength;
+
+ totalTextureSize += accessor.mBlob.mLength / vector3Size;
}
+ };
+
+ for(const auto& blendShape : mBlendShapes)
+ {
+ const auto positionMask = blendShape.mFlags & POSITIONS_MASK;
+ const auto normalMask = blendShape.mFlags & NORMALS_MASK;
+ const auto tangentMask = blendShape.mFlags & 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)));
}
if(HasBlendShapes())
{
- const uint32_t numberOfVertices = static_cast<uint32_t>(mPositions.mBlob.mLength / sizeof(Vector3));
-
// Calculate the size of one buffer inside the texture.
raw.mBlendShapeBufferOffset = numberOfVertices;
if(!mBlendShapeHeader.IsDefined())
{
- CalculateTextureSize(static_cast<uint32_t>(blendShapesBlob.mLength / sizeof(Vector3)), textureWidth, textureHeight);
+ CalculateTextureSize(totalTextureSize, textureWidth, textureHeight);
calculateGltf2BlendShapes = true;
}
else
INVALID = std::numeric_limits<uint32_t>::max()
};
- enum Flags : uint16_t
+ enum : uint32_t
+ {
+ MAX_NUMBER_OF_JOINT_SETS = 4
+ };
+
+ enum Flags : uint32_t
{
FLIP_UVS_VERTICAL = NthBit(0),
U32_INDICES = NthBit(1), // default is unsigned short
U8_JOINT_IDS = NthBit(4),
U16_WEIGHT = NthBit(5), // default is floats
U8_WEIGHT = NthBit(6),
+ S8_POSITION = NthBit(7), // default is floats
+ U8_POSITION = NthBit(8), // default is floats
+ S16_POSITION = NthBit(9), // default is floats
+ U16_POSITION = NthBit(10), // default is floats
+ S8_NORMAL = NthBit(11), // default is floats
+ S16_NORMAL = NthBit(12), // default is floats
+ S8_TANGENT = NthBit(13), // default is floats
+ S16_TANGENT = NthBit(14), // default is floats
+ S8_TEXCOORD = NthBit(15), // default is floats
+ U8_TEXCOORD = NthBit(16), // default is floats
+ S16_TEXCOORD = NthBit(17), // default is floats
+ U16_TEXCOORD = NthBit(18), // default is floats
+ };
+
+ enum FlagMasks : uint32_t
+ {
+ POSITIONS_MASK = 0x780,
+ NORMALS_MASK = 0x1800,
+ TANGENTS_MASK = 0x6000,
+ TEXCOORDS_MASK = 0x78000,
};
enum Attributes
Blob mBlob;
std::unique_ptr<SparseBlob> mSparse;
Index mBufferIdx = INVALID_INDEX;
+ bool mNormalized{false};
Accessor() = default;
Accessor(const MeshDefinition::Blob& blob,
const MeshDefinition::SparseBlob& sparse,
- Index bufferIndex = INVALID_INDEX);
+ Index bufferIndex = INVALID_INDEX,
+ bool normalized = false);
+
Accessor(MeshDefinition::Blob&& blob,
MeshDefinition::SparseBlob&& sparse,
- Index bufferIndex = INVALID_INDEX);
+ Index bufferIndex = INVALID_INDEX,
+ bool normalized = false);
bool IsDefined() const
{
Accessor normals;
Accessor tangents;
float weight = 0.f;
+ uint32_t mFlags = 0x0;
};
struct RawData
bool IsSkinned() const;
/**
+ * @brief Determines if the mesh has any vertex colors
+ */
+ bool HasVertexColor() const;
+
+ /**
+ * @brief Returns the number of joint sets defined by the mesh
+ *
+ * @note Clamped to 4 to minimise GPU attrs.
+ */
+ uint32_t GetNumberOfJointSets() const;
+
+ /**
* @brief Whether the mesh has blend shapes.
*/
bool HasBlendShapes() const;
std::string mUri; // When the mesh data is loaded from embedded resources, this URI is used as a data stream.
Accessor mIndices;
Accessor mPositions;
- Accessor mNormals; // data can be generated based on positions
- Accessor mTexCoords;
- Accessor mColors;
+ Accessor mNormals; // data can be generated based on positions
Accessor mTangents; // data can be generated based on normals and texCoords (the latter isn't mandatory; the results will be better if available)
- Accessor mJoints0;
- Accessor mWeights0;
+ std::vector<Accessor> mTexCoords;
+ std::vector<Accessor> mColors;
+ std::vector<Accessor> mJoints;
+ std::vector<Accessor> mWeights;
Property::Type mTangentType{Property::VECTOR3};
Blob mBlendShapeHeader;
reflector.Reflect(ResourceType::Material, mMaterialIdx);
}
+// How many shader managers are there?!
void ModelRenderable::OnCreate(const NodeDefinition& nodeDefinition, NodeDefinition::CreateParams& params, ModelNode& node) const
{
DALI_ASSERT_DEBUG(mMeshIdx != INVALID_INDEX);
+ ShaderOption::HashType shaderOptionHash{0u};
if(mShaderIdx == INVALID_INDEX)
{
- Shader shader = params.mShaderManager->ProduceShader(params.mResources.mMaterials[mMaterialIdx].first, params.mResources.mMeshes[mMeshIdx].first);
+ ShaderOption option = params.mShaderManager->ProduceShaderOption(params.mResources.mMaterials[mMaterialIdx].first,
+ params.mResources.mMeshes[mMeshIdx].first);
+ shaderOptionHash = option.GetOptionHash();
+ Shader shader = params.mShaderManager->ProduceShader(option);
+
static Geometry defaultGeometry = Geometry::New();
Renderer renderer = Renderer::New(defaultGeometry, shader);
{
mesh.first.mModelPrimitive = ModelPrimitive::New();
- auto primitive = mesh.first.mModelPrimitive;
- GetImplementation(primitive).SetRenderer(renderer);
+ auto& primitive = GetImplementation(mesh.first.mModelPrimitive);
+ primitive.SetRenderer(renderer);
Index envIndex = resources.mMaterials[mMaterialIdx].first.mEnvironmentIdx;
uint32_t specularMipmap = resources.mEnvironmentMaps[envIndex].second.mSpecularMipmapLevels;
- GetImplementation(primitive).SetImageBasedLightTexture(resources.mEnvironmentMaps[envIndex].second.mDiffuse,
- resources.mEnvironmentMaps[envIndex].second.mSpecular,
- resources.mEnvironmentMaps[envIndex].first.mIblIntensity,
- specularMipmap);
+ primitive.SetImageBasedLightTexture(resources.mEnvironmentMaps[envIndex].second.mDiffuse,
+ resources.mEnvironmentMaps[envIndex].second.mSpecular,
+ resources.mEnvironmentMaps[envIndex].first.mIblIntensity,
+ specularMipmap);
bool hasPositions = false;
bool hasNormals = false;
bool hasTangents = false;
mesh.first.RetrieveBlendShapeComponents(hasPositions, hasNormals, hasTangents);
- GetImplementation(primitive).SetBlendShapeOptions(hasPositions, hasNormals, hasTangents, mesh.first.mBlendShapeVersion);
- GetImplementation(primitive).SetBlendShapeGeometry(mesh.second.blendShapeGeometry);
- GetImplementation(primitive).SetSkinned(mesh.first.IsSkinned());
+ primitive.SetBlendShapeOptions(hasPositions, hasNormals, hasTangents, mesh.first.mBlendShapeVersion);
+ primitive.SetBlendShapeGeometry(mesh.second.blendShapeGeometry);
+ primitive.SetSkinned(mesh.first.IsSkinned(), mesh.first.GetNumberOfJointSets());
+ primitive.SetVertexColor(mesh.first.HasVertexColor());
}
auto shader = renderer.GetShader();
material.SetProperty(Scene3D::Material::Property::ALPHA_CUTOFF, matDef.GetAlphaCutoff());
material.SetProperty(Scene3D::Material::Property::DOUBLE_SIDED, matDef.mDoubleSided);
material.SetProperty(Scene3D::Material::Property::IOR, matDef.mIor);
+
+ // This _should_ keep the same shader as generated at the top of the method.
GetImplementation(mesh.first.mModelPrimitive).SetMaterial(material, false);
GetImplementation(material).ResetFlag();
}
- node.AddModelPrimitive(mesh.first.mModelPrimitive);
+ Internal::GetImplementation(node).AddModelPrimitive(mesh.first.mModelPrimitive, shaderOptionHash);
}
void ArcRenderable::OnCreate(const NodeDefinition& nodeDefinition, NodeDefinition::CreateParams& params, ModelNode& node) const
// EXTERNAL INCLUDES
#include <dali/public-api/object/property-array.h>
+#include <regex>
// INTERNAL INCLUDES
#include <dali-scene3d/internal/graphics/builtin-shader-extern-gen.h>
#include <dali-scene3d/public-api/loader/utils.h>
+#include <dali/integration-api/debug.h>
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_MODEL_SHADER_DEFINITION");
+#endif
+} // namespace
+
namespace Dali::Scene3D::Loader
{
namespace
{
}
-void ShaderDefinition::ApplyDefine(std::string& shaderCode, const std::string& definevar)
+void ApplyDefine(std::string& shaderCode, const std::string& definevar)
{
const std::string IF_1 = "#if 1";
}
}
+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)
+ {
+ 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)
+ {
+ std::string line = std::string(" \\\n") + (*i).str();
+ shaderCode.insert(insertionPoint, line);
+ insertionPoint += line.length();
+ }
+ }
+}
+
ShaderDefinition::RawData
ShaderDefinition::LoadRaw(const std::string& shadersPath) const
{
ApplyDefine(raw.mFragmentShaderSource, definevar);
ApplyDefine(raw.mShadowVertexShaderSource, definevar);
}
+ for(const auto& macroDef : mMacros)
+ {
+ RedefineMacro(raw.mVertexShaderSource, macroDef.macro, macroDef.definition);
+ RedefineMacro(raw.mFragmentShaderSource, macroDef.macro, macroDef.definition);
+ RedefineMacro(raw.mShadowVertexShaderSource, macroDef.macro, macroDef.definition);
+ }
}
return raw;
array.PushBack(map[0]);
array.PushBack(map[1]);
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Vert Shader src: \n%s\n", raw.mVertexShaderSource.c_str());
Shader shader = Shader::New(array);
for(Property::Map::SizeType i0 = 0, i1 = mUniforms.Count(); i0 != i1; ++i0)
{
// INTERNAL INCLUDES
#include <dali-scene3d/public-api/loader/renderer-state.h>
+#include <dali-scene3d/public-api/loader/shader-option.h>
namespace Dali::Scene3D::Loader
{
std::string mShadowFragmentShaderSource;
};
- /*
- * @brief Apply the defines values to shader.
- */
- static void ApplyDefine(std::string& shaderCode, const std::string& definevar);
-
ShaderDefinition() = default;
ShaderDefinition(const ShaderDefinition& other);
ShaderDefinition& operator=(const ShaderDefinition& other);
- ShaderDefinition(ShaderDefinition&&) = default;
+ ShaderDefinition(ShaderDefinition&&) = default;
ShaderDefinition& operator=(ShaderDefinition&&) = default;
/*
std::shared_ptr<RawData> mRawData;
RendererState::Type mRendererState = RendererState::NONE;
- std::string mVertexShaderPath;
- std::string mFragmentShaderPath;
- std::vector<std::string> mDefines;
- std::vector<std::string> mHints;
- Property::Map mUniforms;
- bool mUseBuiltInShader{false};
+ std::string mVertexShaderPath;
+ std::string mFragmentShaderPath;
+ std::vector<std::string> mDefines;
+ std::vector<ShaderOption::MacroDefinition> mMacros;
+ std::vector<std::string> mHints;
+ Property::Map mUniforms;
+ bool mUseBuiltInShader{false};
};
} // namespace Dali::Scene3D::Loader
#include <dali/integration-api/debug.h>
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_MODEL_SHADER_MANAGER");
+#endif
+} // namespace
+
namespace Dali::Scene3D::Loader
{
namespace
if(meshDef.IsSkinned())
{
option.AddOption(ShaderOption::Type::SKINNING);
+ option.AddJointMacros(meshDef.mJoints.size());
}
if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
option.AddOption(ShaderOption::Type::FLIP_UVS_VERTICAL);
}
- if(meshDef.mColors.IsDefined())
+ if(!meshDef.mColors.empty() && meshDef.mColors[0].IsDefined())
{
option.AddOption(ShaderOption::Type::COLOR_ATTRIBUTE);
}
ShaderManager::~ShaderManager() = default;
-Dali::Shader ShaderManager::ProduceShader(const MaterialDefinition& materialDefinition, const MeshDefinition& meshDefinition)
+ShaderOption ShaderManager::ProduceShaderOption(const MaterialDefinition& materialDefinition, const MeshDefinition& meshDefinition)
{
- ShaderOption option = MakeOption(materialDefinition, meshDefinition);
- return ProduceShader(option);
+ DALI_LOG_INFO(gLogFilter, Debug::Concise, "Defining shader from mat/mesh definitions\n");
+ return MakeOption(materialDefinition, meshDefinition);
}
Dali::Shader ShaderManager::ProduceShader(const ShaderOption& shaderOption)
auto& shaderMap = mImpl->mShaderMap;
uint64_t hash = shaderOption.GetOptionHash();
- auto iFind = shaderMap.find(hash);
+
+#if defined(DEBUG_ENABLED)
+ std::ostringstream oss;
+ oss << " ShaderOption defines:";
+ std::vector<std::string> defines;
+ shaderOption.GetDefines(defines);
+ for(auto& def : defines)
+ {
+ oss << def << ", ";
+ }
+ oss << std::endl
+ << " ShaderOption macro definitions:" << std::endl;
+ for(auto& macro : shaderOption.GetMacroDefinitions())
+ {
+ oss << macro.macro << " : " << macro.definition << std::endl;
+ }
+ DALI_LOG_INFO(gLogFilter, Debug::Concise, "ShaderOption:\n%s\n", oss.str().c_str());
+#endif
+
+ auto iFind = shaderMap.find(hash);
if(iFind != shaderMap.end())
{
+ DALI_LOG_INFO(gLogFilter, Debug::Concise, "Defining Shader found: hash: %lx", hash);
result = mImpl->mShaders[iFind->second];
}
else
{
+ DALI_LOG_INFO(gLogFilter, Debug::Concise, "Creating new shader: hash: %lx\n", hash);
ShaderDefinition shaderDef;
shaderDef.mUseBuiltInShader = true;
shaderOption.GetDefines(shaderDef.mDefines);
+ shaderDef.mMacros = shaderOption.GetMacroDefinitions();
shaderDef.mUniforms["uCubeMatrix"] = Matrix::IDENTITY;
shaderMap[hash] = mImpl->mShaders.size();
std::string shadowViewProjectionPropertyName(Scene3D::Internal::Light::GetShadowViewProjectionMatrixUniformName());
auto shadowViewProjectionPropertyIndex = shader.RegisterProperty(shadowViewProjectionPropertyName, Matrix::IDENTITY);
Dali::CameraActor shadowLightCamera = Dali::Scene3D::Internal::GetImplementation(mImpl->mShadowLight).GetCamera();
- auto tempViewProjectionMatrixIndex = shadowLightCamera.GetPropertyIndex("tempViewProjectionMatrix");
+ auto tempViewProjectionMatrixIndex = shadowLightCamera.GetPropertyIndex("tempViewProjectionMatrix");
if(tempViewProjectionMatrixIndex != Dali::Property::INVALID_INDEX)
{
tempViewProjectionMatrixIndex = shadowLightCamera.RegisterProperty("tempViewProjectionMatrix", Matrix::IDENTITY);
}
- Dali::Constraint shadowViewProjectionConstraint = Dali::Constraint::New<Matrix>(shader, shadowViewProjectionPropertyIndex, [](Matrix& output, const PropertyInputContainer& inputs)
- {
- output = inputs[0]->GetMatrix(); });
+ Dali::Constraint shadowViewProjectionConstraint = Dali::Constraint::New<Matrix>(shader, shadowViewProjectionPropertyIndex, [](Matrix& output, const PropertyInputContainer& inputs) { output = inputs[0]->GetMatrix(); });
shadowViewProjectionConstraint.AddSource(Source{shadowLightCamera, tempViewProjectionMatrixIndex});
shadowViewProjectionConstraint.ApplyPost();
shadowViewProjectionConstraint.SetTag(INDEX_FOR_SHADOW_CONSTRAINT_TAG);
// INTERNAL INCLUDES
#include <dali-scene3d/public-api/api.h>
+#include <dali-scene3d/public-api/light/light.h>
#include <dali-scene3d/public-api/loader/index.h>
#include <dali-scene3d/public-api/loader/material-definition.h>
#include <dali-scene3d/public-api/loader/mesh-definition.h>
#include <dali-scene3d/public-api/loader/renderer-state.h>
#include <dali-scene3d/public-api/loader/shader-option.h>
-#include <dali-scene3d/public-api/light/light.h>
namespace Dali::Scene3D::Loader
{
* (Although the input materialDefinition and meshDefinition are not identical to those used to create the cached Dali::Shader, they share the cached one.)
* @param[in] materialDefinition MaterialDefinition that includes information of material to create Shader.
* @param[in] meshDefinition meshDefinition that includes information of mesh to create Shader.
- * @return Dali::Shader for the materialDefinition and meshDefinition.
+ * @return ShaderOption for the materialDefinition and meshDefinition.
*/
- Dali::Shader ProduceShader(const MaterialDefinition& materialDefinition, const MeshDefinition& meshDefinition);
+ ShaderOption ProduceShaderOption(const MaterialDefinition& materialDefinition, const MeshDefinition& meshDefinition);
/**
* @brief Produces a Dali::Shader for the input ShaderOption
* @param[in] shader Shader that the constraint will be applied.
*/
DALI_INTERNAL void SetShadowConstraintToShader(Dali::Shader shader);
+
private:
struct Impl;
const std::unique_ptr<Impl> mImpl;
#include <dali-scene3d/public-api/loader/shader-option.h>
// EXTERNAL INCLUDES
+#include <algorithm>
+#include <ostream>
+#include <sstream>
#include <string>
namespace Dali::Scene3D::Loader
"MORPH_VERSION_2_0",
};
static constexpr uint32_t NUMBER_OF_OPTIONS = sizeof(OPTION_KEYWORD) / sizeof(OPTION_KEYWORD[0]);
+static const char* ADD_EXTRA_SKINNING_ATTRIBUTES{"ADD_EXTRA_SKINNING_ATTRIBUTES"};
+static const char* ADD_EXTRA_WEIGHTS{"ADD_EXTRA_WEIGHTS"};
+
+inline void HashString(std::uint64_t& hash, const char* string)
+{
+ char c;
+ while((c = *string++))
+ {
+ hash = hash * 33 + c;
+ }
+}
} // namespace
+ShaderOption::ShaderOption(const ShaderOption& rhs)
+{
+ mOptionHash = rhs.mOptionHash;
+ for(auto& macroDef : rhs.mMacros)
+ {
+ mMacros.emplace_back(macroDef);
+ }
+}
+
+ShaderOption& ShaderOption::operator=(const ShaderOption& rhs)
+{
+ if(this != &rhs)
+ {
+ mOptionHash = rhs.mOptionHash;
+ for(auto& macroDef : rhs.mMacros)
+ {
+ mMacros.emplace_back(macroDef);
+ }
+ }
+ return *this;
+}
+
void ShaderOption::SetTransparency()
{
mOptionHash |= (1 << NUMBER_OF_OPTIONS);
mOptionHash |= (1 << static_cast<uint32_t>(shaderOptionType));
}
+void ShaderOption::AddJointMacros(size_t numberOfJointSets)
+{
+ // Add options for ADD_EXTRA_SKINNING_ATTRIBUTES and ADD_EXTRA_WEIGHTS:
+ if(numberOfJointSets > 1)
+ {
+ std::ostringstream attributes;
+ std::ostringstream weights;
+ for(size_t i = 1; i < numberOfJointSets; ++i)
+ {
+ attributes << "in vec4 aJoints" << i << ";\n";
+ attributes << "in vec4 aWeights" << i << ";\n";
+
+ weights << "bone +=\n"
+ << "uBone[int(aJoints" << i << ".x)] * aWeights" << i << ".x +\n"
+ << "uBone[int(aJoints" << i << ".y)] * aWeights" << i << ".y +\n"
+ << "uBone[int(aJoints" << i << ".z)] * aWeights" << i << ".z +\n"
+ << "uBone[int(aJoints" << i << ".w)] * aWeights" << i << ".w;\n";
+ }
+ AddMacroDefinition(ADD_EXTRA_SKINNING_ATTRIBUTES, attributes.str());
+ AddMacroDefinition(ADD_EXTRA_WEIGHTS, weights.str());
+ }
+}
+
+void ShaderOption::AddMacroDefinition(std::string macro, std::string definition)
+{
+ auto iter = std::find_if(mMacros.begin(), mMacros.end(), [macro](ShaderOption::MacroDefinition& md) { return md.macro == macro; });
+ if(iter != mMacros.end())
+ {
+ iter->definition = definition;
+ }
+ else
+ {
+ mMacros.emplace_back(MacroDefinition{macro, definition});
+ }
+}
+
+const std::vector<ShaderOption::MacroDefinition>& ShaderOption::GetMacroDefinitions() const
+{
+ return mMacros;
+}
+
uint64_t ShaderOption::GetOptionHash() const
{
- return mOptionHash;
+ uint64_t optionHash = mOptionHash;
+ if(!mMacros.empty())
+ {
+ uint64_t hash = 5381;
+ for(auto& macroDef : mMacros)
+ {
+ HashString(hash, macroDef.macro.c_str());
+ HashString(hash, macroDef.definition.c_str());
+ }
+ optionHash |= (hash << 32 & 0xFFFFFFFF00000000);
+ }
+ return optionHash;
}
void ShaderOption::GetDefines(std::vector<std::string>& defines) const
// EXTERNAL INCLUDER
#include <dali/public-api/common/vector-wrapper.h>
#include <memory>
+#include <string>
#include <string_view>
// INTERNAL INCLUDES
namespace Dali::Scene3D::Loader
{
-
class DALI_SCENE3D_API ShaderOption
{
public:
enum class Type
{
- GLTF_CHANNELS = 0,
- THREE_TEXTURE,
- BASE_COLOR_TEXTURE,
- METALLIC_ROUGHNESS_TEXTURE,
- NORMAL_TEXTURE,
- OCCLUSION,
- EMISSIVE,
- ALPHA_TEST,
- SUBSURFACE,
- SPECULAR,
- SPECULAR_COLOR,
- SKINNING,
- FLIP_UVS_VERTICAL,
- COLOR_ATTRIBUTE,
- VEC4_TANGENT,
- MORPH_POSITION,
- MORPH_NORMAL,
- MORPH_TANGENT,
- MORPH_VERSION_2_0
+ GLTF_CHANNELS = 0, // 00001
+ THREE_TEXTURE, // 00002
+ BASE_COLOR_TEXTURE, // 00004
+ METALLIC_ROUGHNESS_TEXTURE, // 00008
+ NORMAL_TEXTURE, // 00010
+ OCCLUSION, // 00020
+ EMISSIVE, // 00040
+ ALPHA_TEST, // 00080
+ SUBSURFACE, // 00100
+ SPECULAR, // 00200
+ SPECULAR_COLOR, // 00400
+ SKINNING, // 00800
+ FLIP_UVS_VERTICAL, // 01000
+ COLOR_ATTRIBUTE, // 02000
+ VEC4_TANGENT, // 04000
+ MORPH_POSITION, // 08000
+ MORPH_NORMAL, // 10000
+ MORPH_TANGENT, // 20000
+ MORPH_VERSION_2_0 // 40000
+ };
+
+ struct MacroDefinition
+ {
+ std::string macro;
+ std::string definition;
};
+ ShaderOption() = default;
+ ShaderOption(const ShaderOption& rhs);
+ ShaderOption& operator=(const ShaderOption& rhs);
+
+ using HashType = uint64_t;
+
public:
/**
* @brief Sets transparency option.
void AddOption(Type shaderOptionType);
/**
+ * Adds macro definitions for joints based on the number of joint sets.
+ */
+ void AddJointMacros(size_t numberOfJointSets);
+
+ /**
+ * Enables empty preprocessor definitions to be defined to a value
+ */
+ void AddMacroDefinition(std::string macro, std::string definition);
+
+ /**
* @brief Retrieves current shader option hash
*
* @return Hash value of currently added options.
*/
- uint64_t GetOptionHash() const;
+ HashType GetOptionHash() const;
/**
* @brief Retrieves a list of define keywords.
*/
static std::string_view GetDefineKeyword(Type shaderOptionType);
+ /**
+ * Get any macro definitions
+ */
+ const std::vector<MacroDefinition>& GetMacroDefinitions() const;
+
private:
- uint64_t mOptionHash{0u};
+ HashType mOptionHash{0u};
+
+ std::vector<MacroDefinition> mMacros;
};
} // namespace Dali::Scene3D::Loader
namespace Dali::Scene3D::Loader
{
-const unsigned int Skinning::MAX_JOINTS = 80;
+const unsigned int Skinning::MAX_JOINTS = 256;
const char* Skinning::BONE_UNIFORM_NAME = "uBone";
} // namespace Dali::Scene3D::Loader
void ModelNode::AddModelPrimitive(ModelPrimitive modelPrimitive)
{
- Internal::GetImplementation(*this).AddModelPrimitive(modelPrimitive);
+ Internal::GetImplementation(*this).AddModelPrimitive(modelPrimitive, 0u);
}
void ModelNode::RemoveModelPrimitive(Dali::Scene3D::ModelPrimitive modelPrimitive)
/**
* @brief The content information the AnimatedVectorImageVisual will use.
- * @details Name "contentInfo", Type Property::MAP.
+ * @details Type Property::MAP.
* The map contains the layer name as a key and Property::Array as a value.
* And the array contains 2 integer values which are the frame numbers, the start frame number and the end frame number of the layer.
* @note This property is read-only.
* Disable broken image for these visuals.
* default is true.
*/
- ENABLE_BROKEN_IMAGE = ORIENTATION_CORRECTION + 14
+ ENABLE_BROKEN_IMAGE = ORIENTATION_CORRECTION + 14,
+
+ /**
+ * @brief The marker information the AnimatedVectorImageVisual will use.
+ * @details Type Property::MAP.
+ * The map contains the marker name as a key and Property::Array as a value.
+ * And the array contains 2 integer values which are the frame numbers, the start frame number and the end frame number of the marker.
+ * @note This property is read-only.
+ */
+ MARKER_INFO = ORIENTATION_CORRECTION + 15,
};
} //namespace Property
{
std::ostringstream oss;
oss << "[url:" << mUrl.GetUrl() << "]";
- DALI_TRACE_BEGIN_WITH_MESSAGE(gTraceFilter, "DALI_IMAGE_FAST_TRACK_UPLOADING_TASK", oss.str().c_str());
+ // DALI_TRACE_BEGIN(gTraceFilter, "DALI_IMAGE_FAST_TRACK_UPLOADING_TASK"); ///< TODO : Open it if we can control trace log level
+ DALI_LOG_RELEASE_INFO("BEGIN: DALI_IMAGE_FAST_TRACK_UPLOADING_TASK %s", oss.str().c_str());
}
#endif
oss << "premult:" << mPremultiplied << " ";
}
oss << "url:" << mUrl.GetUrl() << "]";
- DALI_TRACE_END_WITH_MESSAGE(gTraceFilter, "DALI_IMAGE_FAST_TRACK_UPLOADING_TASK", oss.str().c_str());
+ // DALI_TRACE_END(gTraceFilter, "DALI_IMAGE_FAST_TRACK_UPLOADING_TASK"); ///< TODO : Open it if we can control trace log level
+ DALI_LOG_RELEASE_INFO("END: DALI_IMAGE_FAST_TRACK_UPLOADING_TASK %s", oss.str().c_str());
}
#endif
}
{
std::ostringstream oss;
oss << "[url:" << (!!(animatedImageLoading) ? animatedImageLoading.GetUrl() : url.GetUrl()) << "]";
- DALI_TRACE_BEGIN_WITH_MESSAGE(gTraceFilter, "DALI_IMAGE_LOADING_TASK", oss.str().c_str());
+ // DALI_TRACE_BEGIN(gTraceFilter, "DALI_IMAGE_LOADING_TASK"); ///< TODO : Open it if we can control trace log level
+ DALI_LOG_RELEASE_INFO("BEGIN: DALI_IMAGE_LOADING_TASK %s", oss.str().c_str());
}
#endif
oss << "premult:" << pixelBuffers[0].IsAlphaPreMultiplied() << " ";
}
oss << "url:" << (!!(animatedImageLoading) ? animatedImageLoading.GetUrl() : url.GetUrl()) << "]";
- DALI_TRACE_END_WITH_MESSAGE(gTraceFilter, "DALI_IMAGE_LOADING_TASK", oss.str().c_str());
+ // DALI_TRACE_END(gTraceFilter, "DALI_IMAGE_LOADING_TASK"); ///< TODO : Open it if we can control trace log level
+ DALI_LOG_RELEASE_INFO("END: DALI_IMAGE_LOADING_TASK %s", oss.str().c_str());
}
#endif
}
else if(encodedImageBuffer)
{
pixelBuffer = Dali::LoadImageFromBuffer(encodedImageBuffer.GetRawBuffer(), dimensions, fittingMode, samplingMode, orientationCorrection);
+
+ // We don't need to hold image buffer anymore.
+ encodedImageBuffer.Reset();
}
else if(url.IsValid() && url.IsLocalResource())
{
// EXTERNAL HEADERS
#include <dali/devel-api/common/hash.h>
#include <dali/integration-api/debug.h>
+#include <string_view>
+#include <unordered_map>
// INTERNAL HEADERS
{
namespace Internal
{
+namespace
+{
+const std::string_view& GetEncodedImageBufferExtensions(Dali::EncodedImageBuffer::ImageType imageType)
+{
+ static const std::unordered_map<Dali::EncodedImageBuffer::ImageType, const std::string_view> gEncodedImageBufferExtensionMap =
+ {
+ {Dali::EncodedImageBuffer::ImageType::REGULAR_IMAGE, ""},
+ {Dali::EncodedImageBuffer::ImageType::VECTOR_IMAGE, ".svg"},
+ {Dali::EncodedImageBuffer::ImageType::ANIMATED_VECTOR_IMAGE, ".json"},
+ };
+
+ const auto iter = gEncodedImageBufferExtensionMap.find(imageType);
+
+ DALI_ASSERT_DEBUG(iter != gEncodedImageBufferExtensionMap.end());
+
+ return iter->second;
+}
+} // namespace
#ifdef DEBUG_ENABLED
extern Debug::Filter* gTextureManagerLogFilter; ///< Define at texture-manager-impl.cpp
case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_BUFFER:
{
DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::GetVisualUrl. Using cached buffer index=%d, bufferId=%d\n", cacheIndex.GetIndex(), textureId);
- visualUrl = VisualUrl::CreateBufferUrl(std::to_string(textureId));
+
+ EncodedImageBufferInfo& cachedEncodedImageBufferInfo(mEncodedImageBuffers[cacheIndex.GetIndex()]);
+ const auto& encodedImageBuffer = cachedEncodedImageBufferInfo.encodedImageBuffer;
+ visualUrl = VisualUrl::CreateBufferUrl(std::to_string(textureId), GetEncodedImageBufferExtensions(encodedImageBuffer.GetImageType()));
break;
}
default:
EncodedImageBuffer encodedImageBuffer; // empty handle
if(url.IsValid() && VisualUrl::BUFFER == url.GetProtocolType())
{
- std::string location = url.GetLocation();
+ std::string location = url.GetLocationWithoutExtension();
if(location.size() > 0u)
{
TextureId bufferId = std::stoi(location);
// If same buffer added, increase reference count and return.
bufferInfo.referenceCount++;
- return VisualUrl::CreateBufferUrl(std::to_string(bufferInfo.bufferId));
+ return VisualUrl::CreateBufferUrl(std::to_string(bufferInfo.bufferId), GetEncodedImageBufferExtensions(encodedImageBuffer.GetImageType()));
}
TextureId bufferId = GenerateTextureId(TextureCacheIndex(TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_BUFFER, mEncodedImageBuffers.size()));
DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::AddExternalEncodedImageBuffer() : New buffer regested. bufferId:%d\n", info.bufferId);
- return VisualUrl::CreateBufferUrl(std::to_string(info.bufferId));
+ return VisualUrl::CreateBufferUrl(std::to_string(info.bufferId), GetEncodedImageBufferExtensions(encodedImageBuffer.GetImageType()));
}
TextureSet TextureCacheManager::RemoveExternalTexture(const VisualUrl& url)
if(VisualUrl::BUFFER == url.GetProtocolType())
{
// get the location from the Url
- std::string location = url.GetLocation();
+ std::string location = url.GetLocationWithoutExtension();
if(location.size() > 0u)
{
TextureId bufferId = std::stoi(location);
}
else if(VisualUrl::BUFFER == url.GetProtocolType())
{
- std::string location = url.GetLocation();
+ std::string location = url.GetLocationWithoutExtension();
if(location.size() > 0u)
{
TextureId id = std::stoi(location);
if(textureInfo.loadState != LoadState::UPLOADED)
{
textureInfo.preMultiplied = (preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
- textureInfo.loadState = TextureManager::LoadState::WAITING_FOR_MASK;
+ textureInfo.loadState = TextureManager::LoadState::WAITING_FOR_MASK;
}
}
void TextureManager::QueueLoadTexture(const TextureManager::TextureInfo& textureInfo, TextureUploadObserver* observer)
{
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "Add observer to observer queue (textureId:%d, observer:%p)\n", textureInfo.textureId, observer);
+
const auto& textureId = textureInfo.textureId;
mLoadQueue.PushBack(QueueElement(textureId, observer));
{
if(element.mObserver == observer)
{
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "Remove observer from observer queue (textureId:%d, observer:%p)\n", element.mTextureId, element.mObserver);
element.mTextureId = INVALID_TEXTURE_ID;
element.mObserver = nullptr;
}
observer->DestructionSignal().Disconnect(this, &TextureManager::ObserverDestroyed);
textureInfo.observerList.Erase(iter);
}
+ else
+ {
+ // Given textureId might exist at load queue.
+ // Remove observer from the LoadQueue
+ for(auto&& element : mLoadQueue)
+ {
+ if(element.mTextureId == textureInfo.textureId && element.mObserver == observer)
+ {
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "Remove observer from observer queue (textureId:%d, observer:%p)\n", element.mTextureId, element.mObserver);
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, " Disconnect DestructionSignal to observer:%p\n", observer);
+ observer->DestructionSignal().Disconnect(this, &TextureManager::ObserverDestroyed);
+ element.mObserver = nullptr;
+ break;
+ }
+ }
+ }
}
}
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
{
namespace
{
-const int CUSTOM_PROPERTY_COUNT(12); // 5 transform properties + Start point/color, end point/color, rotate center/angle, offset
+const int CUSTOM_PROPERTY_COUNT(7); // Start point/color, end point/color, rotate center/angle, offset
DALI_ENUM_TO_STRING_TABLE_BEGIN(GRADIENT_TYPE)
DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::DevelAnimatedGradientVisual::GradientType, LINEAR)
{
if(!mCoreShutdown)
{
+ if(mImageUrl.IsBufferResource())
+ {
+ TextureManager& textureManager = mFactoryCache.GetTextureManager();
+ textureManager.RemoveEncodedImageBuffer(mImageUrl.GetUrl());
+ }
+
auto& vectorAnimationManager = mFactoryCache.GetVectorAnimationManager();
vectorAnimationManager.RemoveObserver(*this);
mVectorAnimationTask->GetLayerInfo(layerInfo);
map.Insert(Toolkit::DevelImageVisual::Property::CONTENT_INFO, layerInfo);
+ Property::Map markerInfo;
+ mVectorAnimationTask->GetMarkerInfo(markerInfo);
+ map.Insert(Toolkit::DevelImageVisual::Property::MARKER_INFO, markerInfo);
+
map.Insert(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, IsSynchronousLoadingRequired());
map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth());
map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight());
mVectorAnimationTask->ResourceReadySignal().Connect(this, &AnimatedVectorImageVisual::OnResourceReady);
mVectorAnimationTask->SetAnimationFinishedCallback(MakeCallback(this, &AnimatedVectorImageVisual::OnAnimationFinished));
- mVectorAnimationTask->RequestLoad(mImageUrl, IsSynchronousLoadingRequired());
+ EncodedImageBuffer encodedImageBuffer;
+
+ if(mImageUrl.IsBufferResource())
+ {
+ // Increase reference count of External Resources :
+ // EncodedImageBuffer.
+ // Reference count will be decreased at destructor of the visual.
+ TextureManager& textureManager = mFactoryCache.GetTextureManager();
+ textureManager.UseExternalResource(mImageUrl.GetUrl());
+
+ encodedImageBuffer = textureManager.GetEncodedImageBuffer(mImageUrl.GetUrl());
+ }
+
+ mVectorAnimationTask->RequestLoad(mImageUrl, encodedImageBuffer, IsSynchronousLoadingRequired());
auto& vectorAnimationManager = mFactoryCache.GetVectorAnimationManager();
vectorAnimationManager.AddObserver(*this);
#include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h>
// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/file-loader.h>
#include <dali/integration-api/debug.h>
#include <dali/integration-api/trace.h>
#include <dali/public-api/math/math-utils.h>
VectorAnimationTask::VectorAnimationTask(VisualFactoryCache& factoryCache)
: AsyncTask(MakeCallback(this, &VectorAnimationTask::TaskCompleted), AsyncTask::PriorityType::HIGH, AsyncTask::ThreadType::WORKER_THREAD),
mImageUrl(),
+ mEncodedImageBuffer(),
mVectorRenderer(VectorAnimationRenderer::New()),
mAnimationData(),
mVectorAnimationThread(factoryCache.GetVectorAnimationManager().GetVectorAnimationThread()),
{
std::ostringstream oss;
oss << "[url:" << mImageUrl.GetUrl() << "]";
- DALI_TRACE_BEGIN_WITH_MESSAGE(gTraceFilter, "DALI_LOTTIE_LOADING_TASK", oss.str().c_str());
+ // DALI_TRACE_BEGIN(gTraceFilter, "DALI_LOTTIE_LOADING_TASK"); ///< TODO : Open it if we can control trace log level
+ DALI_LOG_RELEASE_INFO("BEGIN: DALI_LOTTIE_LOADING_TASK %s", oss.str().c_str());
}
#endif
- if(!mVectorRenderer.Load(mImageUrl.GetUrl()))
+ if(mEncodedImageBuffer)
{
- DALI_LOG_ERROR("VectorAnimationTask::Load: Load failed [%s]\n", mImageUrl.GetUrl().c_str());
- mLoadFailed = true;
+ if(!mVectorRenderer.Load(mEncodedImageBuffer.GetRawBuffer()))
+ {
+ mLoadFailed = true;
+ }
+
+ // We don't need to hold image buffer anymore.
+ mEncodedImageBuffer.Reset();
+ }
+ else if(mImageUrl.IsLocalResource())
+ {
+ if(!mVectorRenderer.Load(mImageUrl.GetUrl()))
+ {
+ mLoadFailed = true;
+ }
+ }
+ else
+ {
+ Dali::Vector<uint8_t> remoteData;
+ if(!Dali::FileLoader::DownloadFileSynchronously(mImageUrl.GetUrl(), remoteData) || // Failed if we fail to download json file,
+ !mVectorRenderer.Load(remoteData)) // or download data is not valid vector animation file.
+ {
+ mLoadFailed = true;
+ }
}
if(mLoadFailed)
{
+ DALI_LOG_ERROR("VectorAnimationTask::Load: Load failed [%s]\n", mImageUrl.GetUrl().c_str());
mLoadRequest = false;
if(!synchronousLoading && mLoadCompletedCallback)
{
{
std::ostringstream oss;
oss << "[url:" << mImageUrl.GetUrl() << "]";
- DALI_TRACE_END_WITH_MESSAGE(gTraceFilter, "DALI_LOTTIE_LOADING_TASK", oss.str().c_str());
+ // DALI_TRACE_END(gTraceFilter, "DALI_LOTTIE_LOADING_TASK"); ///< TODO : Open it if we can control trace log level
+ DALI_LOG_RELEASE_INFO("END: DALI_LOTTIE_LOADING_TASK %s", oss.str().c_str());
}
#endif
return false;
{
std::ostringstream oss;
oss << "[url:" << mImageUrl.GetUrl() << "]";
- DALI_TRACE_END_WITH_MESSAGE(gTraceFilter, "DALI_LOTTIE_LOADING_TASK", oss.str().c_str());
+ // DALI_TRACE_END(gTraceFilter, "DALI_LOTTIE_LOADING_TASK"); ///< TODO : Open it if we can control trace log level
+ DALI_LOG_RELEASE_INFO("END: DALI_LOTTIE_LOADING_TASK %s", oss.str().c_str());
}
#endif
DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetRenderer [%p]\n", this);
}
-void VectorAnimationTask::RequestLoad(const VisualUrl& url, bool synchronousLoading)
+void VectorAnimationTask::RequestLoad(const VisualUrl& url, EncodedImageBuffer encodedImageBuffer, bool synchronousLoading)
{
- mImageUrl = url;
+ mImageUrl = url;
+ mEncodedImageBuffer = encodedImageBuffer;
if(!synchronousLoading)
{
mVectorRenderer.GetLayerInfo(map);
}
+void VectorAnimationTask::GetMarkerInfo(Property::Map& map) const
+{
+ mVectorRenderer.GetMarkerInfo(map);
+}
+
VectorAnimationTask::ResourceReadySignalType& VectorAnimationTask::ResourceReadySignal()
{
return mResourceReadySignal;
#include <dali/devel-api/adaptor-framework/vector-animation-renderer.h>
#include <dali/devel-api/threading/conditional-wait.h>
#include <dali/public-api/adaptor-framework/async-task-manager.h>
+#include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
#include <dali/public-api/common/vector-wrapper.h>
#include <dali/public-api/object/property-array.h>
#include <chrono>
* @brief Requests to load the animation file.
*
* @param[in] url The url of the vector animation file
+ * @param[in] encodedImageBuffer The resource buffer if required.
* @param[in] synchronousLoading True if the url should be loaded synchronously
*/
- void RequestLoad(const VisualUrl& url, bool synchronousLoading);
+ void RequestLoad(const VisualUrl& url, EncodedImageBuffer encodedImageBuffer, bool synchronousLoading);
/**
* @brief Queries whether loading is requested.
void GetLayerInfo(Property::Map& map) const;
/**
+ * @brief Gets the all marker information.
+ * @param[out] map The marker information
+ */
+ void GetMarkerInfo(Property::Map& map) const;
+
+ /**
* @brief Connect to this signal to be notified when the resource is ready.
* @return The signal to connect to.
*/
};
VisualUrl mImageUrl;
+ EncodedImageBuffer mEncodedImageBuffer;
VectorAnimationRenderer mVectorRenderer;
std::vector<AnimationData> mAnimationData[2];
VectorAnimationThread& mVectorAnimationThread;
*/
// CLASS HEADER
-#include "svg-task.h"
+#include <dali-toolkit/internal/visuals/svg/svg-task.h>
// EXTERNAL INCLUDES
#include <dali/devel-api/adaptor-framework/file-loader.h>
return mVectorRenderer;
}
-SvgLoadingTask::SvgLoadingTask(VectorImageRenderer vectorRenderer, const VisualUrl& url, float dpi, CallbackBase* callback)
+SvgLoadingTask::SvgLoadingTask(VectorImageRenderer vectorRenderer, const VisualUrl& url, EncodedImageBuffer encodedImageBuffer, float dpi, CallbackBase* callback)
: SvgTask(vectorRenderer, callback, url.GetProtocolType() == VisualUrl::ProtocolType::REMOTE ? AsyncTask::PriorityType::LOW : AsyncTask::PriorityType::HIGH),
mImageUrl(url),
+ mEncodedImageBuffer(encodedImageBuffer),
mDpi(dpi)
{
}
{
std::ostringstream oss;
oss << "[url:" << mImageUrl.GetUrl() << "]";
- DALI_TRACE_BEGIN_WITH_MESSAGE(gTraceFilter, "DALI_SVG_LOADING_TASK", oss.str().c_str());
+ // DALI_TRACE_BEGIN(gTraceFilter, "DALI_SVG_LOADING_TASK"); ///< TODO : Open it if we can control trace log level
+ DALI_LOG_RELEASE_INFO("BEGIN: DALI_SVG_LOADING_TASK %s", oss.str().c_str());
}
#endif
Dali::Vector<uint8_t> buffer;
- if(!mImageUrl.IsLocalResource())
+ if(mEncodedImageBuffer)
{
- if(!Dali::FileLoader::DownloadFileSynchronously(mImageUrl.GetUrl(), buffer))
+ // Copy raw buffer.
+ // TODO : Can't we load svg without copy buffer in future?
+ buffer = mEncodedImageBuffer.GetRawBuffer();
+
+ // We don't need to hold image buffer anymore.
+ mEncodedImageBuffer.Reset();
+ }
+ else if(mImageUrl.IsLocalResource())
+ {
+ if(!Dali::FileLoader::ReadFile(mImageUrl.GetUrl(), buffer))
{
- DALI_LOG_ERROR("Failed to download file! [%s]\n", mImageUrl.GetUrl().c_str());
+ DALI_LOG_ERROR("Failed to read file! [%s]\n", mImageUrl.GetUrl().c_str());
loadFailed = true;
}
}
else
{
- if(!Dali::FileLoader::ReadFile(mImageUrl.GetUrl(), buffer))
+ if(!Dali::FileLoader::DownloadFileSynchronously(mImageUrl.GetUrl(), buffer))
{
- DALI_LOG_ERROR("Failed to read file! [%s]\n", mImageUrl.GetUrl().c_str());
+ DALI_LOG_ERROR("Failed to download file! [%s]\n", mImageUrl.GetUrl().c_str());
loadFailed = true;
}
}
if(!loadFailed)
{
+ buffer.Reserve(buffer.Count() + 1u);
buffer.PushBack('\0');
if(!mVectorRenderer.Load(buffer, mDpi))
std::ostringstream oss;
oss << "[success:" << mHasSucceeded << " ";
oss << "url:" << mImageUrl.GetUrl() << "]";
- DALI_TRACE_END_WITH_MESSAGE(gTraceFilter, "DALI_SVG_LOADING_TASK", oss.str().c_str());
+ // DALI_TRACE_END(gTraceFilter, "DALI_SVG_LOADING_TASK"); ///< TODO : Open it if we can control trace log level
+ DALI_LOG_RELEASE_INFO("END: DALI_SVG_LOADING_TASK %s", oss.str().c_str());
}
#endif
}
#include <dali/public-api/common/intrusive-ptr.h>
#include <dali/public-api/common/vector-wrapper.h>
#include <dali/public-api/images/pixel-data.h>
+#include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
#include <memory>
// INTERNAL INCLUDES
* Constructor
* @param[in] vectorRenderer The vector rasterizer.
* @param[in] url The URL to svg resource to use.
+ * @param[in] encodedImageBuffer The resource buffer if required.
* @param[in] dpi The DPI of the screen.
* @param[in] callback The callback that is called when the operation is completed.
*/
- SvgLoadingTask(VectorImageRenderer vectorRenderer, const VisualUrl& url, float dpi, CallbackBase* callback);
+ SvgLoadingTask(VectorImageRenderer vectorRenderer, const VisualUrl& url, EncodedImageBuffer encodedImageBuffer, float dpi, CallbackBase* callback);
/**
* Destructor.
SvgLoadingTask& operator=(const SvgLoadingTask& task) = delete;
private:
- VisualUrl mImageUrl;
- float mDpi;
+ VisualUrl mImageUrl;
+ EncodedImageBuffer mEncodedImageBuffer;
+ float mDpi;
};
class SvgRasterizingTask : public SvgTask
*/
// CLASS HEADER
-#include "svg-visual.h"
+#include <dali-toolkit/internal/visuals/svg/svg-visual.h>
// INTERNAL INCLUDES
#include <dali-toolkit/internal/visuals/image-atlas-manager.h>
{
Dali::AsyncTaskManager::Get().RemoveTask(mRasterizingTask);
}
+
+ if(mImageUrl.IsBufferResource())
+ {
+ TextureManager& textureManager = mFactoryCache.GetTextureManager();
+ textureManager.RemoveEncodedImageBuffer(mImageUrl.GetUrl());
+ }
}
}
Vector2 dpi = Stage::GetCurrent().GetDpi();
float meanDpi = (dpi.height + dpi.width) * 0.5f;
- mLoadingTask = new SvgLoadingTask(mVectorRenderer, mImageUrl, meanDpi, MakeCallback(this, &SvgVisual::ApplyRasterizedImage));
+ EncodedImageBuffer encodedImageBuffer;
+
+ if(mImageUrl.IsBufferResource())
+ {
+ // Increase reference count of External Resources :
+ // EncodedImageBuffer.
+ // Reference count will be decreased at destructor of the visual.
+ TextureManager& textureManager = mFactoryCache.GetTextureManager();
+ textureManager.UseExternalResource(mImageUrl.GetUrl());
+
+ encodedImageBuffer = textureManager.GetEncodedImageBuffer(mImageUrl.GetUrl());
+ }
+
+ mLoadingTask = new SvgLoadingTask(mVectorRenderer, mImageUrl, encodedImageBuffer, meanDpi, MakeCallback(this, &SvgVisual::ApplyRasterizedImage));
- if(IsSynchronousLoadingRequired() && mImageUrl.IsLocalResource())
+ if(IsSynchronousLoadingRequired() && (mImageUrl.IsLocalResource() || mImageUrl.IsBufferResource()))
{
mLoadingTask->Process();
if(!mLoadingTask->HasSucceeded())
{
DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_TEXT_PERFORMANCE_MARKER, false);
-const int CUSTOM_PROPERTY_COUNT(5); // anim,premul,size,offset,multicol
+const int CUSTOM_PROPERTY_COUNT(2); // uTextColorAnimatable, uHasMultipleTextColors
/**
* Return Property index for the given string key
mTypesetter(Text::Typesetter::New(mController->GetTextModel())),
mTextVisualShaderFactory(shaderFactory),
mTextShaderFeatureCache(),
+ mHasMultipleTextColorsIndex(Property::INVALID_INDEX),
mAnimatableTextColorPropertyIndex(Property::INVALID_INDEX),
mTextColorAnimatableIndex(Property::INVALID_INDEX),
mRendererUpdateNeeded(false)
mImpl->mRenderer = VisualRenderer::New(geometry, shader);
mImpl->mRenderer.ReserveCustomProperties(CUSTOM_PROPERTY_COUNT);
+ mHasMultipleTextColorsIndex = mImpl->mRenderer.RegisterUniqueProperty("uHasMultipleTextColors", false);
}
void TextVisual::DoSetProperties(const Property::Map& propertyMap)
// Enable the pre-multiplied alpha to improve the text quality
renderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, true);
- renderer.RegisterProperty(PREMULTIPLIED_ALPHA, 1.0f);
+ renderer.SetProperty(VisualRenderer::Property::VISUAL_PRE_MULTIPLIED_ALPHA, true);
// Set size and offset for the tiling.
renderer.SetProperty(VisualRenderer::Property::TRANSFORM_SIZE, Vector2(info.width, info.height));
mImpl->mRenderer.SetTextures(textureSet);
//Register transform properties
mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
- mImpl->mRenderer.RegisterProperty("uHasMultipleTextColors", static_cast<float>(hasMultipleTextColors));
+ mImpl->mRenderer.SetProperty(mHasMultipleTextColorsIndex, static_cast<float>(hasMultipleTextColors));
mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
mRendererList.push_back(mImpl->mRenderer);
#define DALI_TOOLKIT_INTERNAL_TEXT_VISUAL_H
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
WeakHandle<Actor> mControl; ///< The control where the renderer is added.
Constraint mColorConstraint{}; ///< Color constraint
Constraint mOpacityConstraint{}; ///< Opacity constraint
+ Property::Index mHasMultipleTextColorsIndex; ///< The index of uHasMultipleTextColors proeprty.
Property::Index mAnimatableTextColorPropertyIndex; ///< The index of animatable text color property registered by the control.
Property::Index mTextColorAnimatableIndex; ///< The index of uTextColorAnimatable property.
bool mRendererUpdateNeeded : 1; ///< The flag to indicate whether the renderer needs to be updated.
if(!url.empty())
{
mLocation = ResolveLocation(url);
- if(VisualUrl::TEXTURE != mLocation && VisualUrl::BUFFER != mLocation)
+ if(VisualUrl::TEXTURE != mLocation)
{
- // TEXTURE and BUFFER location url doesn't need type resolving, REGULAR_IMAGE is fine
+ // TEXTURE location url doesn't need type resolving, REGULAR_IMAGE is fine
mType = ResolveType(url);
}
}
return GetLocation(mUrl);
}
+std::string VisualUrl::GetLocationWithoutExtension() const
+{
+ return GetLocationWithoutExtension(mUrl);
+}
+
std::string VisualUrl::CreateTextureUrl(const std::string& location)
{
return "dali://" + location;
}
-std::string VisualUrl::CreateBufferUrl(const std::string& location)
+std::string VisualUrl::CreateBufferUrl(const std::string& location, const std::string_view& extension)
{
- return "enbuf://" + location;
+ return "enbuf://" + location + std::string(extension);
}
VisualUrl::ProtocolType VisualUrl::GetProtocolType(const std::string& url)
return url;
}
+std::string VisualUrl::GetLocationWithoutExtension(const std::string& url)
+{
+ const auto location = url.find("://");
+ if(std::string::npos != location)
+ {
+ const auto extension = url.find_last_of("."); // Find last position of '.' keyword.
+ const auto locationLength = extension != std::string::npos ? extension - (location + 3u) : std::string::npos;
+ return url.substr(location + 3u, locationLength); // 3 characters forwards from the start of ://, and end of last '.' keyword.
+ }
+ return url;
+}
+
} // namespace Internal
} // namespace Toolkit
// EXTERNAL INCLUDES
#include <cstdint>
#include <string>
+#include <string_view>
namespace Dali
{
std::string GetLocation() const;
/**
+ * @return the location part of the url without extension
+ */
+ std::string GetLocationWithoutExtension() const;
+
+ /**
* Helper to create a URL of type TEXTURE
* @param location the location of the texture
* @return the Url
/**
* Helper to create a URL of type BUFFER
- * @param location the location of the texture
+ * @param[in] location the location of the texture
+ * @param[in] extension the extension of url
* @return the Url
*/
- static std::string CreateBufferUrl(const std::string& location);
+ static std::string CreateBufferUrl(const std::string& location, const std::string_view& extension);
/**
* Helper to get a ProtocolType from url
*/
static std::string GetLocation(const std::string& url);
+ /**
+ * Helper to get a location from url without extension
+ * @param[in] url the location of the texture
+ * @return the location without extension
+ */
+ static std::string GetLocationWithoutExtension(const std::string& url);
+
private:
std::string mUrl;
Type mType;
{
const unsigned int TOOLKIT_MAJOR_VERSION = 2;
const unsigned int TOOLKIT_MINOR_VERSION = 2;
-const unsigned int TOOLKIT_MICRO_VERSION = 51;
+const unsigned int TOOLKIT_MICRO_VERSION = 52;
const char* const TOOLKIT_BUILD_DATE = __DATE__ " " __TIME__;
#ifdef DEBUG_ENABLED
Name: dali2-toolkit
Summary: Dali 3D engine Toolkit
-Version: 2.2.51
+Version: 2.2.52
Release: 1
Group: System/Libraries
License: Apache-2.0 and BSD-3-Clause and MIT