diff --git a/Apps/Sandcastle/gallery/Materials.html b/Apps/Sandcastle/gallery/Materials.html
index 4837b977d00f..e98c8f570e1f 100644
--- a/Apps/Sandcastle/gallery/Materials.html
+++ b/Apps/Sandcastle/gallery/Materials.html
@@ -202,6 +202,28 @@
});
}
+function applyCompressedTextureMaterial(primitive, scene) {
+ Sandcastle.declare(applyCompressedTextureMaterial); // For highlighting in Sandcastle.
+
+ var compressedImageUrl;
+ if (scene.getCompressedTextureFormatSupported('s3tc')) {
+ compressedImageUrl = '../images/LogoDXT1.ktx';
+ } else if (scene.getCompressedTextureFormatSupported('etc1')) {
+ compressedImageUrl = '../images/LogoETC1.ktx';
+ } else if (scene.getCompressedTextureFormatSupported('pvrtc')) {
+ compressedImageUrl = '../images/LogoPVR.ktx';
+ }
+
+ primitive.appearance.material = new Cesium.Material({
+ fabric : {
+ type : 'Image',
+ uniforms : {
+ image : compressedImageUrl
+ }
+ }
+ });
+}
+
function applyNormalMapMaterial(primitive, scene) {
Sandcastle.declare(applyNormalMapMaterial); // For highlighting in Sandcastle.
primitive.appearance.material = new Cesium.Material({
@@ -310,6 +332,13 @@
applyImageMaterial(rectangle, scene);
Sandcastle.highlight(applyImageMaterial);
}
+ }, {
+ text : 'Compressed Image',
+ onselect : function() {
+ toggleRectangleVisibility();
+ applyCompressedTextureMaterial(rectangle, scene);
+ Sandcastle.highlight(applyCompressedTextureMaterial);
+ }
}]);
Sandcastle.addToolbarMenu([{
@@ -443,7 +472,7 @@
Sandcastle.highlight(applyPolylineOutlineMaterial);
}
}]);
-
+
document.getElementById('toolbar').style.width = '10%';
}
diff --git a/Apps/Sandcastle/images/LogoDXT1.ktx b/Apps/Sandcastle/images/LogoDXT1.ktx
new file mode 100644
index 000000000000..73598d1c8d30
Binary files /dev/null and b/Apps/Sandcastle/images/LogoDXT1.ktx differ
diff --git a/Apps/Sandcastle/images/LogoETC1.ktx b/Apps/Sandcastle/images/LogoETC1.ktx
new file mode 100644
index 000000000000..9d8b88d7f541
Binary files /dev/null and b/Apps/Sandcastle/images/LogoETC1.ktx differ
diff --git a/Apps/Sandcastle/images/LogoPVR.ktx b/Apps/Sandcastle/images/LogoPVR.ktx
new file mode 100644
index 000000000000..fd3461c7bbbb
Binary files /dev/null and b/Apps/Sandcastle/images/LogoPVR.ktx differ
diff --git a/CHANGES.md b/CHANGES.md
index e43d58e8c4c1..5f6648d972ac 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -4,6 +4,11 @@ Change Log
### 1.31 - 2017-03-01
* Enable rendering `GroundPrimitives` on hardware without the `EXT_frag_depth` extension; however, this could cause artifacts for certain viewing angles.
+* Added compressed texture support. [#4758](https://github.com/AnalyticalGraphicsInc/cesium/pull/4758)
+ * glTF models and imagery layers can now reference [KTX](https://www.khronos.org/opengles/sdk/tools/KTX/) textures and textures compressed with [crunch](https://github.com/BinomialLLC/crunch).
+ * Added `loadKTX`, to load KTX textures, and `loadCRN` to load crunch compressed textures.
+ * Added new `PixelFormat` and `WebGLConstants` enums from WebGL extensions `WEBGL_compressed_s3tc`, `WEBGL_compressed_texture_pvrtc`, and `WEBGL_compressed_texture_etc1`.
+ * Added `CompressedTextureBuffer`.
### 1.30 - 2017-02-01
diff --git a/LICENSE.md b/LICENSE.md
index 5b0204885d04..e95d8ff924ac 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -288,6 +288,85 @@ OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
+### crunch
+
+https://github.com/BinomialLLC/crunch
+
+>crunch/crnlib uses the ZLIB license:
+>http://opensource.org/licenses/Zlib
+>
+>Copyright (c) 2010-2016 Richard Geldreich, Jr. and Binomial LLC
+>
+>This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+>
+>Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+>
+>1. The origin of this software must not be misrepresented; you must not
+claim that you wrote the original software. If you use this software
+in a product, an acknowledgment in the product documentation would be
+appreciated but is not required.
+>
+>2. Altered source versions must be plainly marked as such, and must not be
+misrepresented as being the original software.
+>
+>3. This notice may not be removed or altered from any source distribution.
+
+### crunch_lib.cpp
+
+https://github.com/Apress/html5-game-dev-insights/blob/master/jones_ch21/crunch_webgl/crunch_js/crunch_lib.cpp
+
+>Copyright (c) 2013, Evan Parker, Brandon Jones. All rights reserved.
+>
+>Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+>
+> * Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+> * Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+>
+>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+### texture-tester
+
+https://github.com/toji/texture-tester
+
+>Copyright (c) 2014, Brandon Jones. All rights reserved.
+>
+>Redistribution and use in source and binary forms, with or without modification,
+>are permitted provided that the following conditions are met:
+>
+>* Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+>* Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+>
+>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
Tests
=====
diff --git a/Source/Core/CompressedTextureBuffer.js b/Source/Core/CompressedTextureBuffer.js
new file mode 100644
index 000000000000..2bee0c470813
--- /dev/null
+++ b/Source/Core/CompressedTextureBuffer.js
@@ -0,0 +1,93 @@
+/*global define*/
+define([
+ './defined',
+ './defineProperties'
+ ], function(
+ defined,
+ defineProperties
+ ) {
+ 'use strict';
+
+ /**
+ * Describes a compressed texture and contains a compressed texture buffer.
+ *
+ * @param {PixelFormat} internalFormat The pixel format of the compressed texture.
+ * @param {Number} width The width of the texture.
+ * @param {Number} height The height of the texture.
+ * @param {Uint8Array} buffer The compressed texture buffer.
+ */
+ function CompressedTextureBuffer(internalFormat, width, height, buffer) {
+ this._format = internalFormat;
+ this._width = width;
+ this._height = height;
+ this._buffer = buffer;
+ }
+
+ defineProperties(CompressedTextureBuffer.prototype, {
+ /**
+ * The format of the compressed texture.
+ * @type PixelFormat
+ * @readonly
+ */
+ internalFormat : {
+ get : function() {
+ return this._format;
+ }
+ },
+ /**
+ * The width of the texture.
+ * @type Number
+ * @readonly
+ */
+ width : {
+ get : function() {
+ return this._width;
+ }
+ },
+ /**
+ * The height of the texture.
+ * @type Number
+ * @readonly
+ */
+ height : {
+ get : function() {
+ return this._height;
+ }
+ },
+ /**
+ * The compressed texture buffer.
+ * @type Uint8Array
+ * @readonly
+ */
+ bufferView : {
+ get : function() {
+ return this._buffer;
+ }
+ }
+ });
+
+ /**
+ * Creates a shallow clone of a compressed texture buffer.
+ *
+ * @param {CompressedTextureBuffer} object The compressed texture buffer to be cloned.
+ * @return {CompressedTextureBuffer} A shallow clone of the compressed texture buffer.
+ */
+ CompressedTextureBuffer.clone = function(object) {
+ if (!defined(object)) {
+ return undefined;
+ }
+
+ return new CompressedTextureBuffer(object._format, object._width, object._height, object._buffer);
+ };
+
+ /**
+ * Creates a shallow clone of this compressed texture buffer.
+ *
+ * @return {CompressedTextureBuffer} A shallow clone of the compressed texture buffer.
+ */
+ CompressedTextureBuffer.prototype.clone = function() {
+ return CompressedTextureBuffer.clone(this);
+ };
+
+ return CompressedTextureBuffer;
+});
\ No newline at end of file
diff --git a/Source/Core/PixelFormat.js b/Source/Core/PixelFormat.js
index 2b95611e7603..ee8f9c48c12d 100644
--- a/Source/Core/PixelFormat.js
+++ b/Source/Core/PixelFormat.js
@@ -69,6 +69,78 @@ define([
*/
LUMINANCE_ALPHA : WebGLConstants.LUMINANCE_ALPHA,
+ /**
+ * A pixel format containing red, green, and blue channels that is DXT1 compressed.
+ *
+ * @type {Number}
+ * @constant
+ */
+ RGB_DXT1 : WebGLConstants.COMPRESSED_RGB_S3TC_DXT1_EXT,
+
+ /**
+ * A pixel format containing red, green, blue, and alpha channels that is DXT1 compressed.
+ *
+ * @type {Number}
+ * @constant
+ */
+ RGBA_DXT1 : WebGLConstants.COMPRESSED_RGBA_S3TC_DXT1_EXT,
+
+ /**
+ * A pixel format containing red, green, blue, and alpha channels that is DXT3 compressed.
+ *
+ * @type {Number}
+ * @constant
+ */
+ RGBA_DXT3 : WebGLConstants.COMPRESSED_RGBA_S3TC_DXT3_EXT,
+
+ /**
+ * A pixel format containing red, green, blue, and alpha channels that is DXT5 compressed.
+ *
+ * @type {Number}
+ * @constant
+ */
+ RGBA_DXT5 : WebGLConstants.COMPRESSED_RGBA_S3TC_DXT5_EXT,
+
+ /**
+ * A pixel format containing red, green, and blue channels that is PVR 4bpp compressed.
+ *
+ * @type {Number}
+ * @constant
+ */
+ RGB_PVRTC_4BPPV1 : WebGLConstants.COMPRESSED_RGB_PVRTC_4BPPV1_IMG,
+
+ /**
+ * A pixel format containing red, green, and blue channels that is PVR 2bpp compressed.
+ *
+ * @type {Number}
+ * @constant
+ */
+ RGB_PVRTC_2BPPV1 : WebGLConstants.COMPRESSED_RGB_PVRTC_2BPPV1_IMG,
+
+ /**
+ * A pixel format containing red, green, blue, and alpha channels that is PVR 4bpp compressed.
+ *
+ * @type {Number}
+ * @constant
+ */
+ RGBA_PVRTC_4BPPV1 : WebGLConstants.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG,
+
+ /**
+ * A pixel format containing red, green, blue, and alpha channels that is PVR 2bpp compressed.
+ *
+ * @type {Number}
+ * @constant
+ */
+ RGBA_PVRTC_2BPPV1 : WebGLConstants.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG,
+
+ /**
+ * A pixel format containing red, green, and blue channels that is ETC1 compressed.
+ *
+ * @type {Number}
+ * @constant
+ */
+ RGB_ETC1 : WebGLConstants.COMPRESSED_RGB_ETC1_WEBGL,
+
/**
* @private
*/
@@ -79,7 +151,16 @@ define([
pixelFormat === PixelFormat.RGB ||
pixelFormat === PixelFormat.RGBA ||
pixelFormat === PixelFormat.LUMINANCE ||
- pixelFormat === PixelFormat.LUMINANCE_ALPHA;
+ pixelFormat === PixelFormat.LUMINANCE_ALPHA ||
+ pixelFormat === PixelFormat.RGB_DXT1 ||
+ pixelFormat === PixelFormat.RGBA_DXT1 ||
+ pixelFormat === PixelFormat.RGBA_DXT3 ||
+ pixelFormat === PixelFormat.RGBA_DXT5 ||
+ pixelFormat === PixelFormat.RGB_PVRTC_4BPPV1 ||
+ pixelFormat === PixelFormat.RGB_PVRTC_2BPPV1 ||
+ pixelFormat === PixelFormat.RGBA_PVRTC_4BPPV1 ||
+ pixelFormat === PixelFormat.RGBA_PVRTC_2BPPV1 ||
+ pixelFormat === PixelFormat.RGB_ETC1;
},
/**
@@ -99,6 +180,75 @@ define([
isDepthFormat : function(pixelFormat) {
return pixelFormat === PixelFormat.DEPTH_COMPONENT ||
pixelFormat === PixelFormat.DEPTH_STENCIL;
+ },
+
+ /**
+ * @private
+ */
+ isCompressedFormat : function(pixelFormat) {
+ return pixelFormat === PixelFormat.RGB_DXT1 ||
+ pixelFormat === PixelFormat.RGBA_DXT1 ||
+ pixelFormat === PixelFormat.RGBA_DXT3 ||
+ pixelFormat === PixelFormat.RGBA_DXT5 ||
+ pixelFormat === PixelFormat.RGB_PVRTC_4BPPV1 ||
+ pixelFormat === PixelFormat.RGB_PVRTC_2BPPV1 ||
+ pixelFormat === PixelFormat.RGBA_PVRTC_4BPPV1 ||
+ pixelFormat === PixelFormat.RGBA_PVRTC_2BPPV1 ||
+ pixelFormat === PixelFormat.RGB_ETC1;
+ },
+
+ /**
+ * @private
+ */
+ isDXTFormat : function(pixelFormat) {
+ return pixelFormat === PixelFormat.RGB_DXT1 ||
+ pixelFormat === PixelFormat.RGBA_DXT1 ||
+ pixelFormat === PixelFormat.RGBA_DXT3 ||
+ pixelFormat === PixelFormat.RGBA_DXT5;
+ },
+
+ /**
+ * @private
+ */
+ isPVRTCFormat : function(pixelFormat) {
+ return pixelFormat === PixelFormat.RGB_PVRTC_4BPPV1 ||
+ pixelFormat === PixelFormat.RGB_PVRTC_2BPPV1 ||
+ pixelFormat === PixelFormat.RGBA_PVRTC_4BPPV1 ||
+ pixelFormat === PixelFormat.RGBA_PVRTC_2BPPV1;
+ },
+
+ /**
+ * @private
+ */
+ isETC1Format : function(pixelFormat) {
+ return pixelFormat === PixelFormat.RGB_ETC1;
+ },
+
+ /**
+ * @private
+ */
+ compressedTextureSize : function(pixelFormat, width, height) {
+ switch (pixelFormat) {
+ case PixelFormat.RGB_DXT1:
+ case PixelFormat.RGBA_DXT1:
+ case PixelFormat.RGB_ETC1:
+ return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * 8;
+
+ case PixelFormat.RGBA_DXT3:
+ case PixelFormat.RGBA_DXT5:
+ return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * 16;
+
+ case PixelFormat.RGB_PVRTC_4BPPV1:
+ case PixelFormat.RGBA_PVRTC_4BPPV1:
+ return Math.floor((Math.max(width, 8) * Math.max(height, 8) * 4 + 7) / 8);
+
+ case PixelFormat.RGB_PVRTC_2BPPV1:
+ case PixelFormat.RGBA_PVRTC_2BPPV1:
+ return Math.floor((Math.max(width, 16) * Math.max(height, 8) * 2 + 7) / 8);
+
+ default:
+ return 0;
+ }
}
};
diff --git a/Source/Core/WebGLConstants.js b/Source/Core/WebGLConstants.js
index 56ab401396ad..9419bf5becbc 100644
--- a/Source/Core/WebGLConstants.js
+++ b/Source/Core/WebGLConstants.js
@@ -315,6 +315,21 @@ define([
UNPACK_COLORSPACE_CONVERSION_WEBGL : 0x9243,
BROWSER_DEFAULT_WEBGL : 0x9244,
+ // WEBGL_compressed_texture_s3tc
+ COMPRESSED_RGB_S3TC_DXT1_EXT : 0x83F0,
+ COMPRESSED_RGBA_S3TC_DXT1_EXT : 0x83F1,
+ COMPRESSED_RGBA_S3TC_DXT3_EXT : 0x83F2,
+ COMPRESSED_RGBA_S3TC_DXT5_EXT : 0x83F3,
+
+ // WEBGL_compressed_texture_pvrtc
+ COMPRESSED_RGB_PVRTC_4BPPV1_IMG : 0x8C00,
+ COMPRESSED_RGB_PVRTC_2BPPV1_IMG : 0x8C01,
+ COMPRESSED_RGBA_PVRTC_4BPPV1_IMG : 0x8C02,
+ COMPRESSED_RGBA_PVRTC_2BPPV1_IMG : 0x8C03,
+
+ // WEBGL_compressed_texture_etc1
+ COMPRESSED_RGB_ETC1_WEBGL : 0x8D64,
+
// Desktop OpenGL
DOUBLE : 0x140A,
diff --git a/Source/Core/loadCRN.js b/Source/Core/loadCRN.js
new file mode 100644
index 000000000000..f50ebefbfb38
--- /dev/null
+++ b/Source/Core/loadCRN.js
@@ -0,0 +1,84 @@
+/*global define*/
+define([
+ './CompressedTextureBuffer',
+ './defined',
+ './DeveloperError',
+ './loadArrayBuffer',
+ './TaskProcessor',
+ '../ThirdParty/when'
+], function(
+ CompressedTextureBuffer,
+ defined,
+ DeveloperError,
+ loadArrayBuffer,
+ TaskProcessor,
+ when) {
+ 'use strict';
+
+ var transcodeTaskProcessor = new TaskProcessor('transcodeCRNToDXT', Number.POSITIVE_INFINITY);
+
+ /**
+ * Asynchronously loads and parses the given URL to a CRN file or parses the raw binary data of a CRN file.
+ * Returns a promise that will resolve to an object containing the image buffer, width, height and format once loaded,
+ * or reject if the URL failed to load or failed to parse the data. The data is loaded
+ * using XMLHttpRequest, which means that in order to make requests to another origin,
+ * the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
+ *
+ * @exports loadCRN
+ *
+ * @param {String|Promise.
+ * The following are part of the KTX format specification but are not supported:
+ *
+ *
+ *
true
if WEBGL_texture_compression_s3tc is supported. This extension provides
+ * access to DXT compressed textures.
+ * @memberof Context.prototype
+ * @type {Boolean}
+ * @see {@link https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/}
+ */
+ s3tc : {
+ get : function() {
+ return this._s3tc;
+ }
+ },
+
+ /**
+ * true
if WEBGL_texture_compression_pvrtc is supported. This extension provides
+ * access to PVR compressed textures.
+ * @memberof Context.prototype
+ * @type {Boolean}
+ * @see {@link https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_pvrtc/}
+ */
+ pvrtc : {
+ get : function() {
+ return this._pvrtc;
+ }
+ },
+
+ /**
+ * true
if WEBGL_texture_compression_etc1 is supported. This extension provides
+ * access to ETC1 compressed textures.
+ * @memberof Context.prototype
+ * @type {Boolean}
+ * @see {@link https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_etc1/}
+ */
+ etc1 : {
+ get : function() {
+ return this._etc1;
+ }
+ },
+
/**
* true
if the OES_vertex_array_object extension is supported. This
* extension can improve performance by reducing the overhead of switching vertex arrays.
diff --git a/Source/Renderer/Texture.js b/Source/Renderer/Texture.js
index b1c80ee0d6c3..242c91bfba4d 100644
--- a/Source/Renderer/Texture.js
+++ b/Source/Renderer/Texture.js
@@ -60,6 +60,8 @@ define([
var pixelDatatype = defaultValue(options.pixelDatatype, PixelDatatype.UNSIGNED_BYTE);
var internalFormat = pixelFormat;
+ var isCompressed = PixelFormat.isCompressedFormat(internalFormat);
+
if (context.webgl2) {
if (pixelFormat === PixelFormat.DEPTH_STENCIL) {
internalFormat = WebGLConstants.DEPTH24_STENCIL8;
@@ -97,7 +99,7 @@ define([
throw new DeveloperError('Invalid options.pixelFormat.');
}
- if (!PixelDatatype.validate(pixelDatatype)) {
+ if (!isCompressed && !PixelDatatype.validate(pixelDatatype)) {
throw new DeveloperError('Invalid options.pixelDatatype.');
}
@@ -123,6 +125,24 @@ define([
throw new DeveloperError('When options.pixelFormat is DEPTH_COMPONENT or DEPTH_STENCIL, this WebGL implementation must support WEBGL_depth_texture. Check context.depthTexture.');
}
}
+
+ if (isCompressed) {
+ if (!defined(source) || !defined(source.arrayBufferView)) {
+ throw new DeveloperError('When options.pixelFormat is compressed, options.source.arrayBufferView must be defined.');
+ }
+
+ if (PixelFormat.isDXTFormat(internalFormat) && !context.s3tc) {
+ throw new DeveloperError('When options.pixelFormat is S3TC compressed, this WebGL implementation must support the WEBGL_texture_compression_s3tc extension. Check context.s3tc.');
+ } else if (PixelFormat.isPVRTCFormat(internalFormat) && !context.pvrtc) {
+ throw new DeveloperError('When options.pixelFormat is PVRTC compressed, this WebGL implementation must support the WEBGL_texture_compression_pvrtc extension. Check context.pvrtc.');
+ } else if (PixelFormat.isETC1Format(internalFormat) && !context.etc1) {
+ throw new DeveloperError('When options.pixelFormat is ETC1 compressed, this WebGL implementation must support the WEBGL_texture_compression_etc1 extension. Check context.etc1.');
+ }
+
+ if (PixelFormat.compressedTextureSize(internalFormat, width, height) !== source.arrayBufferView.byteLength) {
+ throw new DeveloperError('The byte length of the array buffer is invalid for the compressed texture with the given width and height.');
+ }
+ }
//>>includeEnd('debug');
// Use premultiplied alpha for opaque textures should perform better on Chrome:
@@ -144,7 +164,11 @@ define([
if (defined(source.arrayBufferView)) {
// Source: typed array
- gl.texImage2D(textureTarget, 0, internalFormat, width, height, 0, pixelFormat, pixelDatatype, source.arrayBufferView);
+ if (isCompressed) {
+ gl.compressedTexImage2D(textureTarget, 0, internalFormat, width, height, 0, source.arrayBufferView);
+ } else {
+ gl.texImage2D(textureTarget, 0, internalFormat, width, height, 0, pixelFormat, pixelDatatype, source.arrayBufferView);
+ }
} else if (defined(source.framebuffer)) {
// Source: framebuffer
if (source.framebuffer !== context.defaultFramebuffer) {
@@ -197,7 +221,7 @@ define([
* @returns {Texture} A texture with contents from the framebuffer.
*
* @exception {DeveloperError} Invalid pixelFormat.
- * @exception {DeveloperError} pixelFormat cannot be DEPTH_COMPONENT or DEPTH_STENCIL.
+ * @exception {DeveloperError} pixelFormat cannot be DEPTH_COMPONENT, DEPTH_STENCIL or a compressed format.
* @exception {DeveloperError} framebufferXOffset must be greater than or equal to zero.
* @exception {DeveloperError} framebufferYOffset must be greater than or equal to zero.
* @exception {DeveloperError} framebufferXOffset + width must be less than or equal to canvas.clientWidth.
@@ -237,27 +261,21 @@ define([
if (!defined(options.context)) {
throw new DeveloperError('context is required.');
}
-
if (!PixelFormat.validate(pixelFormat)) {
throw new DeveloperError('Invalid pixelFormat.');
}
-
- if (PixelFormat.isDepthFormat(pixelFormat)) {
- throw new DeveloperError('pixelFormat cannot be DEPTH_COMPONENT or DEPTH_STENCIL.');
+ if (PixelFormat.isDepthFormat(pixelFormat) || PixelFormat.isCompressedFormat(pixelFormat)) {
+ throw new DeveloperError('pixelFormat cannot be DEPTH_COMPONENT, DEPTH_STENCIL or a compressed format.');
}
-
if (framebufferXOffset < 0) {
throw new DeveloperError('framebufferXOffset must be greater than or equal to zero.');
}
-
if (framebufferYOffset < 0) {
throw new DeveloperError('framebufferYOffset must be greater than or equal to zero.');
}
-
if (framebufferXOffset + width > gl.drawingBufferWidth) {
throw new DeveloperError('framebufferXOffset + width must be less than or equal to drawingBufferWidth');
}
-
if (framebufferYOffset + height > gl.drawingBufferHeight) {
throw new DeveloperError('framebufferYOffset + height must be less than or equal to drawingBufferHeight.');
}
@@ -379,6 +397,7 @@ define([
* @param {Number} [yOffset=0] The offset in the y direction within the texture to copy into.
*
* @exception {DeveloperError} Cannot call copyFrom when the texture pixel format is DEPTH_COMPONENT or DEPTH_STENCIL.
+ * @exception {DeveloperError} Cannot call copyFrom with a compressed texture pixel format.
* @exception {DeveloperError} xOffset must be greater than or equal to zero.
* @exception {DeveloperError} yOffset must be greater than or equal to zero.
* @exception {DeveloperError} xOffset + source.width must be less than or equal to width.
@@ -403,6 +422,9 @@ define([
if (PixelFormat.isDepthFormat(this._pixelFormat)) {
throw new DeveloperError('Cannot call copyFrom when the texture pixel format is DEPTH_COMPONENT or DEPTH_STENCIL.');
}
+ if (PixelFormat.isCompressedFormat(this._pixelFormat)) {
+ throw new DeveloperError('Cannot call copyFrom with a compressed texture pixel format.');
+ }
if (xOffset < 0) {
throw new DeveloperError('xOffset must be greater than or equal to zero.');
}
@@ -445,6 +467,7 @@ define([
*
* @exception {DeveloperError} Cannot call copyFromFramebuffer when the texture pixel format is DEPTH_COMPONENT or DEPTH_STENCIL.
* @exception {DeveloperError} Cannot call copyFromFramebuffer when the texture pixel data type is FLOAT.
+ * @exception {DeveloperError} Cannot call copyFrom with a compressed texture pixel format.
* @exception {DeveloperError} This texture was destroyed, i.e., destroy() was called.
* @exception {DeveloperError} xOffset must be greater than or equal to zero.
* @exception {DeveloperError} yOffset must be greater than or equal to zero.
@@ -468,6 +491,9 @@ define([
if (this._pixelDatatype === PixelDatatype.FLOAT) {
throw new DeveloperError('Cannot call copyFromFramebuffer when the texture pixel data type is FLOAT.');
}
+ if (PixelFormat.isCompressedFormat(this._pixelFormat)) {
+ throw new DeveloperError('Cannot call copyFrom with a compressed texture pixel format.');
+ }
if (xOffset < 0) {
throw new DeveloperError('xOffset must be greater than or equal to zero.');
}
@@ -513,6 +539,9 @@ define([
if (PixelFormat.isDepthFormat(this._pixelFormat)) {
throw new DeveloperError('Cannot call generateMipmap when the texture pixel format is DEPTH_COMPONENT or DEPTH_STENCIL.');
}
+ if (PixelFormat.isCompressedFormat(this._pixelFormat)) {
+ throw new DeveloperError('Cannot call generateMipmap with a compressed pixel format.');
+ }
if (this._width > 1 && !CesiumMath.isPowerOfTwo(this._width)) {
throw new DeveloperError('width must be a power of two to call generateMipmap().');
}
diff --git a/Source/Scene/ImageryLayer.js b/Source/Scene/ImageryLayer.js
index 98a1d54eb741..9fef8eeac772 100644
--- a/Source/Scene/ImageryLayer.js
+++ b/Source/Scene/ImageryLayer.js
@@ -719,6 +719,7 @@ define([
*/
ImageryLayer.prototype._createTexture = function(context, imagery) {
var imageryProvider = this._imageryProvider;
+ var image = imagery.image;
// If this imagery provider has a discard policy, use it to check if this
// image should be discarded.
@@ -733,7 +734,7 @@ define([
}
// Mark discarded imagery tiles invalid. Parent imagery will be used instead.
- if (discardPolicy.shouldDiscardImage(imagery.image)) {
+ if (discardPolicy.shouldDiscardImage(image)) {
imagery.state = ImageryState.INVALID;
return;
}
@@ -741,11 +742,24 @@ define([
}
// Imagery does not need to be discarded, so upload it to WebGL.
- var texture = new Texture({
- context : context,
- source : imagery.image,
- pixelFormat : imageryProvider.hasAlphaChannel ? PixelFormat.RGBA : PixelFormat.RGB
- });
+ var texture;
+ if (defined(image.internalFormat)) {
+ texture = new Texture({
+ context : context,
+ pixelFormat : image.internalFormat,
+ width : image.width,
+ height : image.height,
+ source : {
+ arrayBufferView : image.bufferView
+ }
+ });
+ } else {
+ texture = new Texture({
+ context : context,
+ source : image,
+ pixelFormat : imageryProvider.hasAlphaChannel ? PixelFormat.RGBA : PixelFormat.RGB
+ });
+ }
if (imageryProvider.tilingScheme instanceof WebMercatorTilingScheme) {
imagery.textureWebMercator = texture;
@@ -758,7 +772,7 @@ define([
function finalizeReprojectTexture(imageryLayer, context, imagery, texture) {
// Use mipmaps if this texture has power-of-two dimensions.
- if (CesiumMath.isPowerOfTwo(texture.width) && CesiumMath.isPowerOfTwo(texture.height)) {
+ if (!PixelFormat.isCompressedFormat(texture.pixelFormat) && CesiumMath.isPowerOfTwo(texture.width) && CesiumMath.isPowerOfTwo(texture.height)) {
var mipmapSampler = context.cache.imageryLayer_mipmapSampler;
if (!defined(mipmapSampler)) {
var maximumSupportedAnisotropy = ContextLimits.maximumTextureFilterAnisotropy;
diff --git a/Source/Scene/ImageryProvider.js b/Source/Scene/ImageryProvider.js
index 520fc3f0ec12..2a0500a0f7b7 100644
--- a/Source/Scene/ImageryProvider.js
+++ b/Source/Scene/ImageryProvider.js
@@ -3,15 +3,19 @@ define([
'../Core/defined',
'../Core/defineProperties',
'../Core/DeveloperError',
+ '../Core/loadCRN',
'../Core/loadImage',
'../Core/loadImageViaBlob',
+ '../Core/loadKTX',
'../Core/throttleRequestByServer'
], function(
defined,
defineProperties,
DeveloperError,
+ loadCRN,
loadImage,
loadImageViaBlob,
+ loadKTX,
throttleRequestByServer) {
'use strict';
@@ -294,6 +298,9 @@ define([
*/
ImageryProvider.prototype.pickFeatures = DeveloperError.throwInstantiationError;
+ var ktxRegex = /\.ktx$/i;
+ var crnRegex = /\.crn$/i;
+
/**
* Loads an image from a given URL. If the server referenced by the URL already has
* too many requests pending, this function will instead return undefined, indicating
@@ -307,7 +314,11 @@ define([
* Image or a Canvas DOM object.
*/
ImageryProvider.loadImage = function(imageryProvider, url) {
- if (defined(imageryProvider.tileDiscardPolicy)) {
+ if (ktxRegex.test(url)) {
+ return throttleRequestByServer(url, loadKTX);
+ } else if (crnRegex.test(url)) {
+ return throttleRequestByServer(url, loadCRN);
+ } else if (defined(imageryProvider.tileDiscardPolicy)) {
return throttleRequestByServer(url, loadImageViaBlob);
}
return throttleRequestByServer(url, loadImage);
diff --git a/Source/Scene/Material.js b/Source/Scene/Material.js
index 6e30939fc74d..c48952fa276f 100644
--- a/Source/Scene/Material.js
+++ b/Source/Scene/Material.js
@@ -11,7 +11,9 @@ define([
'../Core/destroyObject',
'../Core/DeveloperError',
'../Core/isArray',
+ '../Core/loadCRN',
'../Core/loadImage',
+ '../Core/loadKTX',
'../Core/Matrix2',
'../Core/Matrix3',
'../Core/Matrix4',
@@ -42,7 +44,9 @@ define([
destroyObject,
DeveloperError,
isArray,
+ loadCRN,
loadImage,
+ loadKTX,
Matrix2,
Matrix3,
Matrix4,
@@ -413,10 +417,23 @@ define([
uniformId = loadedImage.id;
var image = loadedImage.image;
- var texture = new Texture({
- context : context,
- source : image
- });
+ var texture;
+ if (defined(image.internalFormat)) {
+ texture = new Texture({
+ context : context,
+ pixelFormat : image.internalFormat,
+ width : image.width,
+ height : image.height,
+ source : {
+ arrayBufferView : image.bufferView
+ }
+ });
+ } else {
+ texture = new Texture({
+ context : context,
+ source : image
+ });
+ }
this._textures[uniformId] = texture;
@@ -663,6 +680,9 @@ define([
'mat4' : Matrix4
};
+ var ktxRegex = /\.ktx$/i;
+ var crnRegex = /\.crn$/i;
+
function createTexture2DUpdateFunction(uniformId) {
var oldUniformValue;
return function(material, context) {
@@ -741,7 +761,15 @@ define([
if (uniformValue !== material._texturePaths[uniformId]) {
if (typeof uniformValue === 'string') {
- when(loadImage(uniformValue), function(image) {
+ var promise;
+ if (ktxRegex.test(uniformValue)) {
+ promise = loadKTX(uniformValue);
+ } else if (crnRegex.test(uniformValue)) {
+ promise = loadCRN(uniformValue);
+ } else {
+ promise = loadImage(uniformValue);
+ }
+ when(promise, function(image) {
material._loadedImages.push({
id : uniformId,
image : image
diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js
index ee4952c7fcc5..7f1443d9e048 100644
--- a/Source/Scene/Model.js
+++ b/Source/Scene/Model.js
@@ -21,13 +21,16 @@ define([
'../Core/getStringFromTypedArray',
'../Core/IndexDatatype',
'../Core/loadArrayBuffer',
+ '../Core/loadCRN',
'../Core/loadImage',
'../Core/loadImageFromTypedArray',
+ '../Core/loadKTX',
'../Core/loadText',
'../Core/Math',
'../Core/Matrix2',
'../Core/Matrix3',
'../Core/Matrix4',
+ '../Core/PixelFormat',
'../Core/PrimitiveType',
'../Core/Quaternion',
'../Core/Queue',
@@ -84,13 +87,16 @@ define([
getStringFromTypedArray,
IndexDatatype,
loadArrayBuffer,
+ loadCRN,
loadImage,
loadImageFromTypedArray,
+ loadKTX,
loadText,
CesiumMath,
Matrix2,
Matrix3,
Matrix4,
+ PixelFormat,
PrimitiveType,
Quaternion,
Queue,
@@ -1394,21 +1400,73 @@ define([
loadResources.texturesToCreate.enqueue({
id : id,
image : image,
- bufferView : undefined
+ bufferView : image.bufferView,
+ width : image.width,
+ height : image.height,
+ internalFormat : image.internalFormat
});
};
}
- function parseTextures(model) {
+ var ktxRegex = /(^data:image\/ktx)|(\.ktx$)/i;
+ var crnRegex = /(^data:image\/crn)|(\.crn$)/i;
+
+ function parseTextures(model, context) {
var images = model.gltf.images;
var textures = model.gltf.textures;
for (var id in textures) {
if (textures.hasOwnProperty(id)) {
var gltfImage = images[textures[id].source];
+ var extras = gltfImage.extras;
+
+ var binary = undefined;
+ var uri = undefined;
+
+ // First check for a compressed texture
+ if (defined(extras) && defined(extras.compressedImage3DTiles)) {
+ var crunch = extras.compressedImage3DTiles.crunch;
+ var s3tc = extras.compressedImage3DTiles.s3tc;
+ var pvrtc = extras.compressedImage3DTiles.pvrtc1;
+ var etc1 = extras.compressedImage3DTiles.etc1;
+
+ if (context.s3tc && defined(crunch)) {
+ if (defined(crunch.extensions)&& defined(crunch.extensions.KHR_binary_glTF)) {
+ binary = crunch.extensions.KHR_binary_glTF;
+ } else {
+ uri = crunch.uri;
+ }
+ } else if (context.s3tc && defined(s3tc)) {
+ if (defined(s3tc.extensions)&& defined(s3tc.extensions.KHR_binary_glTF)) {
+ binary = s3tc.extensions.KHR_binary_glTF;
+ } else {
+ uri = s3tc.uri;
+ }
+ } else if (context.pvrtc && defined(pvrtc)) {
+ if (defined(pvrtc.extensions)&& defined(pvrtc.extensions.KHR_binary_glTF)) {
+ binary = pvrtc.extensions.KHR_binary_glTF;
+ } else {
+ uri = pvrtc.uri;
+ }
+ } else if (context.etc1 && defined(etc1)) {
+ if (defined(etc1.extensions)&& defined(etc1.extensions.KHR_binary_glTF)) {
+ binary = etc1.extensions.KHR_binary_glTF;
+ } else {
+ uri = etc1.uri;
+ }
+ }
+ }
+
+ // No compressed texture, so image references either uri (external or base64-encoded) or bufferView
+ if (!defined(binary) && !defined(uri)) {
+ if (defined(gltfImage.extensions) && defined(gltfImage.extensions.KHR_binary_glTF)) {
+ binary = gltfImage.extensions.KHR_binary_glTF;
+ } else {
+ uri = new Uri(gltfImage.uri);
+ }
+ }
// Image references either uri (external or base64-encoded) or bufferView
- if (defined(gltfImage.extensions) && defined(gltfImage.extensions.KHR_binary_glTF)) {
- var binary = gltfImage.extensions.KHR_binary_glTF;
+ if (defined(binary)) {
model._loadResources.texturesToCreateFromBufferView.enqueue({
id : id,
image : undefined,
@@ -1417,9 +1475,16 @@ define([
});
} else {
++model._loadResources.pendingTextureLoads;
- var uri = new Uri(gltfImage.uri);
+ uri = new Uri(uri);
var imagePath = uri.resolve(model._baseUri).toString();
- loadImage(imagePath).then(imageLoad(model, id)).otherwise(getFailedLoadFunction(model, 'image', imagePath));
+
+ if (ktxRegex.test(imagePath)) {
+ loadKTX(imagePath).then(imageLoad(model, id)).otherwise(getFailedLoadFunction(model, 'image', imagePath));
+ } else if (crnRegex.test(imagePath)) {
+ loadCRN(imagePath).then(imageLoad(model, id)).otherwise(getFailedLoadFunction(model, 'image', imagePath));
+ } else {
+ loadImage(imagePath).then(imageLoad(model, id)).otherwise(getFailedLoadFunction(model, 'image', imagePath));
+ }
}
}
}
@@ -1560,13 +1625,13 @@ define([
model._runtime.meshesByName = runtimeMeshesByName;
}
- function parse(model) {
+ function parse(model, context) {
if (!model._loadRendererResourcesFromCache) {
parseBuffers(model);
parseBufferViews(model);
parseShaders(model);
parsePrograms(model);
- parseTextures(model);
+ parseTextures(model, context);
}
parseMaterials(model);
parseMeshes(model);
@@ -1953,12 +2018,20 @@ define([
var gltf = model.gltf;
var bufferView = gltf.bufferViews[gltfTexture.bufferView];
- var onload = getOnImageCreatedFromTypedArray(loadResources, gltfTexture);
var onerror = getFailedLoadFunction(model, 'image', 'id: ' + gltfTexture.id + ', bufferView: ' + gltfTexture.bufferView);
- loadImageFromTypedArray(loadResources.getBuffer(bufferView), gltfTexture.mimeType).
- then(onload).otherwise(onerror);
- ++loadResources.pendingBufferViewToImage;
+ if (gltfTexture.mimeType === 'image/ktx') {
+ loadKTX(loadResources.getBuffer(bufferView)).then(imageLoad(model, gltfTexture.id)).otherwise(onerror);
+ ++model._loadResources.pendingTextureLoads;
+ } else if (gltfTexture.mimeType === 'image/crn') {
+ loadCRN(loadResources.getBuffer(bufferView)).then(imageLoad(model, gltfTexture.id)).otherwise(onerror);
+ ++model._loadResources.pendingTextureLoads;
+ } else {
+ var onload = getOnImageCreatedFromTypedArray(loadResources, gltfTexture);
+ loadImageFromTypedArray(loadResources.getBuffer(bufferView), gltfTexture.mimeType)
+ .then(onload).otherwise(onerror);
+ ++loadResources.pendingBufferViewToImage;
+ }
}
}
@@ -1992,46 +2065,62 @@ define([
var rendererSamplers = model._rendererResources.samplers;
var sampler = rendererSamplers[texture.sampler];
+ var internalFormat = gltfTexture.internalFormat;
+
var mipmap =
- (sampler.minificationFilter === TextureMinificationFilter.NEAREST_MIPMAP_NEAREST) ||
- (sampler.minificationFilter === TextureMinificationFilter.NEAREST_MIPMAP_LINEAR) ||
- (sampler.minificationFilter === TextureMinificationFilter.LINEAR_MIPMAP_NEAREST) ||
- (sampler.minificationFilter === TextureMinificationFilter.LINEAR_MIPMAP_LINEAR);
+ (!(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));
var requiresNpot = mipmap ||
(sampler.wrapS === TextureWrap.REPEAT) ||
(sampler.wrapS === TextureWrap.MIRRORED_REPEAT) ||
(sampler.wrapT === TextureWrap.REPEAT) ||
(sampler.wrapT === TextureWrap.MIRRORED_REPEAT);
- var source = gltfTexture.image;
- var npot = !CesiumMath.isPowerOfTwo(source.width) || !CesiumMath.isPowerOfTwo(source.height);
-
- if (requiresNpot && npot) {
- // WebGL requires power-of-two texture dimensions for mipmapping and REPEAT/MIRRORED_REPEAT wrap modes.
- var canvas = document.createElement('canvas');
- canvas.width = CesiumMath.nextPowerOfTwo(source.width);
- canvas.height = CesiumMath.nextPowerOfTwo(source.height);
- var canvasContext = canvas.getContext('2d');
- canvasContext.drawImage(source, 0, 0, source.width, source.height, 0, 0, canvas.width, canvas.height);
- source = canvas;
- }
-
var tx;
+ var source = gltfTexture.image;
- if (texture.target === WebGLConstants.TEXTURE_2D) {
+ if (defined(internalFormat) && texture.target === WebGLConstants.TEXTURE_2D) {
tx = new Texture({
context : context,
- source : source,
- pixelFormat : texture.internalFormat,
- pixelDatatype : texture.type,
- sampler : sampler,
- flipY : false
+ source : {
+ arrayBufferView : gltfTexture.bufferView
+ },
+ width : gltfTexture.width,
+ height : gltfTexture.height,
+ pixelFormat : internalFormat,
+ sampler : sampler
});
- }
- // GLTF_SPEC: Support TEXTURE_CUBE_MAP. https://github.com/KhronosGroup/glTF/issues/40
+ } else if (defined(source)) {
+ var npot = !CesiumMath.isPowerOfTwo(source.width) || !CesiumMath.isPowerOfTwo(source.height);
+
+ if (requiresNpot && npot) {
+ // WebGL requires power-of-two texture dimensions for mipmapping and REPEAT/MIRRORED_REPEAT wrap modes.
+ var canvas = document.createElement('canvas');
+ canvas.width = CesiumMath.nextPowerOfTwo(source.width);
+ canvas.height = CesiumMath.nextPowerOfTwo(source.height);
+ var canvasContext = canvas.getContext('2d');
+ canvasContext.drawImage(source, 0, 0, source.width, source.height, 0, 0, canvas.width, canvas.height);
+ source = canvas;
+ }
- if (mipmap) {
- tx.generateMipmap();
+ if (texture.target === WebGLConstants.TEXTURE_2D) {
+ tx = new Texture({
+ context : context,
+ source : source,
+ pixelFormat : texture.internalFormat,
+ pixelDatatype : texture.type,
+ sampler : sampler,
+ flipY : false
+ });
+ }
+ // GLTF_SPEC: Support TEXTURE_CUBE_MAP. https://github.com/KhronosGroup/glTF/issues/40
+
+ if (mipmap) {
+ tx.generateMipmap();
+ }
}
model._rendererResources.textures[gltfTexture.id] = tx;
@@ -4127,7 +4216,7 @@ define([
}
this._loadResources = new LoadResources();
- parse(this);
+ parse(this, context);
}
}
diff --git a/Source/Scene/Scene.js b/Source/Scene/Scene.js
index 41a9cfb67135..8ebad9dda2d4 100644
--- a/Source/Scene/Scene.js
+++ b/Source/Scene/Scene.js
@@ -1097,6 +1097,18 @@ define([
}
});
+ /**
+ * Determines if a compressed texture format is supported.
+ * @param {String} format The texture format. May be the name of the format or the WebGL extension name, e.g. s3tc or WEBGL_compressed_texture_s3tc.
+ * @return {boolean} Whether or not the format is supported.
+ */
+ Scene.prototype.getCompressedTextureFormatSupported = function(format) {
+ var context = this.context;
+ return ((format === 'WEBGL_compressed_texture_s3tc' || format === 's3tc') && context.s3tc) ||
+ ((format === 'WEBGL_compressed_texture_pvrtc' || format === 'pvrtc') && context.pvrtc) ||
+ ((format === 'WEBGL_compressed_texture_etc1' || format === 'etc1') && context.etc1);
+ };
+
var scratchPosition0 = new Cartesian3();
var scratchPosition1 = new Cartesian3();
function maxComponent(a, b) {
diff --git a/Source/ThirdParty/crunch.js b/Source/ThirdParty/crunch.js
new file mode 100644
index 000000000000..9bc5362a1ce9
--- /dev/null
+++ b/Source/ThirdParty/crunch.js
@@ -0,0 +1,57 @@
+/**
+ * @licence
+ *
+ * crunch/crnlib v1.04 - Advanced DXTn texture compression library
+ * Copyright (C) 2010-2016 Richard Geldreich, Jr. and Binomial LLC http://binomial.info
+ */
+
+/**
+ * @license
+ *
+ * crunch_lib.cpp
+ *
+ * Copyright (c) 2013, Evan Parker, Brandon Jones. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// The C++ code was compiled to Javascript with Emcripten.
+// For instructions, see:
+// https://github.com/AnalyticalGraphicsInc/crunch
+
+/*global define*/
+define([], function() {
+
+ var Module;if(!Module)Module=(typeof Module!=="undefined"?Module:null)||{};var moduleOverrides={};for(var key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var ENVIRONMENT_IS_WEB=typeof window==="object";var ENVIRONMENT_IS_WORKER=typeof importScripts==="function";var ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof require==="function"&&!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_WORKER;var ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;if(ENVIRONMENT_IS_NODE){if(!Module["print"])Module["print"]=function print(x){process["stdout"].write(x+"\n")};if(!Module["printErr"])Module["printErr"]=function printErr(x){process["stderr"].write(x+"\n")};var nodeFS=require("fs");var nodePath=require("path");Module["read"]=function read(filename,binary){filename=nodePath["normalize"](filename);var ret=nodeFS["readFileSync"](filename);if(!ret&&filename!=nodePath["resolve"](filename)){filename=path.join(__dirname,"..","src",filename);ret=nodeFS["readFileSync"](filename)}if(ret&&!binary)ret=ret.toString();return ret};Module["readBinary"]=function readBinary(filename){var ret=Module["read"](filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}assert(ret.buffer);return ret};Module["load"]=function load(f){globalEval(read(f))};if(!Module["thisProgram"]){if(process["argv"].length>1){Module["thisProgram"]=process["argv"][1].replace(/\\/g,"/")}else{Module["thisProgram"]="unknown-program"}}Module["arguments"]=process["argv"].slice(2);if(typeof module!=="undefined"){module["exports"]=Module}process["on"]("uncaughtException",(function(ex){if(!(ex instanceof ExitStatus)){throw ex}}));Module["inspect"]=(function(){return"[Emscripten Module object]"})}else if(ENVIRONMENT_IS_SHELL){if(!Module["print"])Module["print"]=print;if(typeof printErr!="undefined")Module["printErr"]=printErr;if(typeof read!="undefined"){Module["read"]=read}else{Module["read"]=function read(){throw"no read() available (jsc?)"}}Module["readBinary"]=function readBinary(f){if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}var data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){Module["arguments"]=scriptArgs}else if(typeof arguments!="undefined"){Module["arguments"]=arguments}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){Module["read"]=function read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(typeof arguments!="undefined"){Module["arguments"]=arguments}if(typeof console!=="undefined"){if(!Module["print"])Module["print"]=function print(x){console.log(x)};if(!Module["printErr"])Module["printErr"]=function printErr(x){console.log(x)}}else{var TRY_USE_DUMP=false;if(!Module["print"])Module["print"]=TRY_USE_DUMP&&typeof dump!=="undefined"?(function(x){dump(x)}):(function(x){})}if(ENVIRONMENT_IS_WORKER){Module["load"]=importScripts}if(typeof Module["setWindowTitle"]==="undefined"){Module["setWindowTitle"]=(function(title){document.title=title})}}else{throw"Unknown runtime environment. Where are we?"}function globalEval(x){eval.call(null,x)}if(!Module["load"]&&Module["read"]){Module["load"]=function load(f){globalEval(Module["read"](f))}}if(!Module["print"]){Module["print"]=(function(){})}if(!Module["printErr"]){Module["printErr"]=Module["print"]}if(!Module["arguments"]){Module["arguments"]=[]}if(!Module["thisProgram"]){Module["thisProgram"]="./this.program"}Module.print=Module["print"];Module.printErr=Module["printErr"];Module["preRun"]=[];Module["postRun"]=[];for(var key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}var Runtime={setTempRet0:(function(value){tempRet0=value}),getTempRet0:(function(){return tempRet0}),stackSave:(function(){return STACKTOP}),stackRestore:(function(stackTop){STACKTOP=stackTop}),getNativeTypeSize:(function(type){switch(type){case"i1":case"i8":return 1;case"i16":return 2;case"i32":return 4;case"i64":return 8;case"float":return 4;case"double":return 8;default:{if(type[type.length-1]==="*"){return Runtime.QUANTUM_SIZE}else if(type[0]==="i"){var bits=parseInt(type.substr(1));assert(bits%8===0);return bits/8}else{return 0}}}}),getNativeFieldSize:(function(type){return Math.max(Runtime.getNativeTypeSize(type),Runtime.QUANTUM_SIZE)}),STACK_ALIGN:16,prepVararg:(function(ptr,type){if(type==="double"||type==="i64"){if(ptr&7){assert((ptr&7)===4);ptr+=4}}else{assert((ptr&3)===0)}return ptr}),getAlignSize:(function(type,size,vararg){if(!vararg&&(type=="i64"||type=="double"))return 8;if(!type)return Math.min(size,8);return Math.min(size||(type?Runtime.getNativeFieldSize(type):0),Runtime.QUANTUM_SIZE)}),dynCall:(function(sig,ptr,args){if(args&&args.length){if(!args.splice)args=Array.prototype.slice.call(args);args.splice(0,0,ptr);return Module["dynCall_"+sig].apply(null,args)}else{return Module["dynCall_"+sig].call(null,ptr)}}),functionPointers:[],addFunction:(function(func){for(var i=0;i>>0);n=0;do{w=(sb(Z,N)|0)+a|0;x=w-T|0;a=x>>31;a=a&w|x&~a;if((k[S>>2]|0)>>>0<=a>>>0){k[ka>>2]=1138;k[ka+4>>2]=906;k[ka+8>>2]=1769;yc(ga,1084,ka)|0;xc(ga)|0}k[ha+(n<<2)>>2]=k[(k[O>>2]|0)+(a<<2)>>2];n=n+1|0}while(n>>>0
>>0);x=R|(o|0)!=($|0);v=0;w=z;while(1){u=A|(v|0)==0;t=v<<1;q=0;s=w;while(1){p=(sb(Z,aa)|0)+c|0;n=p-U|0;c=n>>31;c=c&p|n&~c;n=(sb(Z,ba)|0)+f|0;p=n-ca|0;f=p>>31;f=f&n|p&~f;if((x|(q|0)==0)&u){n=l[q+t+(1819+(y<<2))>>0]|0;p=c*3|0;if((k[K>>2]|0)>>>0<=p>>>0){k[la>>2]=1138;k[la+4>>2]=906;k[la+8>>2]=1769;yc(ga,1084,la)|0;xc(ga)|0}na=k[L>>2]|0;k[s>>2]=(m[na+(p<<1)>>1]|0)<<16|k[fa+(n<<2)>>2];k[s+4>>2]=(m[na+(p+2<<1)>>1]|0)<<16|(m[na+(p+1<<1)>>1]|0);k[s+8>>2]=k[ha+(n<<2)>>2];if((k[W>>2]|0)>>>0<=f>>>0){k[ja>>2]=1138;k[ja+4>>2]=906;k[ja+8>>2]=1769;yc(ga,1084,ja)|0;xc(ga)|0}k[s+12>>2]=k[(k[M>>2]|0)+(f<<2)>>2]}q=q+1|0;if((q|0)==2)break;else s=s+16|0}v=v+1|0;if((v|0)==2)break;else w=w+d|0}o=o+C|0;if((o|0)==(D|0))break;else z=z+B|0}}F=F+1|0;if((F|0)==(h|0))break;else E=E+Y|0}}H=H+1|0}while((H|0)!=(G|0));r=ma;return 1}function Lb(a,b,c,d,e,f,g,h){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,n=0,o=0,p=0,q=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0,$=0;$=r;r=r+576|0;_=$+32|0;Z=$+16|0;Y=$;X=$+64|0;W=$+48|0;M=a+272|0;N=k[M>>2]|0;c=k[a+88>>2]|0;O=(l[c+63>>0]|0)<<8|(l[c+64>>0]|0);c=i[c+17>>0]|0;if(!(c<<24>>24)){r=$;return 1}P=(h|0)==0;Q=h+-1|0;R=d<<1;S=a+92|0;T=a+116|0;U=g+-1|0;V=a+212|0;L=(f&1|0)==0;I=a+288|0;J=a+284|0;K=a+164|0;G=a+268|0;H=U<<4;F=c&255;E=(e&1|0)!=0;c=0;f=0;a=1;D=0;do{if(!P){B=k[b+(D<<2)>>2]|0;C=0;while(1){z=C&1;e=(z|0)==0;y=(z<<5^32)+-16|0;z=(z<<1^2)+-1|0;A=e?g:-1;j=e?0:U;if((j|0)!=(A|0)){x=L|(C|0)!=(Q|0);w=e?B:B+H|0;while(1){if((a|0)==1)a=sb(S,T)|0|512;v=a&7;a=a>>>3;n=l[1811+v>>0]|0;e=0;do{t=(sb(S,K)|0)+f|0;u=t-N|0;f=u>>31;f=f&t|u&~f;if((k[M>>2]|0)>>>0<=f>>>0){k[Y>>2]=1138;k[Y+4>>2]=906;k[Y+8>>2]=1769;yc(X,1084,Y)|0;xc(X)|0}k[W+(e<<2)>>2]=m[(k[G>>2]|0)+(f<<1)>>1];e=e+1|0}while(e>>>0 >>0);n=0;do{z=(sb(Y,P)|0)+e|0;A=z-T|0;e=A>>31;e=e&z|A&~e;if((k[S>>2]|0)>>>0<=e>>>0){k[fa>>2]=1138;k[fa+4>>2]=906;k[fa+8>>2]=1769;yc(ca,1084,fa)|0;xc(ca)|0}k[ba+(n<<2)>>2]=m[(k[L>>2]|0)+(e<<1)>>1];n=n+1|0}while(n>>>0 >>0);A=R|(o|0)!=(_|0);y=0;z=C;while(1){x=D|(y|0)==0;w=y<<1;u=0;v=z;while(1){t=(sb(Y,$)|0)+f|0;s=t-U|0;f=s>>31;f=f&t|s&~f;s=(sb(Y,$)|0)+c|0;t=s-U|0;c=t>>31;c=c&s|t&~c;if((A|(u|0)==0)&x){s=l[u+w+(1819+(B<<2))>>0]|0;t=f*3|0;n=k[N>>2]|0;if(n>>>0<=t>>>0){k[ga>>2]=1138;k[ga+4>>2]=906;k[ga+8>>2]=1769;yc(ca,1084,ga)|0;xc(ca)|0;n=k[N>>2]|0}p=k[O>>2]|0;q=c*3|0;if(n>>>0>q>>>0)n=p;else{k[ea>>2]=1138;k[ea+4>>2]=906;k[ea+8>>2]=1769;yc(ca,1084,ea)|0;xc(ca)|0;n=k[O>>2]|0}k[v>>2]=(m[p+(t<<1)>>1]|0)<<16|k[aa+(s<<2)>>2];k[v+4>>2]=(m[p+(t+2<<1)>>1]|0)<<16|(m[p+(t+1<<1)>>1]|0);k[v+8>>2]=(m[n+(q<<1)>>1]|0)<<16|k[ba+(s<<2)>>2];k[v+12>>2]=(m[n+(q+2<<1)>>1]|0)<<16|(m[n+(q+1<<1)>>1]|0)}u=u+1|0;if((u|0)==2)break;else v=v+16|0}y=y+1|0;if((y|0)==2)break;else z=z+d|0}o=o+F|0;if((o|0)==(G|0))break;else C=C+E|0}}I=I+1|0;if((I|0)==(h|0))break;else H=H+X|0}}K=K+1|0}while((K|0)!=(J|0));r=ha;return 1}function Nb(a){a=a|0;var b=0,c=0,d=0,e=0,f=0,g=0,h=0,j=0;j=r;r=r+576|0;h=j+48|0;f=j+32|0;e=j+16|0;d=j;g=j+64|0;k[a>>2]=0;b=a+284|0;c=k[b>>2]|0;if(c){if(!(c&7))kb(c,0,0,1,0)|0;else{k[d>>2]=1138;k[d+4>>2]=2502;k[d+8>>2]=1504;yc(g,1084,d)|0;xc(g)|0}k[b>>2]=0;k[a+288>>2]=0;k[a+292>>2]=0}i[a+296>>0]=0;c=a+268|0;b=k[c>>2]|0;if(b){if(!(b&7))kb(b,0,0,1,0)|0;else{k[e>>2]=1138;k[e+4>>2]=2502;k[e+8>>2]=1504;yc(g,1084,e)|0;xc(g)|0}k[c>>2]=0;k[a+272>>2]=0;k[a+276>>2]=0}i[a+280>>0]=0;b=a+252|0;c=k[b>>2]|0;if(c){if(!(c&7))kb(c,0,0,1,0)|0;else{k[f>>2]=1138;k[f+4>>2]=2502;k[f+8>>2]=1504;yc(g,1084,f)|0;xc(g)|0}k[b>>2]=0;k[a+256>>2]=0;k[a+260>>2]=0}i[a+264>>0]=0;b=a+236|0;c=k[b>>2]|0;if(!c){h=a+248|0;i[h>>0]=0;h=a+212|0;nb(h);h=a+188|0;nb(h);h=a+164|0;nb(h);h=a+140|0;nb(h);h=a+116|0;nb(h);r=j;return}if(!(c&7))kb(c,0,0,1,0)|0;else{k[h>>2]=1138;k[h+4>>2]=2502;k[h+8>>2]=1504;yc(g,1084,h)|0;xc(g)|0}k[b>>2]=0;k[a+240>>2]=0;k[a+244>>2]=0;h=a+248|0;i[h>>0]=0;h=a+212|0;nb(h);h=a+188|0;nb(h);h=a+164|0;nb(h);h=a+140|0;nb(h);h=a+116|0;nb(h);r=j;return}function Ob(a,b){a=a|0;b=b|0;var c=0;c=r;r=r+16|0;k[c>>2]=b;b=k[60]|0;zc(b,a,c)|0;tc(10,b)|0;Aa()}function Pb(){var a=0,b=0;a=r;r=r+16|0;if(!(Ka(192,2)|0)){b=va(k[47]|0)|0;r=a;return b|0}else Ob(2078,a);return 0}function Qb(a){a=a|0;Tc(a);return}function Rb(a){a=a|0;var b=0;b=r;r=r+16|0;Wa[a&3]();Ob(2127,b)}function Sb(){var a=0,b=0;a=Pb()|0;if(((a|0)!=0?(b=k[a>>2]|0,(b|0)!=0):0)?(a=b+48|0,(k[a>>2]&-256|0)==1126902528?(k[a+4>>2]|0)==1129074247:0):0)Rb(k[b+12>>2]|0);b=k[26]|0;k[26]=b+0;Rb(b)}function Tb(a){a=a|0;return}function Ub(a){a=a|0;return}function Vb(a){a=a|0;return}function Wb(a){a=a|0;return}function Xb(a){a=a|0;Qb(a);return}function Yb(a){a=a|0;Qb(a);return}function Zb(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0;g=r;r=r+64|0;f=g;if((a|0)!=(b|0))if((b|0)!=0?(e=bc(b,24,40,0)|0,(e|0)!=0):0){b=f;d=b+56|0;do{k[b>>2]=0;b=b+4|0}while((b|0)<(d|0));k[f>>2]=e;k[f+8>>2]=a;k[f+12>>2]=-1;k[f+48>>2]=1;Ya[k[(k[e>>2]|0)+28>>2]&3](e,f,k[c>>2]|0,1);if((k[f+24>>2]|0)==1){k[c>>2]=k[f+16>>2];b=1}else b=0}else b=0;else b=1;r=g;return b|0}function _b(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0;a=b+16|0;e=k[a>>2]|0;do if(e){if((e|0)!=(c|0)){d=b+36|0;k[d>>2]=(k[d>>2]|0)+1;k[b+24>>2]=2;i[b+54>>0]=1;break}a=b+24|0;if((k[a>>2]|0)==2)k[a>>2]=d}else{k[a>>2]=c;k[b+24>>2]=d;k[b+36>>2]=1}while(0);return}function $b(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;if((a|0)==(k[b+8>>2]|0))_b(0,b,c,d);return}function ac(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;if((a|0)==(k[b+8>>2]|0))_b(0,b,c,d);else{a=k[a+8>>2]|0;Ya[k[(k[a>>2]|0)+28>>2]&3](a,b,c,d)}return}function bc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,l=0,m=0,n=0,o=0,p=0,q=0;q=r;r=r+64|0;p=q;o=k[a>>2]|0;n=a+(k[o+-8>>2]|0)|0;o=k[o+-4>>2]|0;k[p>>2]=c;k[p+4>>2]=a;k[p+8>>2]=b;k[p+12>>2]=d;d=p+16|0;a=p+20|0;b=p+24|0;e=p+28|0;f=p+32|0;g=p+40|0;h=(o|0)==(c|0);l=d;m=l+36|0;do{k[l>>2]=0;l=l+4|0}while((l|0)<(m|0));j[d+36>>1]=0;i[d+38>>0]=0;a:do if(h){k[p+48>>2]=1;Xa[k[(k[c>>2]|0)+20>>2]&3](c,p,n,n,1,0);d=(k[b>>2]|0)==1?n:0}else{Sa[k[(k[o>>2]|0)+24>>2]&3](o,p,n,1,0);switch(k[p+36>>2]|0){case 0:{d=(k[g>>2]|0)==1&(k[e>>2]|0)==1&(k[f>>2]|0)==1?k[a>>2]|0:0;break a}case 1:break;default:{d=0;break a}}if((k[b>>2]|0)!=1?!((k[g>>2]|0)==0&(k[e>>2]|0)==1&(k[f>>2]|0)==1):0){d=0;break}d=k[d>>2]|0}while(0);r=q;return d|0}function cc(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;i[b+53>>0]=1;do if((k[b+4>>2]|0)==(d|0)){i[b+52>>0]=1;d=b+16|0;a=k[d>>2]|0;if(!a){k[d>>2]=c;k[b+24>>2]=e;k[b+36>>2]=1;if(!((e|0)==1?(k[b+48>>2]|0)==1:0))break;i[b+54>>0]=1;break}if((a|0)!=(c|0)){e=b+36|0;k[e>>2]=(k[e>>2]|0)+1;i[b+54>>0]=1;break}a=b+24|0;d=k[a>>2]|0;if((d|0)==2){k[a>>2]=e;d=e}if((d|0)==1?(k[b+48>>2]|0)==1:0)i[b+54>>0]=1}while(0);return}function dc(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0;a:do if((a|0)==(k[b+8>>2]|0)){if((k[b+4>>2]|0)==(c|0)?(f=b+28|0,(k[f>>2]|0)!=1):0)k[f>>2]=d}else{if((a|0)!=(k[b>>2]|0)){h=k[a+8>>2]|0;Sa[k[(k[h>>2]|0)+24>>2]&3](h,b,c,d,e);break}if((k[b+16>>2]|0)!=(c|0)?(g=b+20|0,(k[g>>2]|0)!=(c|0)):0){k[b+32>>2]=d;d=b+44|0;if((k[d>>2]|0)==4)break;f=b+52|0;i[f>>0]=0;j=b+53|0;i[j>>0]=0;a=k[a+8>>2]|0;Xa[k[(k[a>>2]|0)+20>>2]&3](a,b,c,c,1,e);if(i[j>>0]|0){if(!(i[f>>0]|0)){f=1;h=13}}else{f=0;h=13}do if((h|0)==13){k[g>>2]=c;j=b+40|0;k[j>>2]=(k[j>>2]|0)+1;if((k[b+36>>2]|0)==1?(k[b+24>>2]|0)==2:0){i[b+54>>0]=1;if(f)break}else h=16;if((h|0)==16?f:0)break;k[d>>2]=4;break a}while(0);k[d>>2]=3;break}if((d|0)==1)k[b+32>>2]=1}while(0);return}function ec(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0,g=0;do if((a|0)==(k[b+8>>2]|0)){if((k[b+4>>2]|0)==(c|0)?(g=b+28|0,(k[g>>2]|0)!=1):0)k[g>>2]=d}else if((a|0)==(k[b>>2]|0)){if((k[b+16>>2]|0)!=(c|0)?(f=b+20|0,(k[f>>2]|0)!=(c|0)):0){k[b+32>>2]=d;k[f>>2]=c;e=b+40|0;k[e>>2]=(k[e>>2]|0)+1;if((k[b+36>>2]|0)==1?(k[b+24>>2]|0)==2:0)i[b+54>>0]=1;k[b+44>>2]=4;break}if((d|0)==1)k[b+32>>2]=1}while(0);return}function fc(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;if((a|0)==(k[b+8>>2]|0))cc(0,b,c,d,e);else{a=k[a+8>>2]|0;Xa[k[(k[a>>2]|0)+20>>2]&3](a,b,c,d,e,f)}return}function gc(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;if((a|0)==(k[b+8>>2]|0))cc(0,b,c,d,e);return}function hc(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0;e=r;r=r+16|0;d=e;k[d>>2]=k[c>>2];a=Ra[k[(k[a>>2]|0)+16>>2]&7](a,b,d)|0;if(a)k[c>>2]=k[d>>2];r=e;return a&1|0}function ic(a){a=a|0;if(!a)a=0;else a=(bc(a,24,72,0)|0)!=0;return a&1|0}function jc(){var a=0,b=0,c=0,d=0,e=0,f=0,g=0,h=0;e=r;r=r+48|0;g=e+32|0;c=e+24|0;h=e+16|0;f=e;e=e+36|0;a=Pb()|0;if((a|0)!=0?(d=k[a>>2]|0,(d|0)!=0):0){a=d+48|0;b=k[a>>2]|0;a=k[a+4>>2]|0;if(!((b&-256|0)==1126902528&(a|0)==1129074247)){k[c>>2]=2406;Ob(2356,c)}if((b|0)==1126902529&(a|0)==1129074247)a=k[d+44>>2]|0;else a=d+80|0;k[e>>2]=a;d=k[d>>2]|0;a=k[d+4>>2]|0;if(Ra[k[(k[8>>2]|0)+16>>2]&7](8,d,e)|0){h=k[e>>2]|0;h=Ua[k[(k[h>>2]|0)+8>>2]&1](h)|0;k[f>>2]=2406;k[f+4>>2]=a;k[f+8>>2]=h;Ob(2270,f)}else{k[h>>2]=2406;k[h+4>>2]=a;Ob(2315,h)}}Ob(2394,g)}function kc(){var a=0;a=r;r=r+16|0;if(!(Fa(188,6)|0)){r=a;return}else Ob(2167,a)}function lc(a){a=a|0;var b=0;b=r;r=r+16|0;Tc(a);if(!(wa(k[47]|0,0)|0)){r=b;return}else Ob(2217,b)}function mc(a){a=a|0;var b=0,c=0;b=0;while(1){if((l[2415+b>>0]|0)==(a|0)){c=2;break}b=b+1|0;if((b|0)==87){b=87;a=2503;c=5;break}}if((c|0)==2)if(!b)a=2503;else{a=2503;c=5}if((c|0)==5)while(1){c=a;while(1){a=c+1|0;if(!(i[c>>0]|0))break;else c=a}b=b+-1|0;if(!b)break;else c=5}return a|0}function nc(){var a=0;if(!0)a=248;else{a=(za()|0)+60|0;a=k[a>>2]|0}return a|0}function oc(a){a=a|0;var b=0;if(a>>>0>4294963200){b=nc()|0;k[b>>2]=0-a;a=-1}return a|0}function pc(a,b){a=+a;b=b|0;var c=0,d=0,e=0;p[t>>3]=a;c=k[t>>2]|0;d=k[t+4>>2]|0;e=ad(c|0,d|0,52)|0;e=e&2047;switch(e|0){case 0:{if(a!=0.0){a=+pc(a*18446744073709552.0e3,b);c=(k[b>>2]|0)+-64|0}else c=0;k[b>>2]=c;break}case 2047:break;default:{k[b>>2]=e+-1022;k[t>>2]=c;k[t+4>>2]=d&-2146435073|1071644672;a=+p[t>>3]}}return +a}function qc(a,b){a=+a;b=b|0;return +(+pc(a,b))}function rc(a,b,c){a=a|0;b=b|0;c=c|0;do if(a){if(b>>>0<128){i[a>>0]=b;a=1;break}if(b>>>0<2048){i[a>>0]=b>>>6|192;i[a+1>>0]=b&63|128;a=2;break}if(b>>>0<55296|(b&-8192|0)==57344){i[a>>0]=b>>>12|224;i[a+1>>0]=b>>>6&63|128;i[a+2>>0]=b&63|128;a=3;break}if((b+-65536|0)>>>0<1048576){i[a>>0]=b>>>18|240;i[a+1>>0]=b>>>12&63|128;i[a+2>>0]=b>>>6&63|128;i[a+3>>0]=b&63|128;a=4;break}else{a=nc()|0;k[a>>2]=84;a=-1;break}}else a=1;while(0);return a|0}function sc(a,b){a=a|0;b=b|0;if(!a)a=0;else a=rc(a,b,0)|0;return a|0}function tc(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0;if((k[b+76>>2]|0)>=0?(Cc(b)|0)!=0:0){if((i[b+75>>0]|0)!=(a|0)?(d=b+20|0,e=k[d>>2]|0,e>>>0<(k[b+16>>2]|0)>>>0):0){k[d>>2]=e+1;i[e>>0]=a;c=a&255}else c=Ec(b,a)|0;Dc(b)}else g=3;do if((g|0)==3){if((i[b+75>>0]|0)!=(a|0)?(f=b+20|0,c=k[f>>2]|0,c>>>0<(k[b+16>>2]|0)>>>0):0){k[f>>2]=c+1;i[c>>0]=a;c=a&255;break}c=Ec(b,a)|0}while(0);return c|0}function uc(a,b){a=a|0;b=b|0;return (wc(a,Lc(a)|0,1,b)|0)+-1|0}function vc(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0;d=c+16|0;e=k[d>>2]|0;if(!e)if(!(Jc(c)|0)){e=k[d>>2]|0;f=4}else d=0;else f=4;a:do if((f|0)==4){g=c+20|0;f=k[g>>2]|0;if((e-f|0)>>>0>>0){d=Ra[k[c+36>>2]&7](c,a,b)|0;break}b:do if((i[c+75>>0]|0)>-1){d=b;while(1){if(!d){e=f;d=0;break b}e=d+-1|0;if((i[a+e>>0]|0)==10)break;else d=e}if((Ra[k[c+36>>2]&7](c,a,d)|0)>>>0 >>16&2;j=14-(p|q|j)+(v< >>(o>>>0))&i|l<>>0)o=q;else{h=0;do{B=bd(k[o>>2]|0,0,s|0)|0;B=_c(B|0,L|0,h|0,0)|0;h=L;A=kd(B|0,h|0,1e9,0)|0;k[o>>2]=A;h=jd(B|0,h|0,1e9,0)|0;o=o+-4|0}while(o>>>0>=q>>>0);if(!h){o=q;break}o=q+-4|0;k[o>>2]=h}while(0);while(1){if(m>>>0<=o>>>0)break;h=m+-4|0;if(!(k[h>>2]|0))m=h;else break}h=(k[da>>2]|0)-s|0;k[da>>2]=h;if((h|0)>0)q=o;else break}}else o=E;if((h|0)<0){y=((g+25|0)/9|0)+1|0;z=(C|0)==102;w=o;while(1){x=0-h|0;x=(x|0)>9?9:x;do if(w>>>0
>>0)n=.5;else{if((y|0)==(s|0)?(E+(z+-1022<<2)|0)==(m|0):0){n=1.0;break}n=1.5}while(0);do if(F){if((i[G>>0]|0)!=45)break;v=-v;n=-n}while(0);s=x-y|0;k[o>>2]=s;if(!(v+n!=v)){q=w;break}C=s+q|0;k[o>>2]=C;if(C>>>0>999999999){h=w;while(1){q=o+-4|0;k[o>>2]=0;if(q>>>0>>0&(g|0)>-1)}Rc(a,48,g+18|0,18,0);if(k[a>>2]&32)break;vc(u,_-u|0,a)|0}while(0);Rc(a,32,J,y,H^8192);g=(y|0)<(J|0)?J:y}else{s=(u&32|0)!=0;q=n!=n|0.0!=0.0;h=q?0:F;o=h+3|0;Rc(a,32,J,o,m);g=k[a>>2]|0;if(!(g&32)){vc(G,h,a)|0;g=k[a>>2]|0}if(!(g&32))vc(q?(s?5871:5875):s?5863:5867,3,a)|0;Rc(a,32,J,o,H^8192);g=(o|0)<(J|0)?J:o}while(0);w=I;continue a}default:{m=H;h=o;s=0;u=5827;g=N}}while(0);g:do if((K|0)==64){m=aa;h=k[m>>2]|0;m=k[m+4>>2]|0;q=u&32;if(!((h|0)==0&(m|0)==0)){g=N;do{g=g+-1|0;i[g>>0]=l[5811+(h&15)>>0]|q;h=ad(h|0,m|0,4)|0;m=L}while(!((h|0)==0&(m|0)==0));K=aa;if((s&8|0)==0|(k[K>>2]|0)==0&(k[K+4>>2]|0)==0){h=s;s=0;q=5827;K=77}else{h=s;s=2;q=5827+(u>>4)|0;K=77}}else{g=N;h=s;s=0;q=5827;K=77}}else if((K|0)==76){g=Qc(g,h,N)|0;h=H;s=m;K=77}else if((K|0)==82){K=0;H=Kc(g,0,o)|0;G=(H|0)==0;w=g;h=G?o:H-g|0;s=0;u=5827;g=G?g+o|0:H}else if((K|0)==86){K=0;h=0;g=0;q=k[aa>>2]|0;while(1){m=k[q>>2]|0;if(!m)break;g=sc(ea,m)|0;if((g|0)<0|g>>>0>(o-h|0)>>>0)break;h=g+h|0;if(o>>>0>h>>>0)q=q+4|0;else break}if((g|0)<0){f=-1;break a}Rc(a,32,J,h,H);if(!h){g=0;K=98}else{m=0;o=k[aa>>2]|0;while(1){g=k[o>>2]|0;if(!g){g=h;K=98;break g}g=sc(ea,g)|0;m=g+m|0;if((m|0)>(h|0)){g=h;K=98;break g}if(!(k[a>>2]&32))vc(ea,g,a)|0;if(m>>>0>=h>>>0){g=h;K=98;break}else o=o+4|0}}}while(0);if((K|0)==98){K=0;Rc(a,32,J,g,H^8192);w=I;g=(J|0)>(g|0)?J:g;continue}if((K|0)==77){K=0;m=(o|0)>-1?h&-65537:h;h=aa;h=(k[h>>2]|0)!=0|(k[h+4>>2]|0)!=0;if((o|0)!=0|h){h=(h&1^1)+(U-g)|0;w=g;h=(o|0)>(h|0)?o:h;u=q;g=N}else{w=N;h=0;u=q;g=N}}q=g-w|0;h=(h|0)<(q|0)?q:h;o=s+h|0;g=(J|0)<(o|0)?o:J;Rc(a,32,g,o,m);if(!(k[a>>2]&32))vc(u,s,a)|0;Rc(a,48,g,o,m^65536);Rc(a,48,h,q,0);if(!(k[a>>2]&32))vc(w,q,a)|0;Rc(a,32,g,o,m^8192);w=I}h:do if((K|0)==245)if(!a)if(b){f=1;while(1){b=k[e+(f<<2)>>2]|0;if(!b)break;Pc(d+(f<<3)|0,b,c);f=f+1|0;if((f|0)>=10){f=1;break h}}if((f|0)<10)while(1){if(k[e+(f<<2)>>2]|0){f=-1;break h}f=f+1|0;if((f|0)>=10){f=1;break}}else f=1}else f=0;while(0);r=ga;return f|0}function Nc(a){a=a|0;if(!(k[a+68>>2]|0))Dc(a);return}function Oc(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0;d=a+20|0;e=k[d>>2]|0;a=(k[a+16>>2]|0)-e|0;a=a>>>0>c>>>0?c:a;cd(e|0,b|0,a|0)|0;k[d>>2]=(k[d>>2]|0)+a;return c|0}function Pc(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0.0;a:do if(b>>>0<=20)do switch(b|0){case 9:{d=(k[c>>2]|0)+(4-1)&~(4-1);b=k[d>>2]|0;k[c>>2]=d+4;k[a>>2]=b;break a}case 10:{d=(k[c>>2]|0)+(4-1)&~(4-1);b=k[d>>2]|0;k[c>>2]=d+4;d=a;k[d>>2]=b;k[d+4>>2]=((b|0)<0)<<31>>31;break a}case 11:{d=(k[c>>2]|0)+(4-1)&~(4-1);b=k[d>>2]|0;k[c>>2]=d+4;d=a;k[d>>2]=b;k[d+4>>2]=0;break a}case 12:{d=(k[c>>2]|0)+(8-1)&~(8-1);b=d;e=k[b>>2]|0;b=k[b+4>>2]|0;k[c>>2]=d+8;d=a;k[d>>2]=e;k[d+4>>2]=b;break a}case 13:{e=(k[c>>2]|0)+(4-1)&~(4-1);d=k[e>>2]|0;k[c>>2]=e+4;d=(d&65535)<<16>>16;e=a;k[e>>2]=d;k[e+4>>2]=((d|0)<0)<<31>>31;break a}case 14:{e=(k[c>>2]|0)+(4-1)&~(4-1);d=k[e>>2]|0;k[c>>2]=e+4;e=a;k[e>>2]=d&65535;k[e+4>>2]=0;break a}case 15:{e=(k[c>>2]|0)+(4-1)&~(4-1);d=k[e>>2]|0;k[c>>2]=e+4;d=(d&255)<<24>>24;e=a;k[e>>2]=d;k[e+4>>2]=((d|0)<0)<<31>>31;break a}case 16:{e=(k[c>>2]|0)+(4-1)&~(4-1);d=k[e>>2]|0;k[c>>2]=e+4;e=a;k[e>>2]=d&255;k[e+4>>2]=0;break a}case 17:{e=(k[c>>2]|0)+(8-1)&~(8-1);f=+p[e>>3];k[c>>2]=e+8;p[a>>3]=f;break a}case 18:{e=(k[c>>2]|0)+(8-1)&~(8-1);f=+p[e>>3];k[c>>2]=e+8;p[a>>3]=f;break a}default:break a}while(0);while(0);return}function Qc(a,b,c){a=a|0;b=b|0;c=c|0;var d=0;if(b>>>0>0|(b|0)==0&a>>>0>4294967295)while(1){d=kd(a|0,b|0,10,0)|0;c=c+-1|0;i[c>>0]=d|48;d=jd(a|0,b|0,10,0)|0;if(b>>>0>9|(b|0)==9&a>>>0>4294967295){a=d;b=L}else{a=d;break}}if(a)while(1){c=c+-1|0;i[c>>0]=(a>>>0)%10|0|48;if(a>>>0<10)break;else a=(a>>>0)/10|0}return c|0}function Rc(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0,g=0,h=0;h=r;r=r+256|0;g=h;do if((c|0)>(d|0)&(e&73728|0)==0){e=c-d|0;$c(g|0,b|0,(e>>>0>256?256:e)|0)|0;b=k[a>>2]|0;f=(b&32|0)==0;if(e>>>0>255){d=c-d|0;do{if(f){vc(g,256,a)|0;b=k[a>>2]|0}e=e+-256|0;f=(b&32|0)==0}while(e>>>0>255);if(f)e=d&255;else break}else if(!f)break;vc(g,e,a)|0}while(0);r=h;return}function Sc(a){a=a|0;var b=0,c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0;do if(a>>>0<245){o=a>>>0<11?16:a+11&-8;a=o>>>3;h=k[147]|0;c=h>>>a;if(c&3){a=(c&1^1)+a|0;d=a<<1;c=628+(d<<2)|0;d=628+(d+2<<2)|0;e=k[d>>2]|0;f=e+8|0;g=k[f>>2]|0;do if((c|0)!=(g|0)){if(g>>>0<(k[151]|0)>>>0)Aa();b=g+12|0;if((k[b>>2]|0)==(e|0)){k[b>>2]=c;k[d>>2]=g;break}else Aa()}else k[147]=h&~(1<>2]=M|3;M=e+(M|4)|0;k[M>>2]=k[M>>2]|1;M=f;return M|0}g=k[149]|0;if(o>>>0>g>>>0){if(c){d=2<>>12&16;d=d>>>i;e=d>>>5&8;d=d>>>e;f=d>>>2&4;d=d>>>f;c=d>>>1&2;d=d>>>c;a=d>>>1&1;a=(e|i|f|c|a)+(d>>>a)|0;d=a<<1;c=628+(d<<2)|0;d=628+(d+2<<2)|0;f=k[d>>2]|0;i=f+8|0;e=k[i>>2]|0;do if((c|0)!=(e|0)){if(e>>>0<(k[151]|0)>>>0)Aa();b=e+12|0;if((k[b>>2]|0)==(f|0)){k[b>>2]=c;k[d>>2]=e;j=k[149]|0;break}else Aa()}else{k[147]=h&~(1<>2]=o|3;h=f+o|0;k[f+(o|4)>>2]=g|1;k[f+M>>2]=g;if(j){e=k[152]|0;c=j>>>3;b=c<<1;d=628+(b<<2)|0;a=k[147]|0;c=1<>>16&4;v=v<
>>16&2;e=14-(q|r|e)+(s<
>>16&2;f=14-(q|r|f)+(s<