diff --git a/Apps/Sandcastle/gallery/CZML Reference Properties.html b/Apps/Sandcastle/gallery/CZML Reference Properties.html index fb11549fab24..862c96ca8a6e 100644 --- a/Apps/Sandcastle/gallery/CZML Reference Properties.html +++ b/Apps/Sandcastle/gallery/CZML Reference Properties.html @@ -10,10 +10,12 @@
@@ -38,7 +40,7 @@ "cartographicDegrees" : [-110.0, 50.0, 0] } }, { - "id" : "outlineColor-reference", + "id" : "fillColor-reference", "name" : "Referencing Position", "description" : "For more examples of reference properties, see CZML Polygon - Interpolating References.
", "billboard" : { @@ -62,11 +64,11 @@ "text" : "referencing position" }, "position" : { - "reference" : "position-reference#position" + "reference" : "position-reference#position" } }, { "id" : "polygon", - "name" : "Referencing Outline Color", + "name" : "Referencing Fill Color", "description" : "For more examples of reference properties, see CZML Polygon - Interpolating References.
", "label" : { "fillColor" : { @@ -78,7 +80,7 @@ "cartesian2" : [20, 0] }, "style" : "FILL_AND_OUTLINE", - "text" : "referencing outlineColor" + "text" : "referencing fillColor" }, "position" : { "cartographicDegrees" : [-105, 35, 0] @@ -94,17 +96,18 @@ ] }, "height" : 0, - "outline" : true, - "outlineColor" : { - "reference" : "outlineColor-reference#label.outlineColor" - }, - "outlineWidth" : 5 + "material" : { + "solidColor" : { + "color" : { + "reference" : "fillColor-reference#label.outlineColor" + } + } + } } }]; var viewer = new Cesium.Viewer('cesiumContainer'); viewer.dataSources.add(Cesium.CzmlDataSource.load(czml)); - //Sandcastle_End Sandcastle.finishedLoading(); } diff --git a/CHANGES.md b/CHANGES.md index c5ede713ac9a..1967cdddb8a4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,10 +2,15 @@ Change Log ========== ### 1.39 - 2017-11-01 +* Added the ability to load Cesium's assets from the local file system if security permissions allow it. [#5830](https://github.com/AnalyticalGraphicsInc/cesium/issues/5830) * Added function that inserts missing namespace declarations into KML files. [#5860](https://github.com/AnalyticalGraphicsInc/cesium/pull/5860) * Added support for the layer.json `parentUrl` property in `CesiumTerrainProvider` to allow for compositing of tilesets. * Fixed a bug that caused KML ground overlays to appear distorted when rotation was applied. [#5914](https://github.com/AnalyticalGraphicsInc/cesium/issues/5914) +* KML files load when a Network Link fails [#5871](https://github.com/AnalyticalGraphicsInc/cesium/pull/5871) * Adds `invertClassification` and `invertClassificationColor` to `Scene`. When `invertClassification` is `true`, any 3D Tiles geometry that is not classified by a `ClassificationPrimitive` or `GroundPrimitive` will have its color multiplied by `invertClassificationColor`. [#5836](https://github.com/AnalyticalGraphicsInc/cesium/pull/5836) +* Added `eyeSeparation` and `focalLength` properties to `Scene` to configure VR settings. [#5917](https://github.com/AnalyticalGraphicsInc/cesium/pull/5917) +* Added `customTags` property to the UrlTemplateImageryProvider to allow custom keywords in the template URL. [#5696](https://github.com/AnalyticalGraphicsInc/cesium/pull/5696) +* Improved CZML Reference Properties example [#5754](https://github.com/AnalyticalGraphicsInc/cesium/pull/5754) * Fixed bug with placemarks in imported KML: placemarks with no specified icon would be displayed with default icon. [#5819](https://github.com/AnalyticalGraphicsInc/cesium/issues/5819) ### 1.38 - 2017-10-02 diff --git a/Source/Core/HeightmapTessellator.js b/Source/Core/HeightmapTessellator.js index 93f39bb0f2b0..b7604ce29a86 100644 --- a/Source/Core/HeightmapTessellator.js +++ b/Source/Core/HeightmapTessellator.js @@ -219,6 +219,11 @@ define([ var granularityX = rectangleWidth / (width - 1); var granularityY = rectangleHeight / (height - 1); + if (!isGeographic) { + rectangleWidth *= oneOverGlobeSemimajorAxis; + rectangleHeight *= oneOverGlobeSemimajorAxis; + } + var radiiSquared = ellipsoid.radiiSquared; var radiiSquaredX = radiiSquared.x; var radiiSquaredY = radiiSquared.y; diff --git a/Source/Core/OrientedBoundingBox.js b/Source/Core/OrientedBoundingBox.js index 8d3e61b3c7b3..d130972aab50 100644 --- a/Source/Core/OrientedBoundingBox.js +++ b/Source/Core/OrientedBoundingBox.js @@ -272,8 +272,8 @@ define([ if (!defined(rectangle)) { throw new DeveloperError('rectangle is required'); } - if (rectangle.width < 0.0 || rectangle.width > CesiumMath.PI) { - throw new DeveloperError('Rectangle width must be between 0 and pi'); + if (rectangle.width < 0.0 || rectangle.width > CesiumMath.TWO_PI) { + throw new DeveloperError('Rectangle width must be between 0 and 2*pi'); } if (rectangle.height < 0.0 || rectangle.height > CesiumMath.PI) { throw new DeveloperError('Rectangle height must be between 0 and pi'); diff --git a/Source/Core/loadWithXhr.js b/Source/Core/loadWithXhr.js index 1b92cfc10de7..49b35e94e7f8 100644 --- a/Source/Core/loadWithXhr.js +++ b/Source/Core/loadWithXhr.js @@ -172,8 +172,14 @@ define([ xhr.responseType = responseType; } + // While non-standard, file protocol always returns a status of 0 on success + var localFile = false; + if (typeof url === 'string') { + localFile = url.indexOf('file://') === 0; + } + xhr.onload = function() { - if (xhr.status < 200 || xhr.status >= 300) { + if ((xhr.status < 200 || xhr.status >= 300) && !(localFile && xhr.status === 0)) { deferred.reject(new RequestErrorEvent(xhr.status, xhr.response, xhr.getAllResponseHeaders())); return; } diff --git a/Source/DataSources/BillboardGraphics.js b/Source/DataSources/BillboardGraphics.js index 86c260c86d5f..07dc53346bd3 100644 --- a/Source/DataSources/BillboardGraphics.js +++ b/Source/DataSources/BillboardGraphics.js @@ -46,6 +46,7 @@ define([ * @param {Property} [options.sizeInMeters] A boolean Property specifying whether this billboard's size should be measured in meters. * @param {Property} [options.heightReference=HeightReference.NONE] A Property specifying what the height is relative to. * @param {Property} [options.distanceDisplayCondition] A Property specifying at what distance from the camera that this billboard will be displayed. + * @param {Property} [options.disableDepthTestDistance] A Property specifying the distance from the camera at which to disable the depth test to. * * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Billboards.html|Cesium Sandcastle Billboard Demo} */ diff --git a/Source/DataSources/KmlDataSource.js b/Source/DataSources/KmlDataSource.js index ab9ef7665b31..031406722efe 100644 --- a/Source/DataSources/KmlDataSource.js +++ b/Source/DataSources/KmlDataSource.js @@ -2225,6 +2225,8 @@ define([ } else if (viewRefreshMode === 'onRegion') { oneTimeWarning('kml-refrehMode-onRegion', 'KML - Unsupported viewRefreshMode: onRegion'); } + }).otherwise(function(error) { + oneTimeWarning('An error occured during loading ' + linkUrl); }); promises.push(promise); diff --git a/Source/DataSources/LabelGraphics.js b/Source/DataSources/LabelGraphics.js index 52cf604de454..b06f92f343ae 100644 --- a/Source/DataSources/LabelGraphics.js +++ b/Source/DataSources/LabelGraphics.js @@ -47,6 +47,7 @@ define([ * @param {Property} [options.scaleByDistance] A {@link NearFarScalar} Property used to set scale based on distance from the camera. * @param {Property} [options.heightReference=HeightReference.NONE] A Property specifying what the height is relative to. * @param {Property} [options.distanceDisplayCondition] A Property specifying at what distance from the camera that this label will be displayed. + * @param {Property} [options.disableDepthTestDistance] A Property specifying the distance from the camera at which to disable the depth test to. * * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Labels.html|Cesium Sandcastle Labels Demo} */ diff --git a/Source/DataSources/PointGraphics.js b/Source/DataSources/PointGraphics.js index 923622822561..14b10d6f78a2 100644 --- a/Source/DataSources/PointGraphics.js +++ b/Source/DataSources/PointGraphics.js @@ -30,6 +30,7 @@ define([ * @param {Property} [options.translucencyByDistance] A {@link NearFarScalar} Property used to set translucency based on distance from the camera. * @param {Property} [options.heightReference=HeightReference.NONE] A Property specifying what the height is relative to. * @param {Property} [options.distanceDisplayCondition] A Property specifying at what distance from the camera that this point will be displayed. + * @param {Property} [options.disableDepthTestDistance] A Property specifying the distance from the camera at which to disable the depth test to. */ function PointGraphics(options) { this._color = undefined; diff --git a/Source/Renderer/Buffer.js b/Source/Renderer/Buffer.js index 3e6d4bdbede3..bbc0d272e3ac 100644 --- a/Source/Renderer/Buffer.js +++ b/Source/Renderer/Buffer.js @@ -1,4 +1,5 @@ define([ + '../Core/Check', '../Core/defaultValue', '../Core/defined', '../Core/defineProperties', @@ -8,6 +9,7 @@ define([ '../Core/WebGLConstants', './BufferUsage' ], function( + Check, defaultValue, defined, defineProperties, @@ -25,9 +27,7 @@ define([ options = defaultValue(options, defaultValue.EMPTY_OBJECT); //>>includeStart('debug', pragmas.debug); - if (!defined(options.context)) { - throw new DeveloperError('options.context is required.'); - } + Check.defined('options.context', options.context); if (!defined(options.typedArray) && !defined(options.sizeInBytes)) { throw new DeveloperError('Either options.sizeInBytes or options.typedArray is required.'); @@ -37,8 +37,9 @@ define([ throw new DeveloperError('Cannot pass in both options.sizeInBytes and options.typedArray.'); } - if (defined(options.typedArray) && !(typeof options.typedArray === 'object' && typeof options.typedArray.byteLength === 'number')) { - throw new DeveloperError('options.typedArray must be a typed array'); + if (defined(options.typedArray)) { + Check.typeOf.object('options.typedArray', options.typedArray); + Check.typeOf.number('options.typedArray.byteLength', options.typedArray.byteLength); } if (!BufferUsage.validate(options.usage)) { @@ -58,9 +59,7 @@ define([ } //>>includeStart('debug', pragmas.debug); - if (sizeInBytes <= 0) { - throw new DeveloperError('Buffer size must be greater than zero.'); - } + Check.typeOf.number.greaterThan('sizeInBytes', sizeInBytes, 0); //>>includeEnd('debug'); var buffer = gl.createBuffer(); @@ -69,6 +68,7 @@ define([ gl.bindBuffer(bufferTarget, null); this._gl = gl; + this._webgl2 = options.context._webgl2; this._bufferTarget = bufferTarget; this._sizeInBytes = sizeInBytes; this._usage = usage; @@ -118,9 +118,7 @@ define([ */ Buffer.createVertexBuffer = function(options) { //>>includeStart('debug', pragmas.debug); - if (!defined(options.context)) { - throw new DeveloperError('options.context is required.'); - } + Check.defined('options.context', options.context); //>>includeEnd('debug'); return new Buffer({ @@ -179,15 +177,13 @@ define([ */ Buffer.createIndexBuffer = function(options) { //>>includeStart('debug', pragmas.debug); - if (!defined(options.context)) { - throw new DeveloperError('options.context is required.'); - } + Check.defined('options.context', options.context); if (!IndexDatatype.validate(options.indexDatatype)) { throw new DeveloperError('Invalid indexDatatype.'); } - if ((options.indexDatatype === IndexDatatype.UNSIGNED_INT) && !options.context.elementIndexUint) { + if (options.indexDatatype === IndexDatatype.UNSIGNED_INT && !options.context.elementIndexUint) { throw new DeveloperError('IndexDatatype.UNSIGNED_INT requires OES_element_index_uint, which is not supported on this system. Check context.elementIndexUint.'); } //>>includeEnd('debug'); @@ -249,18 +245,106 @@ define([ offsetInBytes = defaultValue(offsetInBytes, 0); //>>includeStart('debug', pragmas.debug); - if (!arrayView) { + Check.defined('arrayView', arrayView); + Check.typeOf.number.lessThanOrEquals('offsetInBytes + arrayView.byteLength', offsetInBytes + arrayView.byteLength, this._sizeInBytes); + //>>includeEnd('debug'); + + var gl = this._gl; + var target = this._bufferTarget; + gl.bindBuffer(target, this._buffer); + gl.bufferSubData(target, offsetInBytes, arrayView); + gl.bindBuffer(target, null); + }; + + Buffer.prototype.copyFromBuffer = function(readBuffer, readOffset, writeOffset, sizeInBytes) { + //>>includeStart('debug', pragmas.debug); + if (!this._webgl2) { + throw new DeveloperError('A WebGL 2 context is required.'); + } + if (!defined(readBuffer)) { + throw new DeveloperError('readBuffer must be defined.'); + } + if (!defined(sizeInBytes) || sizeInBytes <= 0) { + throw new DeveloperError('sizeInBytes must be defined and be greater than zero.'); + } + if (!defined(readOffset) || readOffset < 0 || readOffset + sizeInBytes > readBuffer._sizeInBytes) { + throw new DeveloperError('readOffset must be greater than or equal to zero and readOffset + sizeInBytes must be less than of equal to readBuffer.sizeInBytes.'); + } + if (!defined(writeOffset) || writeOffset < 0 || writeOffset + sizeInBytes > this._sizeInBytes) { + throw new DeveloperError('writeOffset must be greater than or equal to zero and writeOffset + sizeInBytes must be less than of equal to this.sizeInBytes.'); + } + if (this._buffer === readBuffer._buffer && ((writeOffset >= readOffset && writeOffset < readOffset + sizeInBytes) || (readOffset > writeOffset && readOffset < writeOffset + sizeInBytes))) { + throw new DeveloperError('When readBuffer is equal to this, the ranges [readOffset + sizeInBytes) and [writeOffset, writeOffset + sizeInBytes) must not overlap.'); + } + if ((this._bufferTarget === WebGLConstants.ELEMENT_ARRAY_BUFFER && readBuffer._bufferTarget !== WebGLConstants.ELEMENT_ARRAY_BUFFER) || + (this._bufferTarget !== WebGLConstants.ELEMENT_ARRAY_BUFFER && readBuffer._bufferTarget === WebGLConstants.ELEMENT_ARRAY_BUFFER)) { + throw new DeveloperError('Can not copy an index buffer into another buffer type.'); + } + //>>includeEnd('debug'); + + var readTarget = WebGLConstants.COPY_READ_BUFFER; + var writeTarget = WebGLConstants.COPY_WRITE_BUFFER; + + var gl = this._gl; + gl.bindBuffer(writeTarget, this._buffer); + gl.bindBuffer(readTarget, readBuffer._buffer); + gl.copyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, sizeInBytes); + gl.bindBuffer(writeTarget, null); + gl.bindBuffer(readTarget, null); + }; + + Buffer.prototype.getBufferData = function(arrayView, sourceOffset, destinationOffset, length) { + sourceOffset = defaultValue(sourceOffset, 0); + destinationOffset = defaultValue(destinationOffset, 0); + + //>>includeStart('debug', pragmas.debug); + if (!this._webgl2) { + throw new DeveloperError('A WebGL 2 context is required.'); + } + if (!defined(arrayView)) { throw new DeveloperError('arrayView is required.'); } - if (offsetInBytes + arrayView.byteLength > this._sizeInBytes) { - throw new DeveloperError('This buffer is not large enough.'); + + var copyLength; + var elementSize; + var arrayLength = arrayView.byteLength; + if (!defined(length)) { + if (defined(arrayLength)) { + copyLength = arrayLength - destinationOffset; + elementSize = 1; + } else { + arrayLength = arrayView.length; + copyLength = arrayLength - destinationOffset; + elementSize = arrayView.BYTES_PER_ELEMENT; + } + } else { + copyLength = length; + if (defined(arrayLength)) { + elementSize = 1; + } else { + arrayLength = arrayView.length; + elementSize = arrayView.BYTES_PER_ELEMENT; + } + } + + if (destinationOffset < 0 || destinationOffset > arrayLength) { + throw new DeveloperError('destinationOffset must be greater than zero and less than the arrayView length.'); + } + if (destinationOffset + copyLength > arrayLength) { + throw new DeveloperError('destinationOffset + length must be less than or equal to the arrayViewLength.'); + } + if (sourceOffset < 0 || sourceOffset > this._sizeInBytes) { + throw new DeveloperError('sourceOffset must be greater than zero and less than the buffers size.'); + } + if (sourceOffset + copyLength * elementSize > this._sizeInBytes) { + throw new DeveloperError('sourceOffset + length must be less than the buffers size.'); } //>>includeEnd('debug'); var gl = this._gl; - var target = this._bufferTarget; + var target = WebGLConstants.COPY_READ_BUFFER; gl.bindBuffer(target, this._buffer); - gl.bufferSubData(target, offsetInBytes, arrayView); + gl.getBufferSubData(target, sourceOffset, arrayView, destinationOffset, length); gl.bindBuffer(target, null); }; diff --git a/Source/Renderer/ComputeEngine.js b/Source/Renderer/ComputeEngine.js index 1ab87d6cebd8..2329b840b216 100644 --- a/Source/Renderer/ComputeEngine.js +++ b/Source/Renderer/ComputeEngine.js @@ -1,5 +1,6 @@ define([ '../Core/BoundingRectangle', + '../Core/Check', '../Core/Color', '../Core/defined', '../Core/destroyObject', @@ -13,6 +14,7 @@ define([ './ShaderProgram' ], function( BoundingRectangle, + Check, Color, defined, destroyObject, @@ -75,9 +77,7 @@ define([ ComputeEngine.prototype.execute = function(computeCommand) { //>>includeStart('debug', pragmas.debug); - if (!defined(computeCommand)) { - throw new DeveloperError('computeCommand is required.'); - } + Check.defined('computeCommand', computeCommand); //>>includeEnd('debug'); // This may modify the command's resources, so do error checking afterwards @@ -90,9 +90,7 @@ define([ throw new DeveloperError('computeCommand.fragmentShaderSource or computeCommand.shaderProgram is required.'); } - if (!defined(computeCommand.outputTexture)) { - throw new DeveloperError('computeCommand.outputTexture is required.'); - } + Check.defined('computeCommand.outputTexture', computeCommand.outputTexture); //>>includeEnd('debug'); var outputTexture = computeCommand.outputTexture; diff --git a/Source/Renderer/Context.js b/Source/Renderer/Context.js index 5ab984919331..2815a53e8582 100644 --- a/Source/Renderer/Context.js +++ b/Source/Renderer/Context.js @@ -1,87 +1,90 @@ define([ - '../Core/clone', - '../Core/Color', - '../Core/ComponentDatatype', - '../Core/createGuid', - '../Core/defaultValue', - '../Core/defined', - '../Core/defineProperties', - '../Core/destroyObject', - '../Core/DeveloperError', - '../Core/Geometry', - '../Core/GeometryAttribute', - '../Core/Matrix4', - '../Core/PrimitiveType', - '../Core/RuntimeError', - '../Core/WebGLConstants', - '../Shaders/ViewportQuadVS', - './BufferUsage', - './ClearCommand', - './ContextLimits', - './CubeMap', - './DrawCommand', - './PassState', - './PickFramebuffer', - './RenderState', - './ShaderCache', - './ShaderProgram', - './Texture', - './UniformState', - './VertexArray' - ], function( - clone, - Color, - ComponentDatatype, - createGuid, - defaultValue, - defined, - defineProperties, - destroyObject, - DeveloperError, - Geometry, - GeometryAttribute, - Matrix4, - PrimitiveType, - RuntimeError, - WebGLConstants, - ViewportQuadVS, - BufferUsage, - ClearCommand, - ContextLimits, - CubeMap, - DrawCommand, - PassState, - PickFramebuffer, - RenderState, - ShaderCache, - ShaderProgram, - Texture, - UniformState, - VertexArray) { + '../Core/Check', + '../Core/clone', + '../Core/Color', + '../Core/ComponentDatatype', + '../Core/createGuid', + '../Core/defaultValue', + '../Core/defined', + '../Core/defineProperties', + '../Core/destroyObject', + '../Core/DeveloperError', + '../Core/Geometry', + '../Core/GeometryAttribute', + '../Core/Matrix4', + '../Core/PrimitiveType', + '../Core/RuntimeError', + '../Core/WebGLConstants', + '../Shaders/ViewportQuadVS', + './BufferUsage', + './ClearCommand', + './ContextLimits', + './CubeMap', + './DrawCommand', + './PassState', + './PickFramebuffer', + './RenderState', + './ShaderCache', + './ShaderProgram', + './Texture', + './UniformState', + './VertexArray' +], function( + Check, + clone, + Color, + ComponentDatatype, + createGuid, + defaultValue, + defined, + defineProperties, + destroyObject, + DeveloperError, + Geometry, + GeometryAttribute, + Matrix4, + PrimitiveType, + RuntimeError, + WebGLConstants, + ViewportQuadVS, + BufferUsage, + ClearCommand, + ContextLimits, + CubeMap, + DrawCommand, + PassState, + PickFramebuffer, + RenderState, + ShaderCache, + ShaderProgram, + Texture, + UniformState, + VertexArray) { 'use strict'; /*global WebGLRenderingContext*/ + /*global WebGL2RenderingContext*/ function errorToString(gl, error) { var message = 'WebGL Error: '; switch (error) { - case gl.INVALID_ENUM: - message += 'INVALID_ENUM'; - break; - case gl.INVALID_VALUE: - message += 'INVALID_VALUE'; - break; - case gl.INVALID_OPERATION: - message += 'INVALID_OPERATION'; - break; - case gl.OUT_OF_MEMORY: - message += 'OUT_OF_MEMORY'; - break; - case gl.CONTEXT_LOST_WEBGL: - message += 'CONTEXT_LOST_WEBGL lost'; - break; - default: - message += 'Unknown (' + error + ')'; + case gl.INVALID_ENUM: + message += 'INVALID_ENUM'; + break; + case gl.INVALID_VALUE: + message += 'INVALID_VALUE'; + break; + case gl.INVALID_OPERATION: + message += 'INVALID_OPERATION'; + break; + case gl.OUT_OF_MEMORY: + message += 'OUT_OF_MEMORY'; + break; + case gl.CONTEXT_LOST_WEBGL: + message += 'CONTEXT_LOST_WEBGL lost'; + break; + default: + message += 'Unknown (' + error + ')'; } return message; @@ -90,7 +93,7 @@ define([ function createErrorMessage(gl, glFunc, glFuncArguments, error) { var message = errorToString(gl, error) + ': ' + glFunc.name + '('; - for ( var i = 0; i < glFuncArguments.length; ++i) { + for (var i = 0; i < glFuncArguments.length; ++i) { if (i !== 0) { message += ', '; } @@ -178,9 +181,7 @@ define([ } //>>includeStart('debug', pragmas.debug); - if (!defined(canvas)) { - throw new DeveloperError('canvas is required.'); - } + Check.defined('canvas', canvas); //>>includeEnd('debug'); this._canvas = canvas; @@ -194,8 +195,7 @@ define([ webglOptions.alpha = defaultValue(webglOptions.alpha, false); // WebGL default is true webglOptions.stencil = defaultValue(webglOptions.stencil, true); // WebGL default is false - var defaultToWebgl2 = false; - var requestWebgl2 = defaultToWebgl2 && (typeof WebGL2RenderingContext !== 'undefined'); + var requestWebgl2 = defaultValue(options.requestWebgl2, false) && (typeof WebGL2RenderingContext !== 'undefined'); var webgl2 = false; var glContext; @@ -303,33 +303,61 @@ define([ if (webgl2) { var that = this; - glCreateVertexArray = function () { return that._gl.createVertexArray(); }; - glBindVertexArray = function(vao) { that._gl.bindVertexArray(vao); }; - glDeleteVertexArray = function(vao) { that._gl.deleteVertexArray(vao); }; + glCreateVertexArray = function() { + return that._gl.createVertexArray(); + }; + glBindVertexArray = function(vao) { + that._gl.bindVertexArray(vao); + }; + glDeleteVertexArray = function(vao) { + that._gl.deleteVertexArray(vao); + }; - glDrawElementsInstanced = function(mode, count, type, offset, instanceCount) { gl.drawElementsInstanced(mode, count, type, offset, instanceCount); }; - glDrawArraysInstanced = function(mode, first, count, instanceCount) { gl.drawArraysInstanced(mode, first, count, instanceCount); }; - glVertexAttribDivisor = function(index, divisor) { gl.vertexAttribDivisor(index, divisor); }; + glDrawElementsInstanced = function(mode, count, type, offset, instanceCount) { + gl.drawElementsInstanced(mode, count, type, offset, instanceCount); + }; + glDrawArraysInstanced = function(mode, first, count, instanceCount) { + gl.drawArraysInstanced(mode, first, count, instanceCount); + }; + glVertexAttribDivisor = function(index, divisor) { + gl.vertexAttribDivisor(index, divisor); + }; - glDrawBuffers = function(buffers) { gl.drawBuffers(buffers); }; + glDrawBuffers = function(buffers) { + gl.drawBuffers(buffers); + }; } else { vertexArrayObject = getExtension(gl, ['OES_vertex_array_object']); if (defined(vertexArrayObject)) { - glCreateVertexArray = function() { return vertexArrayObject.createVertexArrayOES(); }; - glBindVertexArray = function(vertexArray) { vertexArrayObject.bindVertexArrayOES(vertexArray); }; - glDeleteVertexArray = function(vertexArray) { vertexArrayObject.deleteVertexArrayOES(vertexArray); }; + glCreateVertexArray = function() { + return vertexArrayObject.createVertexArrayOES(); + }; + glBindVertexArray = function(vertexArray) { + vertexArrayObject.bindVertexArrayOES(vertexArray); + }; + glDeleteVertexArray = function(vertexArray) { + vertexArrayObject.deleteVertexArrayOES(vertexArray); + }; } instancedArrays = getExtension(gl, ['ANGLE_instanced_arrays']); if (defined(instancedArrays)) { - glDrawElementsInstanced = function(mode, count, type, offset, instanceCount) { instancedArrays.drawElementsInstancedANGLE(mode, count, type, offset, instanceCount); }; - glDrawArraysInstanced = function(mode, first, count, instanceCount) { instancedArrays.drawArraysInstancedANGLE(mode, first, count, instanceCount); }; - glVertexAttribDivisor = function(index, divisor) { instancedArrays.vertexAttribDivisorANGLE(index, divisor); }; + glDrawElementsInstanced = function(mode, count, type, offset, instanceCount) { + instancedArrays.drawElementsInstancedANGLE(mode, count, type, offset, instanceCount); + }; + glDrawArraysInstanced = function(mode, first, count, instanceCount) { + instancedArrays.drawArraysInstancedANGLE(mode, first, count, instanceCount); + }; + glVertexAttribDivisor = function(index, divisor) { + instancedArrays.vertexAttribDivisorANGLE(index, divisor); + }; } drawBuffers = getExtension(gl, ['WEBGL_draw_buffers']); if (defined(drawBuffers)) { - glDrawBuffers = function(buffers) { drawBuffers.drawBuffersWEBGL(buffers); }; + glDrawBuffers = function(buffers) { + drawBuffers.drawBuffersWEBGL(buffers); + }; } } @@ -787,18 +815,18 @@ define([ var message; switch (status) { - case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - message = 'Framebuffer is not complete. Incomplete attachment: at least one attachment point with a renderbuffer or texture attached has its attached object no longer in existence or has an attached image with a width or height of zero, or the color attachment point has a non-color-renderable image attached, or the depth attachment point has a non-depth-renderable image attached, or the stencil attachment point has a non-stencil-renderable image attached. Color-renderable formats include GL_RGBA4, GL_RGB5_A1, and GL_RGB565. GL_DEPTH_COMPONENT16 is the only depth-renderable format. GL_STENCIL_INDEX8 is the only stencil-renderable format.'; - break; - case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS: - message = 'Framebuffer is not complete. Incomplete dimensions: not all attached images have the same width and height.'; - break; - case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: - message = 'Framebuffer is not complete. Missing attachment: no images are attached to the framebuffer.'; - break; - case gl.FRAMEBUFFER_UNSUPPORTED: - message = 'Framebuffer is not complete. Unsupported: the combination of internal formats of the attached images violates an implementation-dependent set of restrictions.'; - break; + case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + message = 'Framebuffer is not complete. Incomplete attachment: at least one attachment point with a renderbuffer or texture attached has its attached object no longer in existence or has an attached image with a width or height of zero, or the color attachment point has a non-color-renderable image attached, or the depth attachment point has a non-depth-renderable image attached, or the stencil attachment point has a non-stencil-renderable image attached. Color-renderable formats include GL_RGBA4, GL_RGB5_A1, and GL_RGB565. GL_DEPTH_COMPONENT16 is the only depth-renderable format. GL_STENCIL_INDEX8 is the only stencil-renderable format.'; + break; + case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS: + message = 'Framebuffer is not complete. Incomplete dimensions: not all attached images have the same width and height.'; + break; + case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + message = 'Framebuffer is not complete. Missing attachment: no images are attached to the framebuffer.'; + break; + case gl.FRAMEBUFFER_UNSUPPORTED: + message = 'Framebuffer is not complete. Unsupported: the combination of internal formats of the attached images violates an implementation-dependent set of restrictions.'; + break; } throw new DeveloperError(message); @@ -922,22 +950,12 @@ define([ throw new DeveloperError('drawCommand.primitiveType is required and must be valid.'); } - if (!defined(va)) { - throw new DeveloperError('drawCommand.vertexArray is required.'); - } - - if (offset < 0) { - throw new DeveloperError('drawCommand.offset must be greater than or equal to zero.'); - } - - if (count < 0) { - throw new DeveloperError('drawCommand.count must be greater than or equal to zero.'); + Check.defined('drawCommand.vertexArray', va); + Check.typeOf.number.greaterThanOrEquals('drawCommand.offset', offset, 0); + if (defined(count)) { + Check.typeOf.number.greaterThanOrEquals('drawCommand.count', count, 0); } - - if (instanceCount < 0) { - throw new DeveloperError('drawCommand.instanceCount must be greater than or equal to zero.'); - } - + Check.typeOf.number.greaterThanOrEquals('drawCommand.instanceCount', instanceCount, 0); if (instanceCount > 0 && !context.instancedArrays) { throw new DeveloperError('Instanced arrays extension is not supported'); } @@ -971,13 +989,8 @@ define([ Context.prototype.draw = function(drawCommand, passState) { //>>includeStart('debug', pragmas.debug); - if (!defined(drawCommand)) { - throw new DeveloperError('drawCommand is required.'); - } - - if (!defined(drawCommand._shaderProgram)) { - throw new DeveloperError('drawCommand.shaderProgram is required.'); - } + Check.defined('drawCommand', drawCommand); + Check.defined('drawCommand.shaderProgram', drawCommand._shaderProgram); //>>includeEnd('debug'); passState = defaultValue(passState, this._defaultPassState); @@ -1021,13 +1034,8 @@ define([ var framebuffer = readState.framebuffer; //>>includeStart('debug', pragmas.debug); - if (width <= 0) { - throw new DeveloperError('readState.width must be greater than zero.'); - } - - if (height <= 0) { - throw new DeveloperError('readState.height must be greater than zero.'); - } + Check.typeOf.number.greaterThan('readState.width', width, 0); + Check.typeOf.number.greaterThan('readState.height', height, 0); //>>includeEnd('debug'); var pixels = new Uint8Array(4 * width * height); @@ -1055,10 +1063,10 @@ define([ componentDatatype : ComponentDatatype.FLOAT, componentsPerAttribute : 2, values : [ - -1.0, -1.0, + -1.0, -1.0, 1.0, -1.0, - 1.0, 1.0, - -1.0, 1.0 + 1.0, 1.0, + -1.0, 1.0 ] }), @@ -1129,9 +1137,7 @@ define([ */ Context.prototype.getObjectByPickColor = function(pickColor) { //>>includeStart('debug', pragmas.debug); - if (!defined(pickColor)) { - throw new DeveloperError('pickColor is required.'); - } + Check.defined('pickColor', pickColor); //>>includeEnd('debug'); return this._pickObjects[pickColor.toRgba()]; @@ -1180,9 +1186,7 @@ define([ */ Context.prototype.createPickId = function(object) { //>>includeStart('debug', pragmas.debug); - if (!defined(object)) { - throw new DeveloperError('object is required.'); - } + Check.defined('object', object); //>>includeEnd('debug'); // the increment and assignment have to be separate statements to diff --git a/Source/Renderer/CubeMap.js b/Source/Renderer/CubeMap.js index b95bf56c009f..e08eccd1c718 100644 --- a/Source/Renderer/CubeMap.js +++ b/Source/Renderer/CubeMap.js @@ -1,4 +1,5 @@ define([ + '../Core/Check', '../Core/defaultValue', '../Core/defined', '../Core/defineProperties', @@ -14,6 +15,7 @@ define([ './TextureMagnificationFilter', './TextureMinificationFilter' ], function( + Check, defaultValue, defined, defineProperties, @@ -35,9 +37,7 @@ define([ options = defaultValue(options, defaultValue.EMPTY_OBJECT); //>>includeStart('debug', pragmas.debug); - if (!defined(options.context)) { - throw new DeveloperError('options.context is required.'); - } + Check.defined('options.context', options.context); //>>includeEnd('debug'); var context = options.context; diff --git a/Source/Renderer/CubeMapFace.js b/Source/Renderer/CubeMapFace.js index 1695c9a09776..83e9a165cd73 100644 --- a/Source/Renderer/CubeMapFace.js +++ b/Source/Renderer/CubeMapFace.js @@ -1,9 +1,11 @@ define([ + '../Core/Check', '../Core/defaultValue', '../Core/defineProperties', '../Core/DeveloperError', './PixelDatatype' ], function( + Check, defaultValue, defineProperties, DeveloperError, @@ -74,15 +76,9 @@ define([ yOffset = defaultValue(yOffset, 0); //>>includeStart('debug', pragmas.debug); - if (!source) { - throw new DeveloperError('source is required.'); - } - if (xOffset < 0) { - throw new DeveloperError('xOffset must be greater than or equal to zero.'); - } - if (yOffset < 0) { - throw new DeveloperError('yOffset must be greater than or equal to zero.'); - } + Check.defined('source', source); + Check.typeOf.number.greaterThanOrEquals('xOffset', xOffset, 0); + Check.typeOf.number.greaterThanOrEquals('yOffset', yOffset, 0); if (xOffset + source.width > this._size) { throw new DeveloperError('xOffset + source.width must be less than or equal to width.'); } @@ -142,18 +138,10 @@ define([ height = defaultValue(height, this._size); //>>includeStart('debug', pragmas.debug); - if (xOffset < 0) { - throw new DeveloperError('xOffset must be greater than or equal to zero.'); - } - if (yOffset < 0) { - throw new DeveloperError('yOffset must be greater than or equal to zero.'); - } - 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.'); - } + Check.typeOf.number.greaterThanOrEquals('xOffset', xOffset, 0); + Check.typeOf.number.greaterThanOrEquals('yOffset', yOffset, 0); + Check.typeOf.number.greaterThanOrEquals('framebufferXOffset', framebufferXOffset, 0); + Check.typeOf.number.greaterThanOrEquals('framebufferYOffset', framebufferYOffset, 0); if (xOffset + width > this._size) { throw new DeveloperError('xOffset + source.width must be less than or equal to width.'); } diff --git a/Source/Renderer/Framebuffer.js b/Source/Renderer/Framebuffer.js index a98a6aa376ec..20f54665c1ce 100644 --- a/Source/Renderer/Framebuffer.js +++ b/Source/Renderer/Framebuffer.js @@ -1,4 +1,5 @@ define([ + '../Core/Check', '../Core/defaultValue', '../Core/defined', '../Core/defineProperties', @@ -7,6 +8,7 @@ define([ '../Core/PixelFormat', './ContextLimits' ], function( + Check, defaultValue, defined, defineProperties, @@ -71,9 +73,7 @@ define([ options = defaultValue(options, defaultValue.EMPTY_OBJECT); //>>includeStart('debug', pragmas.debug); - if (!defined(options.context)) { - throw new DeveloperError('options.context is required.'); - } + Check.defined('options.context', options.context); //>>includeEnd('debug'); var gl = options.context._gl; diff --git a/Source/Renderer/RenderState.js b/Source/Renderer/RenderState.js index 07ab7633fe12..774f7a04871f 100644 --- a/Source/Renderer/RenderState.js +++ b/Source/Renderer/RenderState.js @@ -6,7 +6,8 @@ define([ '../Core/DeveloperError', '../Core/WebGLConstants', '../Core/WindingOrder', - './ContextLimits' + './ContextLimits', + './freezeRenderState' ], function( BoundingRectangle, Color, @@ -15,7 +16,8 @@ define([ DeveloperError, WebGLConstants, WindingOrder, - ContextLimits) { + ContextLimits, + freezeRenderState) { 'use strict'; function validateBlendEquation(blendEquation) { @@ -61,7 +63,7 @@ define([ (depthFunction === WebGLConstants.ALWAYS)); } - function validateStencilFunction (stencilFunction) { + function validateStencilFunction(stencilFunction) { return ((stencilFunction === WebGLConstants.NEVER) || (stencilFunction === WebGLConstants.LESS) || (stencilFunction === WebGLConstants.EQUAL) || @@ -175,8 +177,8 @@ define([ //>>includeStart('debug', pragmas.debug); if ((this.lineWidth < ContextLimits.minimumAliasedLineWidth) || - (this.lineWidth > ContextLimits.maximumAliasedLineWidth)) { - throw new DeveloperError('renderState.lineWidth is out of range. Check minimumAliasedLineWidth and maximumAliasedLineWidth.'); + (this.lineWidth > ContextLimits.maximumAliasedLineWidth)) { + throw new DeveloperError('renderState.lineWidth is out of range. Check minimumAliasedLineWidth and maximumAliasedLineWidth.'); } if (!WindingOrder.validate(this.frontFace)) { throw new DeveloperError('Invalid renderState.frontFace.'); @@ -411,7 +413,9 @@ define([ cachedState = renderStateCache[fullKey]; if (!defined(cachedState)) { states.id = nextRenderStateId++; - + //>>includeStart('debug', pragmas.debug); + states = freezeRenderState(states); + //>>includeEnd('debug'); cachedState = { referenceCount : 0, state : states @@ -622,6 +626,7 @@ define([ } var scratchViewport = new BoundingRectangle(); + function applyViewport(gl, renderState, passState) { var viewport = defaultValue(renderState.viewport, passState.viewport); if (!defined(viewport)) { @@ -667,8 +672,8 @@ define([ } if ((previousState.polygonOffset.enabled !== nextState.polygonOffset.enabled) || - (previousState.polygonOffset.factor !== nextState.polygonOffset.factor) || - (previousState.polygonOffset.units !== nextState.polygonOffset.units)) { + (previousState.polygonOffset.factor !== nextState.polygonOffset.factor) || + (previousState.polygonOffset.units !== nextState.polygonOffset.units)) { funcs.push(applyPolygonOffset); } @@ -681,9 +686,9 @@ define([ } if ((previousState.colorMask.red !== nextState.colorMask.red) || - (previousState.colorMask.green !== nextState.colorMask.green) || - (previousState.colorMask.blue !== nextState.colorMask.blue) || - (previousState.colorMask.alpha !== nextState.colorMask.alpha)) { + (previousState.colorMask.green !== nextState.colorMask.green) || + (previousState.colorMask.blue !== nextState.colorMask.blue) || + (previousState.colorMask.alpha !== nextState.colorMask.alpha)) { funcs.push(applyColorMask); } @@ -696,21 +701,21 @@ define([ } if ((previousState.stencilTest.enabled !== nextState.stencilTest.enabled) || - (previousState.stencilTest.frontFunction !== nextState.stencilTest.frontFunction) || - (previousState.stencilTest.backFunction !== nextState.stencilTest.backFunction) || - (previousState.stencilTest.reference !== nextState.stencilTest.reference) || - (previousState.stencilTest.mask !== nextState.stencilTest.mask) || - (previousState.stencilTest.frontOperation.fail !== nextState.stencilTest.frontOperation.fail) || - (previousState.stencilTest.frontOperation.zFail !== nextState.stencilTest.frontOperation.zFail) || - (previousState.stencilTest.backOperation.fail !== nextState.stencilTest.backOperation.fail) || - (previousState.stencilTest.backOperation.zFail !== nextState.stencilTest.backOperation.zFail) || - (previousState.stencilTest.backOperation.zPass !== nextState.stencilTest.backOperation.zPass)) { + (previousState.stencilTest.frontFunction !== nextState.stencilTest.frontFunction) || + (previousState.stencilTest.backFunction !== nextState.stencilTest.backFunction) || + (previousState.stencilTest.reference !== nextState.stencilTest.reference) || + (previousState.stencilTest.mask !== nextState.stencilTest.mask) || + (previousState.stencilTest.frontOperation.fail !== nextState.stencilTest.frontOperation.fail) || + (previousState.stencilTest.frontOperation.zFail !== nextState.stencilTest.frontOperation.zFail) || + (previousState.stencilTest.backOperation.fail !== nextState.stencilTest.backOperation.fail) || + (previousState.stencilTest.backOperation.zFail !== nextState.stencilTest.backOperation.zFail) || + (previousState.stencilTest.backOperation.zPass !== nextState.stencilTest.backOperation.zPass)) { funcs.push(applyStencilTest); } if ((previousState.sampleCoverage.enabled !== nextState.sampleCoverage.enabled) || - (previousState.sampleCoverage.value !== nextState.sampleCoverage.value) || - (previousState.sampleCoverage.invert !== nextState.sampleCoverage.invert)) { + (previousState.sampleCoverage.value !== nextState.sampleCoverage.value) || + (previousState.sampleCoverage.invert !== nextState.sampleCoverage.invert)) { funcs.push(applySampleCoverage); } @@ -749,7 +754,7 @@ define([ var previousBlendingEnabled = (defined(previousPassState.blendingEnabled)) ? previousPassState.blendingEnabled : previousRenderState.blending.enabled; var blendingEnabled = (defined(passState.blendingEnabled)) ? passState.blendingEnabled : renderState.blending.enabled; if ((previousBlendingEnabled !== blendingEnabled) || - (blendingEnabled && (previousRenderState.blending !== renderState.blending))) { + (blendingEnabled && (previousRenderState.blending !== renderState.blending))) { applyBlending(gl, renderState, passState); } diff --git a/Source/Renderer/Renderbuffer.js b/Source/Renderer/Renderbuffer.js index c36c80e0bc84..8da442cbd5bf 100644 --- a/Source/Renderer/Renderbuffer.js +++ b/Source/Renderer/Renderbuffer.js @@ -1,4 +1,5 @@ define([ + '../Core/Check', '../Core/defaultValue', '../Core/defined', '../Core/defineProperties', @@ -7,6 +8,7 @@ define([ './ContextLimits', './RenderbufferFormat' ], function( + Check, defaultValue, defined, defineProperties, @@ -23,9 +25,7 @@ define([ options = defaultValue(options, defaultValue.EMPTY_OBJECT); //>>includeStart('debug', pragmas.debug); - if (!defined(options.context)) { - throw new DeveloperError('options.context is required.'); - } + Check.defined('options.context', options.context); //>>includeEnd('debug'); var context = options.context; @@ -41,17 +41,13 @@ define([ throw new DeveloperError('Invalid format.'); } - if (width <= 0) { - throw new DeveloperError('Width must be greater than zero.'); - } + Check.typeOf.number.greaterThan('width', width, 0); if (width > maximumRenderbufferSize) { throw new DeveloperError('Width must be less than or equal to the maximum renderbuffer size (' + maximumRenderbufferSize + '). Check maximumRenderbufferSize.'); } - if (height <= 0) { - throw new DeveloperError('Height must be greater than zero.'); - } + Check.typeOf.number.greaterThan('height', height, 0); if (height > maximumRenderbufferSize) { throw new DeveloperError('Height must be less than or equal to the maximum renderbuffer size (' + maximumRenderbufferSize + '). Check maximumRenderbufferSize.'); diff --git a/Source/Renderer/Sampler.js b/Source/Renderer/Sampler.js index c11922f91a52..d074b9a0d38d 100644 --- a/Source/Renderer/Sampler.js +++ b/Source/Renderer/Sampler.js @@ -1,4 +1,5 @@ define([ + '../Core/Check', '../Core/defaultValue', '../Core/defined', '../Core/defineProperties', @@ -7,6 +8,7 @@ define([ './TextureMinificationFilter', './TextureWrap' ], function( + Check, defaultValue, defined, defineProperties, @@ -45,9 +47,7 @@ define([ throw new DeveloperError('Invalid sampler.magnificationFilter.'); } - if (maximumAnisotropy < 1.0) { - throw new DeveloperError('sampler.maximumAnisotropy must be greater than or equal to one.'); - } + Check.typeOf.number.greaterThanOrEquals('maximumAnisotropy', maximumAnisotropy, 1.0); //>>includeEnd('debug'); this._wrapS = wrapS; diff --git a/Source/Renderer/ShaderProgram.js b/Source/Renderer/ShaderProgram.js index e839d4cd4e0f..7a79505965e8 100644 --- a/Source/Renderer/ShaderProgram.js +++ b/Source/Renderer/ShaderProgram.js @@ -1,4 +1,5 @@ define([ + '../Core/Check', '../Core/defaultValue', '../Core/defined', '../Core/defineProperties', @@ -10,6 +11,7 @@ define([ './createUniform', './createUniformArray' ], function( + Check, defaultValue, defined, defineProperties, @@ -65,9 +67,7 @@ define([ options = defaultValue(options, defaultValue.EMPTY_OBJECT); //>>includeStart('debug', pragmas.debug); - if (!defined(options.context)) { - throw new DeveloperError('options.context is required.'); - } + Check.defined('options.context', options.context); //>>includeEnd('debug'); return options.context.shaderCache.getShaderProgram(options); @@ -77,9 +77,7 @@ define([ options = defaultValue(options, defaultValue.EMPTY_OBJECT); //>>includeStart('debug', pragmas.debug); - if (!defined(options.context)) { - throw new DeveloperError('options.context is required.'); - } + Check.defined('options.context', options.context); //>>includeEnd('debug'); return options.context.shaderCache.replaceShaderProgram(options); diff --git a/Source/Renderer/Texture.js b/Source/Renderer/Texture.js index 34d71a6d56a6..2ba7284e05c7 100644 --- a/Source/Renderer/Texture.js +++ b/Source/Renderer/Texture.js @@ -1,5 +1,7 @@ define([ '../Core/Cartesian2', + '../Core/Check', + '../Core/createGuid', '../Core/defaultValue', '../Core/defined', '../Core/defineProperties', @@ -16,6 +18,8 @@ define([ './TextureMinificationFilter' ], function( Cartesian2, + Check, + createGuid, defaultValue, defined, defineProperties, @@ -36,9 +40,7 @@ define([ options = defaultValue(options, defaultValue.EMPTY_OBJECT); //>>includeStart('debug', pragmas.debug); - if (!defined(options.context)) { - throw new DeveloperError('options.context is required.'); - } + Check.defined('options.context', options.context); //>>includeEnd('debug'); var context = options.context; @@ -95,17 +97,13 @@ define([ throw new DeveloperError('options requires a source field to create an initialized texture or width and height fields to create a blank texture.'); } - if (width <= 0) { - throw new DeveloperError('Width must be greater than zero.'); - } + Check.typeOf.number.greaterThan('width', width, 0); if (width > ContextLimits.maximumTextureSize) { throw new DeveloperError('Width must be less than or equal to the maximum texture size (' + ContextLimits.maximumTextureSize + '). Check maximumTextureSize.'); } - if (height <= 0) { - throw new DeveloperError('Height must be greater than zero.'); - } + Check.typeOf.number.greaterThan('height', height, 0); if (height > ContextLimits.maximumTextureSize) { throw new DeveloperError('Height must be less than or equal to the maximum texture size (' + ContextLimits.maximumTextureSize + '). Check maximumTextureSize.'); @@ -212,6 +210,7 @@ define([ sizeInBytes = PixelFormat.textureSizeInBytes(pixelFormat, pixelDatatype, width, height); } + this._id = createGuid(); this._context = context; this._textureFilterAnisotropic = context._textureFilterAnisotropic; this._textureTarget = textureTarget; @@ -267,9 +266,7 @@ define([ options = defaultValue(options, defaultValue.EMPTY_OBJECT); //>>includeStart('debug', pragmas.debug); - if (!defined(options.context)) { - throw new DeveloperError('options.context is required.'); - } + Check.defined('options.context', options.context); //>>includeEnd('debug'); var context = options.context; @@ -283,21 +280,15 @@ define([ var framebuffer = options.framebuffer; //>>includeStart('debug', pragmas.debug); - if (!defined(options.context)) { - throw new DeveloperError('context is required.'); - } if (!PixelFormat.validate(pixelFormat)) { throw new DeveloperError('Invalid pixelFormat.'); } 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.'); - } + Check.defined('options.context', options.context); + Check.typeOf.number.greaterThanOrEquals('framebufferXOffset', framebufferXOffset, 0); + Check.typeOf.number.greaterThanOrEquals('framebufferYOffset', framebufferYOffset, 0); if (framebufferXOffset + width > gl.drawingBufferWidth) { throw new DeveloperError('framebufferXOffset + width must be less than or equal to drawingBufferWidth'); } @@ -324,6 +315,18 @@ define([ }; defineProperties(Texture.prototype, { + /** + * A unique id for the texture + * @memberof Texture.prototype + * @type {String} + * @readonly + * @private + */ + id : { + get : function() { + return this._id; + } + }, /** * The sampler to use when sampling this texture. * Create a sampler by calling {@link Sampler}. If this @@ -449,27 +452,17 @@ define([ yOffset = defaultValue(yOffset, 0); //>>includeStart('debug', pragmas.debug); - if (!defined(source)) { - throw new DeveloperError('source is required.'); - } + Check.defined('source', source); 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.'); - } - if (yOffset < 0) { - throw new DeveloperError('yOffset must be greater than or equal to zero.'); - } - if (xOffset + source.width > this._width) { - throw new DeveloperError('xOffset + source.width must be less than or equal to width.'); - } - if (yOffset + source.height > this._height) { - throw new DeveloperError('yOffset + source.height must be less than or equal to height.'); - } + Check.typeOf.number.greaterThanOrEquals('xOffset', xOffset, 0); + Check.typeOf.number.greaterThanOrEquals('yOffset', yOffset, 0); + Check.typeOf.number.lessThanOrEquals('xOffset + source.width', xOffset + source.width, this._width); + Check.typeOf.number.lessThanOrEquals('yOffset + source.height', yOffset + source.height, this._height); //>>includeEnd('debug'); var gl = this._context._gl; @@ -527,24 +520,13 @@ define([ 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.'); - } - if (yOffset < 0) { - throw new DeveloperError('yOffset must be greater than or equal to zero.'); - } - 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 (xOffset + width > this._width) { - throw new DeveloperError('xOffset + width must be less than or equal to width.'); - } - if (yOffset + height > this._height) { - throw new DeveloperError('yOffset + height must be less than or equal to height.'); - } + + Check.typeOf.number.greaterThanOrEquals('xOffset', xOffset, 0); + Check.typeOf.number.greaterThanOrEquals('yOffset', yOffset, 0); + Check.typeOf.number.greaterThanOrEquals('framebufferXOffset', framebufferXOffset, 0); + Check.typeOf.number.greaterThanOrEquals('framebufferYOffset', framebufferYOffset, 0); + Check.typeOf.number.lessThanOrEquals('xOffset + width', xOffset + width, this._width); + Check.typeOf.number.lessThanOrEquals('yOffset + height', yOffset + height, this._height); //>>includeEnd('debug'); var gl = this._context._gl; diff --git a/Source/Renderer/VertexArray.js b/Source/Renderer/VertexArray.js index 535f57e76307..5807c94cb71c 100644 --- a/Source/Renderer/VertexArray.js +++ b/Source/Renderer/VertexArray.js @@ -1,4 +1,5 @@ define([ + '../Core/Check', '../Core/ComponentDatatype', '../Core/defaultValue', '../Core/defined', @@ -13,6 +14,7 @@ define([ './BufferUsage', './ContextLimits' ], function( + Check, ComponentDatatype, defaultValue, defined, @@ -266,13 +268,8 @@ define([ options = defaultValue(options, defaultValue.EMPTY_OBJECT); //>>includeStart('debug', pragmas.debug); - if (!defined(options.context)) { - throw new DeveloperError('options.context is required.'); - } - - if (!defined(options.attributes)) { - throw new DeveloperError('options.attributes is required.'); - } + Check.defined('options.context', options.context); + Check.defined('options.attributes', options.attributes); //>>includeEnd('debug'); var context = options.context; @@ -528,9 +525,7 @@ define([ options = defaultValue(options, defaultValue.EMPTY_OBJECT); //>>includeStart('debug', pragmas.debug); - if (!defined(options.context)) { - throw new DeveloperError('options.context is required.'); - } + Check.defined('options.context', options.context); //>>includeEnd('debug'); var context = options.context; @@ -669,9 +664,7 @@ define([ */ VertexArray.prototype.getAttribute = function(index) { //>>includeStart('debug', pragmas.debug); - if (!defined(index)) { - throw new DeveloperError('index is required.'); - } + Check.defined('index', index); //>>includeEnd('debug'); return this._attributes[index]; diff --git a/Source/Renderer/VertexArrayFacade.js b/Source/Renderer/VertexArrayFacade.js index 82c3d0a5ba0b..4a0c7efaa0f8 100644 --- a/Source/Renderer/VertexArrayFacade.js +++ b/Source/Renderer/VertexArrayFacade.js @@ -1,4 +1,5 @@ define([ + '../Core/Check', '../Core/ComponentDatatype', '../Core/defaultValue', '../Core/defined', @@ -9,6 +10,7 @@ define([ './BufferUsage', './VertexArray' ], function( + Check, ComponentDatatype, defaultValue, defined, @@ -25,9 +27,7 @@ define([ */ function VertexArrayFacade(context, attributes, sizeInVertices, instanced) { //>>includeStart('debug', pragmas.debug); - if (!context) { - throw new DeveloperError('context is required.'); - } + Check.defined('context', context); if (!attributes || (attributes.length === 0)) { throw new DeveloperError('At least one attribute is required.'); } diff --git a/Source/Renderer/freezeRenderState.js b/Source/Renderer/freezeRenderState.js new file mode 100644 index 000000000000..bc568ee4ef7f --- /dev/null +++ b/Source/Renderer/freezeRenderState.js @@ -0,0 +1,37 @@ +/*global define*/ +define([ + '../Core/defined', + '../Core/freezeObject' + ], function( + defined, + freezeObject) { + 'use strict'; + + /** + * Returns frozen renderState as well as all of the object literal properties. This function is deep object freeze + * function ignoring properties named "_applyFunctions". + * + * @private + * + * @param {Object} renderState + * @returns {Object} Returns frozen renderState. + * + */ + function freezeRenderState(renderState) { + if (typeof renderState !== 'object' || renderState === null) { + return renderState; + } + + var propName; + var propNames = Object.keys(renderState); + + for (var i = 0; i < propNames.length; i++) { + propName = propNames[i]; + if (renderState.hasOwnProperty(propName) && propName !== '_applyFunctions') { + renderState[propName] = freezeRenderState(renderState[propName]); + } + } + return freezeObject(renderState); + } + return freezeRenderState; +}); diff --git a/Source/Renderer/loadCubeMap.js b/Source/Renderer/loadCubeMap.js index e3b28341b8db..723009863b6e 100644 --- a/Source/Renderer/loadCubeMap.js +++ b/Source/Renderer/loadCubeMap.js @@ -1,10 +1,12 @@ define([ + '../Core/Check', '../Core/defined', '../Core/DeveloperError', '../Core/loadImage', '../ThirdParty/when', './CubeMap' ], function( + Check, defined, DeveloperError, loadImage, @@ -50,9 +52,7 @@ define([ */ function loadCubeMap(context, urls, allowCrossOrigin) { //>>includeStart('debug', pragmas.debug); - if (!defined(context)) { - throw new DeveloperError('context is required.'); - } + Check.defined('context', context); if ((!defined(urls)) || (!defined(urls.positiveX)) || (!defined(urls.negativeX)) || diff --git a/Source/Scene/GlobeSurfaceTileProvider.js b/Source/Scene/GlobeSurfaceTileProvider.js index 00c047e2b83d..801376f39439 100644 --- a/Source/Scene/GlobeSurfaceTileProvider.js +++ b/Source/Scene/GlobeSurfaceTileProvider.js @@ -504,7 +504,7 @@ define([ } var ortho3D = frameState.mode === SceneMode.SCENE3D && frameState.camera.frustum instanceof OrthographicFrustum; - if (frameState.mode === SceneMode.SCENE3D && !ortho3D) { + if (frameState.mode === SceneMode.SCENE3D && !ortho3D && defined(occluders)) { var occludeePointInScaledSpace = surfaceTile.occludeePointInScaledSpace; if (!defined(occludeePointInScaledSpace)) { return intersection; diff --git a/Source/Scene/PolylineCollection.js b/Source/Scene/PolylineCollection.js index c8149202879a..bcc898aae734 100644 --- a/Source/Scene/PolylineCollection.js +++ b/Source/Scene/PolylineCollection.js @@ -26,6 +26,7 @@ define([ '../Renderer/RenderState', '../Renderer/ShaderProgram', '../Renderer/ShaderSource', + '../Renderer/Texture', '../Renderer/VertexArray', '../Shaders/PolylineCommon', '../Shaders/PolylineFS', @@ -63,6 +64,7 @@ define([ RenderState, ShaderProgram, ShaderSource, + Texture, VertexArray, PolylineCommon, PolylineFS, @@ -1010,6 +1012,14 @@ define([ } } + function replacer(key, value) { + if (value instanceof Texture) { + return value.id; + } + + return value; + } + var scratchUniformArray = []; function createMaterialId(material) { var uniforms = Material._uniformList[material.type]; @@ -1024,7 +1034,7 @@ define([ index += 2; } - return material.type + ':' + JSON.stringify(scratchUniformArray); + return material.type + ':' + JSON.stringify(scratchUniformArray, replacer); } function sortPolylinesIntoBuckets(collection) { diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js index 7b990cb5697e..fe5444d669aa 100644 --- a/Source/Scene/QuadtreePrimitive.js +++ b/Source/Scene/QuadtreePrimitive.js @@ -427,12 +427,12 @@ define([ primitive._occluders.ellipsoid.cameraPosition = frameState.camera.positionWC; - var tileProvider = primitive._tileProvider; - var occluders = primitive._occluders; - var tile; var levelZeroTiles = primitive._levelZeroTiles; + var tileProvider = primitive._tileProvider; + var occluders = levelZeroTiles.length > 1 ? primitive._occluders : undefined; + // Sort the level zero tiles by the distance from the center to the camera. // The level zero tiles aren't necessarily a nice neat quad, so we can use the // quadtree ordering we use elsewhere in the tree diff --git a/Source/Scene/Scene.js b/Source/Scene/Scene.js index f93620ea04bf..6329d5364404 100644 --- a/Source/Scene/Scene.js +++ b/Source/Scene/Scene.js @@ -653,6 +653,18 @@ define([ this._actualInvertClassificationColor = Color.clone(this._invertClassificationColor); this._invertClassification = new InvertClassification(); + /** + * The focal length for use when with cardboard or WebVR. + * @type {Number} + */ + this.focalLength = undefined; + + /** + * The eye separation distance in meters for use with cardboard or WebVR. + * @type {Number} + */ + this.eyeSeparation = undefined; + this._brdfLutGenerator = new BrdfLutGenerator(); this._terrainExaggeration = defaultValue(options.terrainExaggeration, 1.0); @@ -2282,8 +2294,8 @@ define([ var savedCamera = Camera.clone(camera, scene._cameraVR); var near = camera.frustum.near; - var fo = near * 5.0; - var eyeSeparation = fo / 30.0; + var fo = near * defaultValue(scene.focalLength, 5.0); + var eyeSeparation = defaultValue(scene.eyeSeparation, fo / 30.0); var eyeTranslation = Cartesian3.multiplyByScalar(savedCamera.right, eyeSeparation * 0.5, scratchEyeTranslation); camera.frustum.aspectRatio = viewport.width / viewport.height; diff --git a/Source/Scene/ShadowMap.js b/Source/Scene/ShadowMap.js index 152676ce2643..cae5d0f5210a 100644 --- a/Source/Scene/ShadowMap.js +++ b/Source/Scene/ShadowMap.js @@ -1512,6 +1512,7 @@ define([ var cullEnabled = command.renderState.cull.enabled; if (!cullEnabled) { castRenderState = clone(castRenderState, false); + castRenderState.cull = clone(castRenderState.cull, false); castRenderState.cull.enabled = false; castRenderState = RenderState.fromCache(castRenderState); } diff --git a/Source/Scene/UrlTemplateImageryProvider.js b/Source/Scene/UrlTemplateImageryProvider.js index 7187182f0700..94529176764a 100644 --- a/Source/Scene/UrlTemplateImageryProvider.js +++ b/Source/Scene/UrlTemplateImageryProvider.js @@ -44,6 +44,38 @@ define([ ImageryProvider) { 'use strict'; + var tags = { + '{x}': xTag, + '{y}': yTag, + '{z}': zTag, + '{s}': sTag, + '{reverseX}': reverseXTag, + '{reverseY}': reverseYTag, + '{reverseZ}': reverseZTag, + '{westDegrees}': westDegreesTag, + '{southDegrees}': southDegreesTag, + '{eastDegrees}': eastDegreesTag, + '{northDegrees}': northDegreesTag, + '{westProjected}': westProjectedTag, + '{southProjected}': southProjectedTag, + '{eastProjected}': eastProjectedTag, + '{northProjected}': northProjectedTag, + '{width}': widthTag, + '{height}': heightTag + }; + + var pickFeaturesTags = combine(tags, { + '{i}' : iTag, + '{j}' : jTag, + '{reverseI}' : reverseITag, + '{reverseJ}' : reverseJTag, + '{longitudeDegrees}' : longitudeDegreesTag, + '{latitudeDegrees}' : latitudeDegreesTag, + '{longitudeProjected}' : longitudeProjectedTag, + '{latitudeProjected}' : latitudeProjectedTag, + '{format}' : formatTag + }); + /** * Provides imagery by requesting tiles using a specified URL template. * @@ -132,6 +164,7 @@ define([ * source does not support picking features or if you don't want this provider's features to be pickable. Note * that this can be dynamically overridden by modifying the {@link UriTemplateImageryProvider#enablePickFeatures} * property. + * @param {Object} [options.customTags] Allow to replace custom keywords in the URL template. The object must have strings as keys and functions as values. * * * @example @@ -157,6 +190,15 @@ define([ * 'width=256&height=256', * rectangle : Cesium.Rectangle.fromDegrees(96.799393, -43.598214999057824, 153.63925700000001, -9.2159219997013) * }); + * // Using custom tags in your template url. + * var custom = new Cesium.UrlTemplateImageryProvider({ + * url : 'https://yoururl/{Time}/{z}/{y}/{x}.png', + * customTags : { + * Time: function(imageryProvider, x, y , level) { + * return '20171231' + * } + * } + * }); * * @see ArcGisMapServerImageryProvider * @see BingMapsImageryProvider @@ -568,8 +610,33 @@ define([ } that._credit = credit; - that._urlParts = urlTemplateToParts(that._url, tags); //eslint-disable-line no-use-before-define - that._pickFeaturesUrlParts = urlTemplateToParts(that._pickFeaturesUrl, pickFeaturesTags); //eslint-disable-line no-use-before-define + var tag; + var allTags = {}; + var allPickFeaturesTags = {}; + for (tag in tags) { + if (tags.hasOwnProperty(tag)) { + allTags[tag] = tags[tag]; + } + } + for (tag in pickFeaturesTags) { + if (pickFeaturesTags.hasOwnProperty(tag)) { + allPickFeaturesTags[tag] = pickFeaturesTags[tag]; + } + } + + var customTags = properties.customTags; + if (defined(customTags)) { + for (tag in customTags) { + if (customTags.hasOwnProperty(tag)) { + var targetTag = '{' + tag + '}'; + allTags[targetTag] = customTags[tag]; + allPickFeaturesTags[targetTag] = customTags[tag]; + } + } + } + + that._urlParts = urlTemplateToParts(that._url, allTags); + that._pickFeaturesUrlParts = urlTemplateToParts(that._pickFeaturesUrl, allPickFeaturesTags); return true; }); }; @@ -963,37 +1030,5 @@ define([ return format; } - var tags = { - '{x}': xTag, - '{y}': yTag, - '{z}': zTag, - '{s}': sTag, - '{reverseX}': reverseXTag, - '{reverseY}': reverseYTag, - '{reverseZ}': reverseZTag, - '{westDegrees}': westDegreesTag, - '{southDegrees}': southDegreesTag, - '{eastDegrees}': eastDegreesTag, - '{northDegrees}': northDegreesTag, - '{westProjected}': westProjectedTag, - '{southProjected}': southProjectedTag, - '{eastProjected}': eastProjectedTag, - '{northProjected}': northProjectedTag, - '{width}': widthTag, - '{height}': heightTag - }; - - var pickFeaturesTags = combine(tags, { - '{i}' : iTag, - '{j}' : jTag, - '{reverseI}' : reverseITag, - '{reverseJ}' : reverseJTag, - '{longitudeDegrees}' : longitudeDegreesTag, - '{latitudeDegrees}' : latitudeDegreesTag, - '{longitudeProjected}' : longitudeProjectedTag, - '{latitudeProjected}' : latitudeProjectedTag, - '{format}' : formatTag - }); - return UrlTemplateImageryProvider; }); diff --git a/Specs/Core/OrientedBoundingBoxSpec.js b/Specs/Core/OrientedBoundingBoxSpec.js index 4341fd3fe346..242890fe98bf 100644 --- a/Specs/Core/OrientedBoundingBoxSpec.js +++ b/Specs/Core/OrientedBoundingBoxSpec.js @@ -172,14 +172,12 @@ defineSuite([ it('fromRectangle throws with invalid rectangles', function() { var ellipsoid = Ellipsoid.UNIT_SPHERE; - expect(function() { return OrientedBoundingBox.fromRectangle(new Rectangle(1.0, -1.0, -1.0, 1.0), 0.0, 0.0, ellipsoid); }).toThrowDeveloperError(); expect(function() { return OrientedBoundingBox.fromRectangle(new Rectangle(-1.0, 1.0, 1.0, -1.0), 0.0, 0.0, ellipsoid); }).toThrowDeveloperError(); - expect(function() { return OrientedBoundingBox.fromRectangle(new Rectangle(-1.0, 1.0, -2.0, 2.0), 0.0, 0.0, ellipsoid); }).toThrowDeveloperError(); expect(function() { return OrientedBoundingBox.fromRectangle(new Rectangle(-2.0, 2.0, -1.0, 1.0), 0.0, 0.0, ellipsoid); }).toThrowDeveloperError(); - expect(function() { return OrientedBoundingBox.fromRectangle(new Rectangle(-2.0, -2.0, 2.0, 1.0), 0.0, 0.0, ellipsoid); }).toThrowDeveloperError(); + expect(function() { return OrientedBoundingBox.fromRectangle(new Rectangle(-4.0, -2.0, 4.0, 1.0), 0.0, 0.0, ellipsoid); }).toThrowDeveloperError(); expect(function() { return OrientedBoundingBox.fromRectangle(new Rectangle(-2.0, -2.0, 1.0, 2.0), 0.0, 0.0, ellipsoid); }).toThrowDeveloperError(); expect(function() { return OrientedBoundingBox.fromRectangle(new Rectangle(-1.0, -2.0, 2.0, 2.0), 0.0, 0.0, ellipsoid); }).toThrowDeveloperError(); - expect(function() { return OrientedBoundingBox.fromRectangle(new Rectangle(-2.0, -1.0, 2.0, 2.0), 0.0, 0.0, ellipsoid); }).toThrowDeveloperError(); + expect(function() { return OrientedBoundingBox.fromRectangle(new Rectangle(-4.0, -1.0, 4.0, 2.0), 0.0, 0.0, ellipsoid); }).toThrowDeveloperError(); }); it('fromRectangle throws with non-revolution ellipsoids', function() { diff --git a/Specs/Renderer/BufferSpec.js b/Specs/Renderer/BufferSpec.js index d957fa19a039..4c49dc81a713 100644 --- a/Specs/Renderer/BufferSpec.js +++ b/Specs/Renderer/BufferSpec.js @@ -10,319 +10,696 @@ defineSuite([ createContext) { 'use strict'; - var context; - var buffer; + createBufferSpecs({}); + var c = createContext({ requestWebgl2 : true }); + // Don't repeat WebGL 1 tests when WebGL 2 is not supported + if (c.webgl2) { + createBufferSpecs({ requestWebgl2 : true }); + } + c.destroyForSpecs(); + + function createBufferSpecs(contextOptions) { + var context; + var buffer; + var buffer2; + var webglMessage = contextOptions.requestWebgl2 ? ': WebGL 2' : ''; + + beforeAll(function() { + context = createContext(contextOptions); + }); + + afterAll(function() { + context.destroyForSpecs(); + }); + + afterEach(function() { + if (buffer && !buffer.isDestroyed()) { + buffer = buffer.destroy(); + } + if (buffer2 && !buffer2.isDestroyed()) { + buffer2 = buffer2.destroy(); + } + }); - beforeAll(function() { - context = createContext(); - }); + it('throws when creating a vertex buffer with no context' + webglMessage, function() { + expect(function() { + buffer = Buffer.createVertexBuffer({ + sizeInBytes : 4, + usage : BufferUsage.STATIC_DRAW + }); + }).toThrowDeveloperError(); + }); - afterAll(function() { - context.destroyForSpecs(); - }); + it('throws when creating a vertex buffer with an invalid typed array' + webglMessage, function() { + expect(function() { + buffer = Buffer.createVertexBuffer({ + context : context, + typedArray : {}, + usage : BufferUsage.STATIC_DRAW + }); + }).toThrowDeveloperError(); + }); - afterEach(function() { - if (buffer) { - buffer = buffer.destroy(); - } - }); + it('throws when creating a vertex buffer with both a typed array and size in bytes' + webglMessage, function() { + expect(function() { + buffer = Buffer.createVertexBuffer({ + context : context, + typedArray : new Float32Array([0, 0, 0, 1]), + sizeInBytes : 16, + usage : BufferUsage.STATIC_DRAW + }); + }).toThrowDeveloperError(); + }); - it('throws when creating a vertex buffer with no context', function() { - expect(function() { + it('throws when creating a vertex buffer without a typed array or size in bytes' + webglMessage, function() { + expect(function() { + buffer = Buffer.createVertexBuffer({ + context : context, + usage : BufferUsage.STATIC_DRAW + }); + }).toThrowDeveloperError(); + }); + + it('throws when creating a vertex buffer with invalid usage' + webglMessage, function() { + expect(function() { + buffer = Buffer.createVertexBuffer({ + context : context, + sizeInBytes : 16, + usage : 0 + }); + }).toThrowDeveloperError(); + }); + + it('throws when creating a vertex buffer with size of zero' + webglMessage, function() { + expect(function() { + buffer = Buffer.createVertexBuffer({ + context : context, + sizeInBytes : 0, + usage : BufferUsage.STATIC_DRAW + }); + }).toThrowDeveloperError(); + }); + + it('creates vertex buffer' + webglMessage, function() { buffer = Buffer.createVertexBuffer({ - sizeInBytes : 4, + context : context, + sizeInBytes : 16, usage : BufferUsage.STATIC_DRAW }); - }).toThrowDeveloperError(); - }); - it('throws when creating a vertex buffer with an invalid typed array', function() { - expect(function() { + expect(buffer.sizeInBytes).toEqual(16); + expect(buffer.usage).toEqual(BufferUsage.STATIC_DRAW); + }); + + it('copies array to a vertex buffer' + webglMessage, function() { + var sizeInBytes = 3 * Float32Array.BYTES_PER_ELEMENT; + var vertices = new ArrayBuffer(sizeInBytes); + var positions = new Float32Array(vertices); + positions[0] = 1.0; + positions[1] = 2.0; + positions[2] = 3.0; + buffer = Buffer.createVertexBuffer({ context : context, - typedArray : {}, + sizeInBytes : sizeInBytes, usage : BufferUsage.STATIC_DRAW }); - }).toThrowDeveloperError(); - }); + buffer.copyFromArrayView(vertices); + }); + + it('can create a vertex buffer from a typed array' + webglMessage, function() { + var typedArray = new Float32Array(3); + typedArray[0] = 1.0; + typedArray[1] = 2.0; + typedArray[2] = 3.0; - it('throws when creating a vertex buffer with both a typed array and size in bytes', function() { - expect(function() { buffer = Buffer.createVertexBuffer({ context : context, - typedArray : new Float32Array([0, 0, 0, 1]), - sizeInBytes : 16, + typedArray : typedArray, usage : BufferUsage.STATIC_DRAW }); - }).toThrowDeveloperError(); - }); + expect(buffer.sizeInBytes).toEqual(typedArray.byteLength); + expect(buffer.usage).toEqual(BufferUsage.STATIC_DRAW); + }); - it('throws when creating a vertex buffer without a typed array or size in bytes', function() { - expect(function() { + it('can create a vertex buffer from a size in bytes' + webglMessage, function() { buffer = Buffer.createVertexBuffer({ context : context, + sizeInBytes : 4, usage : BufferUsage.STATIC_DRAW }); - }).toThrowDeveloperError(); - }); + expect(buffer.sizeInBytes).toEqual(4); + expect(buffer.usage).toEqual(BufferUsage.STATIC_DRAW); + }); - it('throws when creating a vertex buffer with invalid usage', function() { - expect(function() { - buffer = Buffer.createVertexBuffer({ + it('throws when creating an index buffer with no context' + webglMessage, function() { + expect(function() { + buffer = Buffer.createIndexBuffer({ + sizeInBytes : 4, + usage : BufferUsage.STATIC_DRAW, + indexDatatype : IndexDatatype.UNSIGNED_SHORT + }); + }).toThrowDeveloperError(); + }); + + it('throws when creating an index buffer with an invalid typed array' + webglMessage, function() { + expect(function() { + buffer = Buffer.createIndexBuffer({ + context : context, + typedArray : {}, + usage : BufferUsage.STATIC_DRAW, + indexDatatype : IndexDatatype.UNSIGNED_SHORT + }); + }).toThrowDeveloperError(); + }); + + it('throws when creating an index buffer with both a typed array and size in bytes' + webglMessage, function() { + expect(function() { + buffer = Buffer.createIndexBuffer({ + context : context, + typedArray : new Uint16Array([0, 1, 2, 0, 2, 3]), + sizeInBytes : 12, + usage : BufferUsage.STATIC_DRAW, + indexDatatype : IndexDatatype.UNSIGNED_SHORT + }); + }).toThrowDeveloperError(); + }); + + it('throws when creating an index buffer without a typed array or size in bytes' + webglMessage, function() { + expect(function() { + buffer = Buffer.createIndexBuffer({ + context : context, + usage : BufferUsage.STATIC_DRAW, + indexDatatype : IndexDatatype.UNSIGNED_SHORT + }); + }).toThrowDeveloperError(); + }); + + it('throws when creating an index buffer with invalid usage' + webglMessage, function() { + expect(function() { + buffer = Buffer.createIndexBuffer({ + context : context, + sizeInBytes : 16, + usage : "invalid", + indexDatatype : IndexDatatype.UNSIGNED_SHORT + }); + }).toThrowDeveloperError(); + }); + + it('throws when creating an index buffer with invalid index data type' + webglMessage, function() { + expect(function() { + buffer = Buffer.createIndexBuffer({ + context : context, + sizeInBytes : 16, + usage : BufferUsage.STATIC_DRAW, + indexDatatype : 'invalid' + }); + }).toThrowDeveloperError(); + }); + + it('throws when creating an index buffer with size of zero' + webglMessage, function() { + expect(function() { + buffer = Buffer.createIndexBuffer({ + context : context, + sizeInBytes : 0, + usage : BufferUsage.STATIC_DRAW, + indexDatatype : IndexDatatype.UNSIGNED_SHORT + }); + }).toThrowDeveloperError(); + }); + + it('creates index buffer' + webglMessage, function() { + buffer = Buffer.createIndexBuffer({ context : context, - sizeInBytes : 16, - usage : 0 + sizeInBytes : 6, + usage : BufferUsage.STREAM_DRAW, + indexDatatype : IndexDatatype.UNSIGNED_SHORT }); - }).toThrowDeveloperError(); - }); - it('throws when creating a vertex buffer with size of zero', function() { - expect(function() { - buffer = Buffer.createVertexBuffer({ + expect(buffer.sizeInBytes).toEqual(6); + expect(buffer.usage).toEqual(BufferUsage.STREAM_DRAW); + + expect(buffer.indexDatatype).toEqual(IndexDatatype.UNSIGNED_SHORT); + expect(buffer.bytesPerIndex).toEqual(2); + expect(buffer.numberOfIndices).toEqual(3); + }); + + it('copies array to an index buffer' + webglMessage, function() { + var sizeInBytes = 3 * Uint16Array.BYTES_PER_ELEMENT; + var elements = new ArrayBuffer(sizeInBytes); + var indices = new Uint16Array(elements); + indices[0] = 1; + indices[1] = 2; + indices[2] = 3; + + buffer = Buffer.createIndexBuffer({ context : context, - sizeInBytes : 0, - usage : BufferUsage.STATIC_DRAW + sizeInBytes : sizeInBytes, + usage : BufferUsage.STATIC_DRAW, + indexDatatype : IndexDatatype.UNSIGNED_SHORT }); - }).toThrowDeveloperError(); - }); - - it('creates vertex buffer', function() { - buffer = Buffer.createVertexBuffer({ - context : context, - sizeInBytes : 16, - usage : BufferUsage.STATIC_DRAW - }); - - expect(buffer.sizeInBytes).toEqual(16); - expect(buffer.usage).toEqual(BufferUsage.STATIC_DRAW); - }); - - it('copies array to a vertex buffer', function() { - var sizeInBytes = 3 * Float32Array.BYTES_PER_ELEMENT; - var vertices = new ArrayBuffer(sizeInBytes); - var positions = new Float32Array(vertices); - positions[0] = 1.0; - positions[1] = 2.0; - positions[2] = 3.0; - - buffer = Buffer.createVertexBuffer({ - context : context, - sizeInBytes : sizeInBytes, - usage : BufferUsage.STATIC_DRAW - }); - buffer.copyFromArrayView(vertices); - }); - - it('can create a vertex buffer from a typed array', function() { - var typedArray = new Float32Array(3 * Float32Array.BYTES_PER_ELEMENT); - typedArray[0] = 1.0; - typedArray[1] = 2.0; - typedArray[2] = 3.0; - - buffer = Buffer.createVertexBuffer({ - context : context, - typedArray : typedArray, - usage : BufferUsage.STATIC_DRAW - }); - expect(buffer.sizeInBytes).toEqual(typedArray.byteLength); - expect(buffer.usage).toEqual(BufferUsage.STATIC_DRAW); - }); - - it('can create a vertex buffer from a size in bytes', function() { - buffer = Buffer.createVertexBuffer({ - context : context, - sizeInBytes : 4, - usage : BufferUsage.STATIC_DRAW - }); - expect(buffer.sizeInBytes).toEqual(4); - expect(buffer.usage).toEqual(BufferUsage.STATIC_DRAW); - }); - - it('throws when creating an index buffer with no context', function() { - expect(function() { + buffer.copyFromArrayView(elements); + }); + + it('can create an index buffer from a typed array' + webglMessage, function() { + var typedArray = new Uint16Array(3); + typedArray[0] = 1; + typedArray[1] = 2; + typedArray[2] = 3; + buffer = Buffer.createIndexBuffer({ - sizeInBytes : 4, + context : context, + typedArray : typedArray, usage : BufferUsage.STATIC_DRAW, indexDatatype : IndexDatatype.UNSIGNED_SHORT }); - }).toThrowDeveloperError(); - }); + expect(buffer.sizeInBytes).toEqual(typedArray.byteLength); + expect(buffer.usage).toEqual(BufferUsage.STATIC_DRAW); + expect(buffer.indexDatatype).toEqual(IndexDatatype.UNSIGNED_SHORT); + }); - it('throws when creating an index buffer with an invalid typed array', function() { - expect(function() { + it('can create an index buffer from a size in bytes' + webglMessage, function() { buffer = Buffer.createIndexBuffer({ context : context, - typedArray : {}, + sizeInBytes : 6, usage : BufferUsage.STATIC_DRAW, indexDatatype : IndexDatatype.UNSIGNED_SHORT }); - }).toThrowDeveloperError(); - }); + expect(buffer.sizeInBytes).toEqual(6); + expect(buffer.usage).toEqual(BufferUsage.STATIC_DRAW); + expect(buffer.indexDatatype).toEqual(IndexDatatype.UNSIGNED_SHORT); + }); + + it('getBufferData throws without WebGL 2' + webglMessage, function() { + if (context.webgl2) { + return; + } + + buffer = Buffer.createVertexBuffer({ + context : context, + sizeInBytes : 4, + usage : BufferUsage.STATIC_DRAW + }); + var array = new Uint8Array(4); + + expect(function() { + buffer.getBufferData(array); + }).toThrowDeveloperError(); + }); + + it('getBufferData throws without arrayView' + webglMessage, function() { + if (!context.webgl2) { + return; + } + + buffer = Buffer.createVertexBuffer({ + context : context, + sizeInBytes : 4, + usage : BufferUsage.STATIC_DRAW + }); + + expect(function() { + buffer.getBufferData(undefined); + }).toThrowDeveloperError(); + }); + + it('getBufferData throws with invalid sourceOffset' + webglMessage, function() { + if (!context.webgl2) { + return; + } + + buffer = Buffer.createVertexBuffer({ + context : context, + sizeInBytes : 4, + usage : BufferUsage.STATIC_DRAW + }); + var array = new Uint8Array(4); + + expect(function() { + buffer.getBufferData(array, -1); + }).toThrowDeveloperError(); + expect(function() { + buffer.getBufferData(array, 5); + }).toThrowDeveloperError(); + }); + + it('getBufferData throws with invalid destinationOffset' + webglMessage, function() { + if (!context.webgl2) { + return; + } + + buffer = Buffer.createVertexBuffer({ + context : context, + sizeInBytes : 4, + usage : BufferUsage.STATIC_DRAW + }); + var array = new Uint8Array(4); + + expect(function() { + buffer.getBufferData(array, 0, -1); + }).toThrowDeveloperError(); + expect(function() { + buffer.getBufferData(array, 0, 5); + }).toThrowDeveloperError(); + }); + + it('getBufferData throws with invalid length' + webglMessage, function() { + if (!context.webgl2) { + return; + } + + buffer = Buffer.createVertexBuffer({ + context : context, + sizeInBytes : 4, + usage : BufferUsage.STATIC_DRAW + }); + var array = new Uint8Array(4); + + expect(function() { + buffer.getBufferData(array, 2, 0, 4); + }).toThrowDeveloperError(); + expect(function() { + buffer.getBufferData(array, 0, 2, 4); + }).toThrowDeveloperError(); + }); + + it('getBufferData reads from vertex buffer' + webglMessage, function() { + if (!context.webgl2) { + return; + } + + var typedArray = new Uint8Array(4); + typedArray[0] = 1; + typedArray[1] = 2; + typedArray[2] = 3; + typedArray[3] = 4; + + buffer = Buffer.createVertexBuffer({ + context : context, + typedArray : typedArray, + usage : BufferUsage.STATIC_DRAW + }); + + var destArray = new Uint8Array(4); + buffer.getBufferData(destArray); + + expect(destArray).toEqual(typedArray); + }); + + it('getBufferData reads from index buffer' + webglMessage, function() { + if (!context.webgl2) { + return; + } + var typedArray = new Uint16Array(3); + typedArray[0] = 1; + typedArray[1] = 2; + typedArray[2] = 3; - it('throws when creating an index buffer with both a typed array and size in bytes', function() { - expect(function() { buffer = Buffer.createIndexBuffer({ context : context, - typedArray : new Uint16Array([0, 1, 2, 0, 2, 3]), - sizeInBytes : 12, + typedArray : typedArray, usage : BufferUsage.STATIC_DRAW, indexDatatype : IndexDatatype.UNSIGNED_SHORT }); - }).toThrowDeveloperError(); - }); - it('throws when creating an index buffer without a typed array or size in bytes', function() { - expect(function() { + var destArray = new Uint16Array(3); + buffer.getBufferData(destArray); + + expect(destArray).toEqual(typedArray); + }); + + it('copyFromBuffer throws without WebGL 2' + webglMessage, function() { + if (context.webgl2) { + return; + } + + buffer = Buffer.createVertexBuffer({ + context : context, + sizeInBytes : 4, + usage : BufferUsage.STATIC_DRAW + }); + buffer2 = Buffer.createVertexBuffer({ + context : context, + sizeInBytes : 4, + usage : BufferUsage.STATIC_DRAW + }); + + expect(function() { + buffer.copyFromBuffer(buffer2, 0, 0, 4); + }).toThrowDeveloperError(); + }); + + it('copyFromBuffer throws without readBuffer' + webglMessage, function() { + if (!context.webgl2) { + return; + } + + buffer = Buffer.createVertexBuffer({ + context : context, + sizeInBytes : 4, + usage : BufferUsage.STATIC_DRAW + }); + + expect(function() { + buffer.copyFromBuffer(undefined, 0, 0, 4); + }).toThrowDeveloperError(); + }); + + it('copyFromBuffer throws with invalid readOffset' + webglMessage, function() { + if (!context.webgl2) { + return; + } + + buffer = Buffer.createVertexBuffer({ + context : context, + sizeInBytes : 4, + usage : BufferUsage.STATIC_DRAW + }); + buffer2 = Buffer.createVertexBuffer({ + context : context, + sizeInBytes : 4, + usage : BufferUsage.STATIC_DRAW + }); + + expect(function() { + buffer.copyFromBuffer(buffer2, undefined, 0, 4); + }).toThrowDeveloperError(); + expect(function() { + buffer.copyFromBuffer(buffer2, -1, 0, 4); + }).toThrowDeveloperError(); + expect(function() { + buffer.copyFromBuffer(buffer2, 5, 0, 4); + }).toThrowDeveloperError(); + }); + + it('copyFromBuffer throws with invalid writeOffset' + webglMessage, function() { + if (!context.webgl2) { + return; + } + + buffer = Buffer.createVertexBuffer({ + context : context, + sizeInBytes : 4, + usage : BufferUsage.STATIC_DRAW + }); + buffer2 = Buffer.createVertexBuffer({ + context : context, + sizeInBytes : 4, + usage : BufferUsage.STATIC_DRAW + }); + + expect(function() { + buffer.copyFromBuffer(buffer2, 0, undefined, 4); + }).toThrowDeveloperError(); + expect(function() { + buffer.copyFromBuffer(buffer2, 0, -1, 4); + }).toThrowDeveloperError(); + expect(function() { + buffer.copyFromBuffer(buffer2, 0, 5, 4); + }).toThrowDeveloperError(); + }); + + it('copyFromBuffer throws with invalid sizeInBytes' + webglMessage, function() { + if (!context.webgl2) { + return; + } + + buffer = Buffer.createVertexBuffer({ + context : context, + sizeInBytes : 4, + usage : BufferUsage.STATIC_DRAW + }); + buffer2 = Buffer.createVertexBuffer({ + context : context, + sizeInBytes : 4, + usage : BufferUsage.STATIC_DRAW + }); + + expect(function() { + buffer.copyFromBuffer(buffer2, 0, 0, undefined); + }).toThrowDeveloperError(); + expect(function() { + buffer.copyFromBuffer(buffer2, 0, 0, -1); + }).toThrowDeveloperError(); + expect(function() { + buffer.copyFromBuffer(buffer2, 0, 0, 0); + }).toThrowDeveloperError(); + expect(function() { + buffer.copyFromBuffer(buffer2, 0, 0, 5); + }).toThrowDeveloperError(); + }); + + it('copyFromBuffer throws with one index buffer and the other is not an index buffer' + webglMessage, function() { + if (!context.webgl2) { + return; + } + + var typedArray = new Uint16Array([0, 1, 2, 3, 4]); buffer = Buffer.createIndexBuffer({ context : context, + typedArray : typedArray, usage : BufferUsage.STATIC_DRAW, indexDatatype : IndexDatatype.UNSIGNED_SHORT }); - }).toThrowDeveloperError(); - }); + var typedArray2 = new Float32Array([5.0, 6.0, 7.0, 8.0, 9.0]); + buffer2 = Buffer.createVertexBuffer({ + context : context, + typedArray : typedArray2, + usage : BufferUsage.STATIC_DRAW + }); + + expect(function() { + buffer2.copyFromBuffer(buffer, 0, 0, typedArray.byteLength); + }).toThrowDeveloperError(); + }); + + it('copyFromBuffer throws when readBuffer is the same buffer and copy range overlaps' + webglMessage, function() { + if (!context.webgl2) { + return; + } + + buffer = Buffer.createVertexBuffer({ + context : context, + sizeInBytes : 4, + usage : BufferUsage.STATIC_DRAW + }); + + expect(function() { + buffer.copyFromBuffer(buffer, 0, 1, 2); + }).toThrowDeveloperError(); + expect(function() { + buffer.copyFromBuffer(buffer, 1, 0, 2); + }).toThrowDeveloperError(); + }); - it('throws when creating an index buffer with invalid usage', function() { - expect(function() { + it('copyFromBuffer with vertex buffers' + webglMessage, function() { + if (!context.webgl2) { + return; + } + + var typedArray = new Float32Array([0.0, 1.0, 2.0, 3.0, 4.0]); + buffer = Buffer.createVertexBuffer({ + context : context, + typedArray : typedArray, + usage : BufferUsage.STATIC_DRAW + }); + var typedArray2 = new Float32Array([5.0, 6.0, 7.0, 8.0, 9.0]); + buffer2 = Buffer.createVertexBuffer({ + context : context, + typedArray : typedArray2, + usage : BufferUsage.STATIC_DRAW + }); + + var destArray = new Float32Array(5); + buffer.getBufferData(destArray); + expect(destArray).toEqual(typedArray); + buffer2.getBufferData(destArray); + expect(destArray).toEqual(typedArray2); + + buffer2.copyFromBuffer(buffer, 0, 0, typedArray.byteLength); + buffer2.getBufferData(destArray); + expect(destArray).toEqual(typedArray); + }); + + it('copyFromBuffer with index buffers' + webglMessage, function() { + if (!context.webgl2) { + return; + } + + var typedArray = new Uint16Array([0, 1, 2, 3, 4]); buffer = Buffer.createIndexBuffer({ context : context, - sizeInBytes : 16, - usage : "invalid", + typedArray : typedArray, + usage : BufferUsage.STATIC_DRAW, + indexDatatype : IndexDatatype.UNSIGNED_SHORT + }); + var typedArray2 = new Uint16Array([5, 6, 7, 8, 9]); + buffer2 = Buffer.createIndexBuffer({ + context : context, + typedArray : typedArray2, + usage : BufferUsage.STATIC_DRAW, indexDatatype : IndexDatatype.UNSIGNED_SHORT }); - }).toThrowDeveloperError(); - }); - it('throws when creating an index buffer with invalid index data type', function() { - expect(function() { - buffer = Buffer.createIndexBuffer({ + var destArray = new Uint16Array(5); + buffer.getBufferData(destArray); + expect(destArray).toEqual(typedArray); + buffer2.getBufferData(destArray); + expect(destArray).toEqual(typedArray2); + + buffer2.copyFromBuffer(buffer, 0, 0, typedArray.byteLength); + buffer2.getBufferData(destArray); + expect(destArray).toEqual(typedArray); + }); + + it('destroys' + webglMessage, function() { + var b = Buffer.createIndexBuffer({ context : context, - sizeInBytes : 16, + sizeInBytes : 3, usage : BufferUsage.STATIC_DRAW, - indexDatatype : 'invalid' + indexDatatype : IndexDatatype.UNSIGNED_BYTE }); - }).toThrowDeveloperError(); - }); + expect(b.isDestroyed()).toEqual(false); + b.destroy(); + expect(b.isDestroyed()).toEqual(true); + }); - it('throws when creating an index buffer with size of zero', function() { - expect(function() { - buffer = Buffer.createIndexBuffer({ + it('fails to provide an array view' + webglMessage, function() { + buffer = Buffer.createVertexBuffer({ context : context, - sizeInBytes : 0, + sizeInBytes : 3, + usage : BufferUsage.STATIC_DRAW + }); + expect(function() { + buffer.copyFromArrayView(); + }).toThrowDeveloperError(); + }); + + it('fails to copy a large array view' + webglMessage, function() { + buffer = Buffer.createVertexBuffer({ + context : context, + sizeInBytes : 3, + usage : BufferUsage.STATIC_DRAW + }); + var elements = new ArrayBuffer(3); + + expect(function() { + buffer.copyFromArrayView(elements, 1); + }).toThrowDeveloperError(); + }); + + it('fails to destroy' + webglMessage, function() { + var b = Buffer.createIndexBuffer({ + context : context, + sizeInBytes : 3, usage : BufferUsage.STATIC_DRAW, - indexDatatype : IndexDatatype.UNSIGNED_SHORT + indexDatatype : IndexDatatype.UNSIGNED_BYTE }); - }).toThrowDeveloperError(); - }); - - it('creates index buffer', function() { - buffer = Buffer.createIndexBuffer({ - context : context, - sizeInBytes : 6, - usage : BufferUsage.STREAM_DRAW, - indexDatatype : IndexDatatype.UNSIGNED_SHORT - }); - - expect(buffer.sizeInBytes).toEqual(6); - expect(buffer.usage).toEqual(BufferUsage.STREAM_DRAW); - - expect(buffer.indexDatatype).toEqual(IndexDatatype.UNSIGNED_SHORT); - expect(buffer.bytesPerIndex).toEqual(2); - expect(buffer.numberOfIndices).toEqual(3); - }); - - it('copies array to an index buffer', function() { - var sizeInBytes = 3 * Uint16Array.BYTES_PER_ELEMENT; - var elements = new ArrayBuffer(sizeInBytes); - var indices = new Uint16Array(elements); - indices[0] = 1; - indices[1] = 2; - indices[2] = 3; - - buffer = Buffer.createIndexBuffer({ - context : context, - sizeInBytes : sizeInBytes, - usage : BufferUsage.STATIC_DRAW, - indexDatatype : IndexDatatype.UNSIGNED_SHORT - }); - buffer.copyFromArrayView(elements); - }); - - it('can create an index buffer from a typed array', function() { - var typedArray = new Uint16Array(3 * Uint16Array.BYTES_PER_ELEMENT); - typedArray[0] = 1; - typedArray[1] = 2; - typedArray[2] = 3; - - buffer = Buffer.createIndexBuffer({ - context : context, - typedArray : typedArray, - usage : BufferUsage.STATIC_DRAW, - indexDatatype : IndexDatatype.UNSIGNED_SHORT - }); - expect(buffer.sizeInBytes).toEqual(typedArray.byteLength); - expect(buffer.usage).toEqual(BufferUsage.STATIC_DRAW); - expect(buffer.indexDatatype).toEqual(IndexDatatype.UNSIGNED_SHORT); - }); - - it('can create an index buffer from a size in bytes', function() { - buffer = Buffer.createIndexBuffer({ - context : context, - sizeInBytes : 6, - usage : BufferUsage.STATIC_DRAW, - indexDatatype : IndexDatatype.UNSIGNED_SHORT - }); - expect(buffer.sizeInBytes).toEqual(6); - expect(buffer.usage).toEqual(BufferUsage.STATIC_DRAW); - expect(buffer.indexDatatype).toEqual(IndexDatatype.UNSIGNED_SHORT); - }); - - it('destroys', function() { - var b = Buffer.createIndexBuffer({ - context : context, - sizeInBytes : 3, - usage : BufferUsage.STATIC_DRAW, - indexDatatype : IndexDatatype.UNSIGNED_BYTE - }); - expect(b.isDestroyed()).toEqual(false); - b.destroy(); - expect(b.isDestroyed()).toEqual(true); - }); - - it('fails to provide an array view', function() { - buffer = Buffer.createVertexBuffer({ - context : context, - sizeInBytes : 3, - usage : BufferUsage.STATIC_DRAW - }); - expect(function() { - buffer.copyFromArrayView(); - }).toThrowDeveloperError(); - }); - - it('fails to copy a large array view', function() { - buffer = Buffer.createVertexBuffer({ - context : context, - sizeInBytes : 3, - usage : BufferUsage.STATIC_DRAW - }); - var elements = new ArrayBuffer(3); - - expect(function() { - buffer.copyFromArrayView(elements, 1); - }).toThrowDeveloperError(); - }); - - it('fails to destroy', function() { - var b = Buffer.createIndexBuffer({ - context : context, - sizeInBytes : 3, - usage : BufferUsage.STATIC_DRAW, - indexDatatype : IndexDatatype.UNSIGNED_BYTE - }); - b.destroy(); - - expect(function() { b.destroy(); - }).toThrowDeveloperError(); - }); + + expect(function() { + b.destroy(); + }).toThrowDeveloperError(); + }); + } }, 'WebGL'); diff --git a/Specs/Renderer/RenderStateSpec.js b/Specs/Renderer/RenderStateSpec.js index db21029c59d7..2a80493f342f 100644 --- a/Specs/Renderer/RenderStateSpec.js +++ b/Specs/Renderer/RenderStateSpec.js @@ -407,6 +407,21 @@ defineSuite([ expect(cache[fullKey]).not.toBeDefined(); }); + it('freezes render states', function(){ + var rs = RenderState.fromCache(); + expect(function() { + rs.depthRange = {}; + }).toThrow(); + + expect(function() { + rs.frontFace = WindingOrder.COUNTER_CLOCKWISE; + }).toThrow(); + + expect(function() { + rs._applyFunctions.push(function(){}); + }).not.toThrow(); + }); + it('fails to create (frontFace)', function() { expect(function() { RenderState.fromCache({ diff --git a/Specs/Renderer/TextureSpec.js b/Specs/Renderer/TextureSpec.js index c19d91c26140..61feb90a4e99 100644 --- a/Specs/Renderer/TextureSpec.js +++ b/Specs/Renderer/TextureSpec.js @@ -99,6 +99,7 @@ defineSuite([ source : blueImage }); + expect(texture.id).toBeDefined(); expect(texture.pixelFormat).toEqual(PixelFormat.RGBA); expect(texture.pixelDatatype).toEqual(PixelDatatype.UNSIGNED_BYTE); }); diff --git a/Specs/Renderer/VertexArraySpec.js b/Specs/Renderer/VertexArraySpec.js index f59af9fb5fa6..1974532d9ddf 100644 --- a/Specs/Renderer/VertexArraySpec.js +++ b/Specs/Renderer/VertexArraySpec.js @@ -510,7 +510,7 @@ defineSuite([ attributes : [{ vertexBuffer : Buffer.createVertexBuffer({ context : context, - sizeInBytes : new Float32Array([0, 0, 0, 1]), + sizeInBytes : new Float32Array([0, 0, 0, 1]).byteLength, usage : BufferUsage.STATIC_DRAW }), componentsPerAttribute : 4 diff --git a/Specs/Renderer/freezeRenderStateSpec.js b/Specs/Renderer/freezeRenderStateSpec.js new file mode 100644 index 000000000000..b702657356b0 --- /dev/null +++ b/Specs/Renderer/freezeRenderStateSpec.js @@ -0,0 +1,67 @@ +/*global defineSuite*/ +defineSuite([ + 'Renderer/freezeRenderState' + ], function( + freezeRenderState) { + 'use strict'; + + it('works for literals', function() { + var fresh = { + a: 1, + b: 'b', + c: 2.2, + u: undefined, + n: null + }; + + var frozen = freezeRenderState(fresh); + + expect(function() { + frozen.a = 2; + }).toThrow(); + + expect(function() { + frozen.b = 'c'; + }).toThrow(); + + expect(function() { + frozen.c = 2; + }).toThrow(); + + }); + + it('works for deep objects', function() { + var fresh = { + a: 2, + o: { + b: 2, + c: 'c' + } + }; + + var frozen = freezeRenderState(fresh); + + expect(function() { + frozen.o.b = 3; + frozen.o.c = 'dddd'; + }).toThrow(); + }); + + it('ignores _applyFunctions', function() { + var fresh = { + a: 1, + _applyFunctions: [function() { }] + }; + + var frozen = freezeRenderState(fresh); + + expect(function() { + frozen.a = 0; + }).toThrow(); + + expect(function() { + frozen._applyFunctions.push(function() { }); + }).not.toThrow(); + }); + +}); diff --git a/Specs/Scene/UrlTemplateImageryProviderSpec.js b/Specs/Scene/UrlTemplateImageryProviderSpec.js index b8befc7068a8..58b36954a391 100644 --- a/Specs/Scene/UrlTemplateImageryProviderSpec.js +++ b/Specs/Scene/UrlTemplateImageryProviderSpec.js @@ -634,6 +634,34 @@ defineSuite([ }); }); + it('uses custom tags', function() { + var provider = new UrlTemplateImageryProvider({ + url: 'made/up/tms/server/{custom1}/{custom2}/{z}/{y}/{x}.PNG', + tilingScheme: new GeographicTilingScheme(), + maximumLevel: 6, + customTags: { + custom1: function() { return 'foo';}, + custom2: function() { return 'bar';} + } + }); + + return pollToPromise(function() { + return provider.ready; + }).then(function() { + spyOn(loadImage, 'createImage').and.callFake(function(url, crossOrigin, deferred) { + expect(url).toEqual('made/up/tms/server/foo/bar/2/1/3.PNG'); + + // Just return any old image. + loadImage.defaultCreateImage('Data/Images/Red16x16.png', crossOrigin, deferred); + }); + + return provider.requestImage(3, 1, 2).then(function(image) { + expect(loadImage.createImage).toHaveBeenCalled(); + expect(image).toBeInstanceOf(Image); + }); + }); + }); + describe('pickFeatures', function() { it('returns undefined when enablePickFeatures is false', function() { var provider = new UrlTemplateImageryProvider({ diff --git a/Specs/karma-main.js b/Specs/karma-main.js index 46b04fc0451b..76f6d7d201d5 100644 --- a/Specs/karma-main.js +++ b/Specs/karma-main.js @@ -20,12 +20,14 @@ if (release) { require.config({ - baseUrl : '/base/Build/Cesium' + baseUrl : '/base/Build/Cesium', + waitSeconds : 0 }); toRequire.push('../Stubs/paths'); } else { require.config({ - baseUrl : '/base/Source' + baseUrl : '/base/Source', + waitSeconds : 0 }); }