diff --git a/CHANGES.md b/CHANGES.md index cd1d736cbe81..721374cf53b6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,8 +3,10 @@ Change Log ### 1.57 - 2019-05-01 -##### Fixes :wrench: +##### Additions :tada: +* Added support for the `KHR_texture_transform` glTF extension. [#7549](https://github.com/AnalyticalGraphicsInc/cesium/pull/7549) +##### Fixes :wrench: * Fixed an error where `clampToHeightMostDetailed` or `sampleHeightMostDetailed` would crash if entities were created when the promise resolved. [#7690](https://github.com/AnalyticalGraphicsInc/cesium/pull/7690) ### 1.56.1 - 2019-04-02 diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js index 09ae462f5652..d32bdf8cfea5 100644 --- a/Source/Scene/Model.js +++ b/Source/Scene/Model.js @@ -252,6 +252,8 @@ define([ * {@link https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_unlit/README.md|KHR_materials_unlit} *
  • * {@link https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness/README.md|KHR_materials_pbrSpecularGlossiness} + *
  • + * {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_texture_transform/README.md|KHR_texture_transform} *
  • * *

    @@ -1296,6 +1298,8 @@ define([ * {@link https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_unlit/README.md|KHR_materials_unlit} *
  • * {@link https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness/README.md|KHR_materials_pbrSpecularGlossiness} + *
  • + * {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_texture_transform/README.md|KHR_texture_transform} *
  • * *

    @@ -2379,24 +2383,67 @@ define([ var rendererSamplers = model._rendererResources.samplers; var sampler = rendererSamplers[texture.sampler]; - sampler = defaultValue(sampler, new Sampler({ - wrapS : TextureWrap.REPEAT, - wrapT : TextureWrap.REPEAT - })); + if (!defined(sampler)) { + sampler = new Sampler({ + wrapS : TextureWrap.REPEAT, + wrapT : TextureWrap.REPEAT + }); + } + + var usesTextureTransform = false; + var materials = model.gltf.materials; + var materialsLength = materials.length; + for (var i = 0; i < materialsLength; ++i) { + var material = materials[i]; + if (defined(material.extensions) && defined(material.extensions.KHR_techniques_webgl)) { + var values = material.extensions.KHR_techniques_webgl.values; + for (var valueName in values) { + if (values.hasOwnProperty(valueName) && valueName.indexOf('Texture') !== -1) { + var value = values[valueName]; + if (value.index === gltfTexture.id && defined(value.extensions) && defined(value.extensions.KHR_texture_transform)) { + usesTextureTransform = true; + break; + } + } + } + } + if (usesTextureTransform) { + break; + } + } + + var wrapS = sampler.wrapS; + var wrapT = sampler.wrapT; + var minFilter = sampler.minificationFilter; + + if (usesTextureTransform && minFilter !== TextureMinificationFilter.LINEAR && minFilter !== TextureMinificationFilter.NEAREST) { + if (minFilter === TextureMinificationFilter.NEAREST_MIPMAP_NEAREST || minFilter === TextureMinificationFilter.NEAREST_MIPMAP_LINEAR) { + minFilter = TextureMinificationFilter.NEAREST; + } else { + minFilter = TextureMinificationFilter.LINEAR; + } + + sampler = new Sampler({ + wrapS : sampler.wrapS, + wrapT : sampler.wrapT, + textureMinificationFilter : minFilter, + textureMagnificationFilter : sampler.magnificationFilter + }); + } var internalFormat = gltfTexture.internalFormat; var mipmap = (!(defined(internalFormat) && PixelFormat.isCompressedFormat(internalFormat))) && - ((sampler.minificationFilter === TextureMinificationFilter.NEAREST_MIPMAP_NEAREST) || - (sampler.minificationFilter === TextureMinificationFilter.NEAREST_MIPMAP_LINEAR) || - (sampler.minificationFilter === TextureMinificationFilter.LINEAR_MIPMAP_NEAREST) || - (sampler.minificationFilter === TextureMinificationFilter.LINEAR_MIPMAP_LINEAR)); + ((minFilter === TextureMinificationFilter.NEAREST_MIPMAP_NEAREST) || + (minFilter === TextureMinificationFilter.NEAREST_MIPMAP_LINEAR) || + (minFilter === TextureMinificationFilter.LINEAR_MIPMAP_NEAREST) || + (minFilter === TextureMinificationFilter.LINEAR_MIPMAP_LINEAR)); var requiresNpot = mipmap || - (sampler.wrapS === TextureWrap.REPEAT) || - (sampler.wrapS === TextureWrap.MIRRORED_REPEAT) || - (sampler.wrapT === TextureWrap.REPEAT) || - (sampler.wrapT === TextureWrap.MIRRORED_REPEAT); + (wrapS === TextureWrap.REPEAT) || + (wrapS === TextureWrap.MIRRORED_REPEAT) || + (wrapT === TextureWrap.REPEAT) || + (wrapT === TextureWrap.MIRRORED_REPEAT); var tx; var source = gltfTexture.image; diff --git a/Source/Scene/ModelUtility.js b/Source/Scene/ModelUtility.js index 391ce8ee8efd..53a517e95c67 100644 --- a/Source/Scene/ModelUtility.js +++ b/Source/Scene/ModelUtility.js @@ -493,6 +493,7 @@ define([ 'KHR_techniques_webgl' : true, 'KHR_materials_unlit' : true, 'KHR_materials_pbrSpecularGlossiness' : true, + 'KHR_texture_transform' : true, 'WEB3D_quantized_attributes' : true, 'EXT_texture_webp' : true }; diff --git a/Source/Scene/processPbrMaterials.js b/Source/Scene/processPbrMaterials.js index ca2f77f6943f..d772999bc0ab 100644 --- a/Source/Scene/processPbrMaterials.js +++ b/Source/Scene/processPbrMaterials.js @@ -87,6 +87,43 @@ define([ defined(material.extensions.KHR_materials_pbrSpecularGlossiness); } + function addTextureCoordinates(gltf, textureName, generatedMaterialValues, defaultTexCoord, result) { + var texCoord; + if (defined(generatedMaterialValues[textureName + 'Offset'])) { + var textureIndex = generatedMaterialValues[textureName].index; + var sampler = gltf.samplers[gltf.textures[textureIndex].sampler]; + + var repeatS = sampler.wrapS === WebGLConstants.REPEAT ? 'true' : 'false'; + var repeatT = sampler.wrapT === WebGLConstants.REPEAT ? 'true' : 'false'; + + texCoord = textureName + 'Coord'; + result.fragmentShaderMain += ' vec2 ' + texCoord + ' = computeTexCoord(' + defaultTexCoord + ', ' + textureName + 'Offset, ' + textureName + 'Rotation, ' + textureName + 'Scale, ' + repeatS + ', ' + repeatT + ');\n'; + } else { + texCoord = defaultTexCoord; + } + return texCoord; + } + + var DEFAULT_TEXTURE_OFFSET = [0.0, 0.0]; + var DEFAULT_TEXTURE_ROTATION = [0.0]; + var DEFAULT_TEXTURE_SCALE = [1.0, 1.0]; + + function handleKHRTextureTransform(parameterName, value, generatedMaterialValues) { + if (parameterName.indexOf('Texture') === -1 || !defined(value.extensions) || !defined(value.extensions.KHR_texture_transform)) { + return; + } + + var uniformName = 'u_' + parameterName; + var extension = value.extensions.KHR_texture_transform; + generatedMaterialValues[uniformName + 'Offset'] = defaultValue(extension.offset, DEFAULT_TEXTURE_OFFSET); + generatedMaterialValues[uniformName + 'Rotation'] = defaultValue(extension.rotation, DEFAULT_TEXTURE_ROTATION); + generatedMaterialValues[uniformName + 'Scale'] = defaultValue(extension.scale, DEFAULT_TEXTURE_SCALE); + + if (defined(value.texCoord) && defined(extension.texCoord)) { + generatedMaterialValues[uniformName].texCoord = extension.texCoord; + } + } + function generateTechnique(gltf, material, materialIndex, generatedMaterialValues, primitiveByMaterial, options) { var addBatchIdToGeneratedShaders = defaultValue(options.addBatchIdToGeneratedShaders, false); @@ -99,12 +136,15 @@ define([ var uniformName; var parameterName; + var value; var pbrMetallicRoughness = material.pbrMetallicRoughness; if (defined(pbrMetallicRoughness) && !useSpecGloss) { for (parameterName in pbrMetallicRoughness) { if (pbrMetallicRoughness.hasOwnProperty(parameterName)) { + value = pbrMetallicRoughness[parameterName]; uniformName = 'u_' + parameterName; - generatedMaterialValues[uniformName] = pbrMetallicRoughness[parameterName]; + generatedMaterialValues[uniformName] = value; + handleKHRTextureTransform(parameterName, value, generatedMaterialValues); } } } @@ -113,16 +153,20 @@ define([ var pbrSpecularGlossiness = material.extensions.KHR_materials_pbrSpecularGlossiness; for (parameterName in pbrSpecularGlossiness) { if (pbrSpecularGlossiness.hasOwnProperty(parameterName)) { + value = pbrSpecularGlossiness[parameterName]; uniformName = 'u_' + parameterName; - generatedMaterialValues[uniformName] = pbrSpecularGlossiness[parameterName]; + generatedMaterialValues[uniformName] = value; + handleKHRTextureTransform(parameterName, value, generatedMaterialValues); } } } for (var additional in material) { if (material.hasOwnProperty(additional) && ((additional.indexOf('Texture') >= 0) || additional.indexOf('Factor') >= 0)) { + value = material[additional]; uniformName = 'u_' + additional; - generatedMaterialValues[uniformName] = material[additional]; + generatedMaterialValues[uniformName] = value; + handleKHRTextureTransform(additional, value, generatedMaterialValues); } } @@ -371,19 +415,42 @@ define([ fragmentShader += 'varying vec4 v_tangent;\n'; } + var fragmentShaderMain = ''; + // Add texture coordinates if the material uses them - var v_texcoord; + var v_texCoord; + var normalTexCoord; + var baseColorTexCoord; + var specularGlossinessTexCoord; + var diffuseTexCoord; + var metallicRoughnessTexCoord; + var occlusionTexCoord; + var emissiveTexCoord; + if (hasTexCoords) { techniqueAttributes.a_texcoord_0 = { semantic : 'TEXCOORD_0' }; - v_texcoord = 'v_texcoord_0'; + v_texCoord = 'v_texcoord_0'; vertexShader += 'attribute vec2 a_texcoord_0;\n'; - vertexShader += 'varying vec2 ' + v_texcoord + ';\n'; - vertexShaderMain += ' ' + v_texcoord + ' = a_texcoord_0;\n'; + vertexShader += 'varying vec2 ' + v_texCoord + ';\n'; + vertexShaderMain += ' ' + v_texCoord + ' = a_texcoord_0;\n'; + + fragmentShader += 'varying vec2 ' + v_texCoord + ';\n'; + + var result = { + fragmentShaderMain : fragmentShaderMain + }; + normalTexCoord = addTextureCoordinates(gltf, 'u_normalTexture', generatedMaterialValues, v_texCoord, result); + baseColorTexCoord = addTextureCoordinates(gltf, 'u_baseColorTexture', generatedMaterialValues, v_texCoord, result); + specularGlossinessTexCoord = addTextureCoordinates(gltf, 'u_specularGlossinessTexture', generatedMaterialValues, v_texCoord, result); + diffuseTexCoord = addTextureCoordinates(gltf, 'u_diffuseTexture', generatedMaterialValues, v_texCoord, result); + metallicRoughnessTexCoord = addTextureCoordinates(gltf, 'u_metallicRoughnessTexture', generatedMaterialValues, v_texCoord, result); + occlusionTexCoord = addTextureCoordinates(gltf, 'u_occlusionTexture', generatedMaterialValues, v_texCoord, result); + emissiveTexCoord = addTextureCoordinates(gltf, 'u_emmissiveTexture', generatedMaterialValues, v_texCoord, result); - fragmentShader += 'varying vec2 ' + v_texcoord + ';\n'; + fragmentShaderMain = result.fragmentShaderMain; } // Add skinning information if available @@ -488,6 +555,20 @@ define([ '#endif \n' + '}\n\n'; + fragmentShader += + 'vec2 computeTexCoord(vec2 texCoords, vec2 offset, float rotation, vec2 scale, bool repeatS, bool repeatT) \n' + + '{\n' + + ' rotation = -rotation; \n' + + ' mat3 transform = mat3(\n' + + ' cos(rotation) * scale.x, sin(rotation) * scale.x, 0.0, \n' + + ' -sin(rotation) * scale.y, cos(rotation) * scale.y, 0.0, \n' + + ' offset.x, offset.y, 1.0); \n' + + ' vec2 transformedTexCoords = (transform * vec3(fract(texCoords), 1.0)).xy; \n' + + ' transformedTexCoords.x = repeatS ? fract(transformedTexCoords.x) : clamp(transformedTexCoords.x, 0.0, 1.0); \n' + + ' transformedTexCoords.y = repeatT ? fract(transformedTexCoords.y) : clamp(transformedTexCoords.y, 0.0, 1.0); \n' + + ' return transformedTexCoords; \n' + + '}\n\n'; + fragmentShader += '#ifdef USE_IBL_LIGHTING \n'; fragmentShader += 'uniform vec2 gltf_iblFactor; \n'; fragmentShader += '#endif \n'; @@ -496,6 +577,7 @@ define([ fragmentShader += '#endif \n'; fragmentShader += 'void main(void) \n{\n'; + fragmentShader += fragmentShaderMain; // Add normal mapping to fragment shader if (hasNormals) { @@ -506,7 +588,7 @@ define([ fragmentShader += ' vec3 t = normalize(v_tangent.xyz);\n'; fragmentShader += ' vec3 b = normalize(cross(ng, t) * v_tangent.w);\n'; fragmentShader += ' mat3 tbn = mat3(t, b, ng);\n'; - fragmentShader += ' vec3 n = texture2D(u_normalTexture, ' + v_texcoord + ').rgb;\n'; + fragmentShader += ' vec3 n = texture2D(u_normalTexture, ' + normalTexCoord + ').rgb;\n'; fragmentShader += ' n = normalize(tbn * (2.0 * n - 1.0));\n'; } else { // Add standard derivatives extension @@ -518,13 +600,13 @@ define([ fragmentShader += '#ifdef GL_OES_standard_derivatives\n'; fragmentShader += ' vec3 pos_dx = dFdx(v_positionEC);\n'; fragmentShader += ' vec3 pos_dy = dFdy(v_positionEC);\n'; - fragmentShader += ' vec3 tex_dx = dFdx(vec3(' + v_texcoord + ',0.0));\n'; - fragmentShader += ' vec3 tex_dy = dFdy(vec3(' + v_texcoord + ',0.0));\n'; + fragmentShader += ' vec3 tex_dx = dFdx(vec3(' + normalTexCoord + ',0.0));\n'; + fragmentShader += ' vec3 tex_dy = dFdy(vec3(' + normalTexCoord + ',0.0));\n'; fragmentShader += ' vec3 t = (tex_dy.t * pos_dx - tex_dx.t * pos_dy) / (tex_dx.s * tex_dy.t - tex_dy.s * tex_dx.t);\n'; fragmentShader += ' t = normalize(t - ng * dot(ng, t));\n'; fragmentShader += ' vec3 b = normalize(cross(ng, t));\n'; fragmentShader += ' mat3 tbn = mat3(t, b, ng);\n'; - fragmentShader += ' vec3 n = texture2D(u_normalTexture, ' + v_texcoord + ').rgb;\n'; + fragmentShader += ' vec3 n = texture2D(u_normalTexture, ' + normalTexCoord + ').rgb;\n'; fragmentShader += ' n = normalize(tbn * (2.0 * n - 1.0));\n'; fragmentShader += '#else\n'; fragmentShader += ' vec3 n = ng;\n'; @@ -543,7 +625,7 @@ define([ // Add base color to fragment shader if (defined(generatedMaterialValues.u_baseColorTexture)) { - fragmentShader += ' vec4 baseColorWithAlpha = SRGBtoLINEAR4(texture2D(u_baseColorTexture, ' + v_texcoord + '));\n'; + fragmentShader += ' vec4 baseColorWithAlpha = SRGBtoLINEAR4(texture2D(u_baseColorTexture, ' + baseColorTexCoord + '));\n'; if (defined(generatedMaterialValues.u_baseColorFactor)) { fragmentShader += ' baseColorWithAlpha *= u_baseColorFactor;\n'; } @@ -562,7 +644,7 @@ define([ if (hasNormals) { if (useSpecGloss) { if (defined(generatedMaterialValues.u_specularGlossinessTexture)) { - fragmentShader += ' vec4 specularGlossiness = SRGBtoLINEAR4(texture2D(u_specularGlossinessTexture, ' + v_texcoord + '));\n'; + fragmentShader += ' vec4 specularGlossiness = SRGBtoLINEAR4(texture2D(u_specularGlossinessTexture, ' + specularGlossinessTexCoord + '));\n'; fragmentShader += ' vec3 specular = specularGlossiness.rgb;\n'; fragmentShader += ' float glossiness = specularGlossiness.a;\n'; if (defined(generatedMaterialValues.u_specularFactor)) { @@ -584,7 +666,7 @@ define([ } } if (defined(generatedMaterialValues.u_diffuseTexture)) { - fragmentShader += ' vec4 diffuse = SRGBtoLINEAR4(texture2D(u_diffuseTexture, ' + v_texcoord + '));\n'; + fragmentShader += ' vec4 diffuse = SRGBtoLINEAR4(texture2D(u_diffuseTexture, ' + diffuseTexCoord + '));\n'; if (defined(generatedMaterialValues.u_diffuseFactor)) { fragmentShader += ' diffuse *= u_diffuseFactor;\n'; } @@ -594,7 +676,7 @@ define([ fragmentShader += ' vec4 diffuse = vec4(1.0);\n'; } } else if (defined(generatedMaterialValues.u_metallicRoughnessTexture)) { - fragmentShader += ' vec3 metallicRoughness = texture2D(u_metallicRoughnessTexture, ' + v_texcoord + ').rgb;\n'; + fragmentShader += ' vec3 metallicRoughness = texture2D(u_metallicRoughnessTexture, ' + metallicRoughnessTexCoord + ').rgb;\n'; fragmentShader += ' float metalness = clamp(metallicRoughness.b, 0.0, 1.0);\n'; fragmentShader += ' float roughness = clamp(metallicRoughness.g, 0.04, 1.0);\n'; if (defined(generatedMaterialValues.u_metallicFactor)) { @@ -763,10 +845,10 @@ define([ // Ignore occlusion and emissive when unlit if (!isUnlit) { if (defined(generatedMaterialValues.u_occlusionTexture)) { - fragmentShader += ' color *= texture2D(u_occlusionTexture, ' + v_texcoord + ').r;\n'; + fragmentShader += ' color *= texture2D(u_occlusionTexture, ' + occlusionTexCoord + ').r;\n'; } if (defined(generatedMaterialValues.u_emissiveTexture)) { - fragmentShader += ' vec3 emissive = SRGBtoLINEAR3(texture2D(u_emissiveTexture, ' + v_texcoord + ').rgb);\n'; + fragmentShader += ' vec3 emissive = SRGBtoLINEAR3(texture2D(u_emissiveTexture, ' + emissiveTexCoord + ').rgb);\n'; if (defined(generatedMaterialValues.u_emissiveFactor)) { fragmentShader += ' emissive *= u_emissiveFactor;\n'; } @@ -831,6 +913,16 @@ define([ } function getPBRValueType(paramName) { + if (paramName.indexOf('Offset') !== -1) { + return WebGLConstants.FLOAT_VEC2; + } else if (paramName.indexOf('Rotation') !== -1) { + return WebGLConstants.FLOAT; + } else if (paramName.indexOf('Scale') !== -1) { + return WebGLConstants.FLOAT_VEC2; + } else if (paramName.indexOf('Texture') !== -1) { + return WebGLConstants.SAMPLER_2D; + } + switch (paramName) { case 'u_baseColorFactor': return WebGLConstants.FLOAT_VEC4; @@ -838,16 +930,6 @@ define([ return WebGLConstants.FLOAT; case 'u_roughnessFactor': return WebGLConstants.FLOAT; - case 'u_baseColorTexture': - return WebGLConstants.SAMPLER_2D; - case 'u_metallicRoughnessTexture': - return WebGLConstants.SAMPLER_2D; - case 'u_normalTexture': - return WebGLConstants.SAMPLER_2D; - case 'u_occlusionTexture': - return WebGLConstants.SAMPLER_2D; - case 'u_emissiveTexture': - return WebGLConstants.SAMPLER_2D; case 'u_emissiveFactor': return WebGLConstants.FLOAT_VEC3; // Specular Glossiness Types @@ -857,10 +939,6 @@ define([ return WebGLConstants.FLOAT_VEC3; case 'u_glossinessFactor': return WebGLConstants.FLOAT; - case 'u_diffuseTexture': - return WebGLConstants.SAMPLER_2D; - case 'u_specularGlossinessTexture': - return WebGLConstants.SAMPLER_2D; } } diff --git a/Specs/Data/Models/Box-Texture-Transform/CesiumTexturedBoxTest.gltf b/Specs/Data/Models/Box-Texture-Transform/CesiumTexturedBoxTest.gltf new file mode 100644 index 000000000000..c16c964666b9 --- /dev/null +++ b/Specs/Data/Models/Box-Texture-Transform/CesiumTexturedBoxTest.gltf @@ -0,0 +1,188 @@ +{ + "asset": { + "generator": "COLLADA2GLTF", + "version": "2.0" + }, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "scene": 0, + "nodes": [ + { + "children": [ + 1 + ], + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + -1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ], + "name": "Z_UP" + }, + { + "mesh": 0, + "name": "Mesh" + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 2, + "TEXCOORD_0": 3 + }, + "indices": 0, + "mode": 4, + "material": 0 + } + ], + "name": "Mesh" + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5123, + "count": 36, + "max": [ + 23 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 288, + "componentType": 5126, + "count": 24, + "max": [ + 0.5, + 0.5, + 0.5 + ], + "min": [ + -0.5, + -0.5, + -0.5 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 6.0, + 1.0 + ], + "min": [ + 0.0, + 0.0 + ], + "type": "VEC2" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 0, + "extensions": { + "KHR_texture_transform": { + "scale": [5.0, 3.0] + } + } + }, + "metallicFactor": 0.0 + }, + "name": "Texture" + } + ], + "textures": [ + { + "sampler": 0, + "source": 0 + } + ], + "images": [ + { + "uri": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANMAAADTCAIAAACUZbGOAAAACXBIWXMAAAsTAAALEwEAmpwYAAA4JmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMwMTQgNzkuMTU2Nzk3LCAyMDE0LzA4LzIwLTA5OjUzOjAyICAgICAgICAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgICAgICAgICAgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIgogICAgICAgICAgICB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIKICAgICAgICAgICAgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIj4KICAgICAgICAgPHhtcDpDcmVhdG9yVG9vbD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNCAoV2luZG93cyk8L3htcDpDcmVhdG9yVG9vbD4KICAgICAgICAgPHhtcDpDcmVhdGVEYXRlPjIwMTUtMDMtMDJUMDg6NDc6NTQtMDU6MDA8L3htcDpDcmVhdGVEYXRlPgogICAgICAgICA8eG1wOk1vZGlmeURhdGU+MjAxNS0wMy0wMlQwODo1MTo1Mi0wNTowMDwveG1wOk1vZGlmeURhdGU+CiAgICAgICAgIDx4bXA6TWV0YWRhdGFEYXRlPjIwMTUtMDMtMDJUMDg6NTE6NTItMDU6MDA8L3htcDpNZXRhZGF0YURhdGU+CiAgICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2UvcG5nPC9kYzpmb3JtYXQ+CiAgICAgICAgIDxwaG90b3Nob3A6Q29sb3JNb2RlPjM8L3Bob3Rvc2hvcDpDb2xvck1vZGU+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6ZmFhN2VhN2MtN2ZlZS0yZTQ3LWExNmUtMGVjNTc2YTkzZmY2PC94bXBNTTpJbnN0YW5jZUlEPgogICAgICAgICA8eG1wTU06RG9jdW1lbnRJRD54bXAuZGlkOmZhYTdlYTdjLTdmZWUtMmU0Ny1hMTZlLTBlYzU3NmE5M2ZmNjwveG1wTU06RG9jdW1lbnRJRD4KICAgICAgICAgPHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD54bXAuZGlkOmZhYTdlYTdjLTdmZWUtMmU0Ny1hMTZlLTBlYzU3NmE5M2ZmNjwveG1wTU06T3JpZ2luYWxEb2N1bWVudElEPgogICAgICAgICA8eG1wTU06SGlzdG9yeT4KICAgICAgICAgICAgPHJkZjpTZXE+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPmNyZWF0ZWQ8L3N0RXZ0OmFjdGlvbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0Omluc3RhbmNlSUQ+eG1wLmlpZDpmYWE3ZWE3Yy03ZmVlLTJlNDctYTE2ZS0wZWM1NzZhOTNmZjY8L3N0RXZ0Omluc3RhbmNlSUQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDp3aGVuPjIwMTUtMDMtMDJUMDg6NDc6NTQtMDU6MDA8L3N0RXZ0OndoZW4+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpzb2Z0d2FyZUFnZW50PkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE0IChXaW5kb3dzKTwvc3RFdnQ6c29mdHdhcmVBZ2VudD4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgIDwvcmRmOlNlcT4KICAgICAgICAgPC94bXBNTTpIaXN0b3J5PgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICAgICA8dGlmZjpYUmVzb2x1dGlvbj43MjAwMDAvMTAwMDA8L3RpZmY6WFJlc29sdXRpb24+CiAgICAgICAgIDx0aWZmOllSZXNvbHV0aW9uPjcyMDAwMC8xMDAwMDwvdGlmZjpZUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6UmVzb2x1dGlvblVuaXQ+MjwvdGlmZjpSZXNvbHV0aW9uVW5pdD4KICAgICAgICAgPGV4aWY6Q29sb3JTcGFjZT42NTUzNTwvZXhpZjpDb2xvclNwYWNlPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+MjExPC9leGlmOlBpeGVsWERpbWVuc2lvbj4KICAgICAgICAgPGV4aWY6UGl4ZWxZRGltZW5zaW9uPjIxMTwvZXhpZjpQaXhlbFlEaW1lbnNpb24+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAg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" + } + ], + "samplers": [ + { + "magFilter": 9729, + "minFilter": 9986, + "wrapS": 10497, + "wrapT": 10497 + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 768, + "byteLength": 72, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 576, + "byteStride": 12, + "target": 34962 + }, + { + "buffer": 0, + "byteOffset": 576, + "byteLength": 192, + "byteStride": 8, + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 840, + "uri": "data:application/octet-stream;base64,AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAC/AADAQAAAAAAAAKBAAAAAAAAAwED+/38/AACgQP7/fz8AAIBAAAAAAAAAoEAAAAAAAACAQAAAgD8AAKBAAACAPwAAAEAAAAAAAACAPwAAAAAAAABAAACAPwAAgD8AAIA/AABAQAAAAAAAAIBAAAAAAAAAQEAAAIA/AACAQAAAgD8AAEBAAAAAAAAAAEAAAAAAAABAQAAAgD8AAABAAACAPwAAAAAAAAAAAAAAAP7/fz8AAIA/AAAAAAAAgD/+/38/AAABAAIAAwACAAEABAAFAAYABwAGAAUACAAJAAoACwAKAAkADAANAA4ADwAOAA0AEAARABIAEwASABEAFAAVABYAFwAWABUA" + } + ] +} diff --git a/Specs/Scene/ModelSpec.js b/Specs/Scene/ModelSpec.js index 890c5c3db4ea..7beafda1a432 100644 --- a/Specs/Scene/ModelSpec.js +++ b/Specs/Scene/ModelSpec.js @@ -90,6 +90,7 @@ defineSuite([ var texturedBoxCRNEmbeddedUrl = './Data/Models/Box-Textured-CRN-Embedded/CesiumTexturedBoxTest.gltf'; var texturedBoxCustomUrl = './Data/Models/Box-Textured-Custom/CesiumTexturedBoxTest.gltf'; var texturedBoxKhrBinaryUrl = './Data/Models/Box-Textured-Binary/CesiumTexturedBoxTest.glb'; + var texturedBoxTextureTransformUrl = './Data/Models/Box-Texture-Transform/CesiumTexturedBoxTest.gltf'; var texturedBoxWebpUrl = './Data/Models/Box-Textured-Webp/CesiumBoxWebp.gltf'; var boxRtcUrl = './Data/Models/Box-RTC/Box.gltf'; var boxEcefUrl = './Data/Models/Box-ECEF/ecef.gltf'; @@ -1208,6 +1209,16 @@ defineSuite([ }); }); + it('renders textured box with KHR_texture_transform extension', function() { + return loadModel(texturedBoxTextureTransformUrl, { + incrementallyLoadTextures : false + }).then(function(m) { + verifyRender(m); + expect(Object.keys(m._rendererResources.textures).length).toBe(1); + primitives.remove(m); + }); + }); + it('renders textured box with WebP texture', function() { if (!FeatureDetection.supportsWebP()) { return;