diff --git a/.gitattributes b/.gitattributes index eba1110b5794..b29479ecf36d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,3 @@ # Auto detect text files and perform LF normalization -* text=auto \ No newline at end of file +* text=auto +package.json text eol=lf diff --git a/.gitignore b/.gitignore index 3028e8e0b71a..f55a016948ef 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ Thumbs.db /node_modules npm-debug.log npm-debug.log.* +package-lock.json # WebStorm user-specific .idea/workspace.xml diff --git a/.travis.yml b/.travis.yml index 42139a1752fe..ba2f838c45bd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: node_js node_js: - - "6" + - "8" sudo: false before_script: - export DISPLAY=:99.0 diff --git a/Apps/Sandcastle/CesiumSandcastle.js b/Apps/Sandcastle/CesiumSandcastle.js index 9f5f91270acd..40074438ec48 100644 --- a/Apps/Sandcastle/CesiumSandcastle.js +++ b/Apps/Sandcastle/CesiumSandcastle.js @@ -16,6 +16,10 @@ require({ }, { name : 'Source', location : '.' + }, { + name: 'CesiumUnminified', + location : '../Build/CesiumUnminified', + main: 'Cesium' }, { name : 'CodeMirror', location : '../ThirdParty/codemirror-4.6' @@ -43,6 +47,10 @@ require({ 'dojo/query', 'dojo/when', 'Sandcastle/LinkButton', + 'Source/Core/defined', + 'Source/Core/getBaseUri', + 'Source/Core/loadJsonp', + 'Source/Core/loadWithXhr', 'Source/Cesium', 'CodeMirror/addon/hint/show-hint', 'CodeMirror/addon/hint/javascript-hint', @@ -86,11 +94,18 @@ require({ query, when, LinkButton, - Cesium) { + defined, + getBaseUri, + loadJsonp, + loadWithXhr, + Cesium +) { 'use strict'; //In order for CodeMirror auto-complete to work, Cesium needs to be defined as a global. - window.Cesium = Cesium; + if (!defined(window.Cesium)) { + window.Cesium = Cesium; + } parser.parse(); @@ -214,7 +229,7 @@ require({ } function openDocTab(title, link) { - if (!Cesium.defined(docTabs[title])) { + if (!defined(docTabs[title])) { docTabs[title] = new ContentPane({ title : title, focused : true, @@ -271,7 +286,7 @@ require({ function onCursorActivity() { docNode.style.left = '-999px'; - if (Cesium.defined(docTimer)) { + if (defined(docTimer)) { window.clearTimeout(docTimer); } docTimer = window.setTimeout(showDocPopup, 500); @@ -295,7 +310,7 @@ require({ } function closeGalleryTooltip() { - if (Cesium.defined(activeGalleryTooltipDemo)) { + if (defined(activeGalleryTooltipDemo)) { popup.close(demoTooltips[activeGalleryTooltipDemo.name]); activeGalleryTooltipDemo = undefined; } @@ -312,7 +327,7 @@ require({ suffix = 'searchDemo'; } - if (Cesium.defined(activeGalleryTooltipDemo)) { + if (defined(activeGalleryTooltipDemo)) { popup.open({ popup : demoTooltips[activeGalleryTooltipDemo.name], around : dom.byId(activeGalleryTooltipDemo.name + suffix), @@ -324,7 +339,7 @@ require({ function scheduleGalleryTooltip(demo) { if (demo !== activeGalleryTooltipDemo) { activeGalleryTooltipDemo = demo; - if (Cesium.defined(galleryTooltipTimer)) { + if (defined(galleryTooltipTimer)) { window.clearTimeout(galleryTooltipTimer); } galleryTooltipTimer = window.setTimeout(openGalleryTooltip, 220); @@ -372,7 +387,7 @@ require({ var hints = JSHINT.errors; for (i = 0, len = hints.length; i < len; ++i) { var hint = hints[i]; - if (hint !== null && Cesium.defined(hint.reason) && hint.line > 0) { + if (hint !== null && defined(hint.reason) && hint.line > 0) { line = jsEditor.setGutterMarker(scriptLineToEditorLine(hint.line), 'hintGutter', makeLineLabel(hint.reason, 'hintMarker')); jsEditor.addLineClass(line, 'text', 'hintLine'); errorLines.push(line); @@ -383,7 +398,7 @@ require({ } function scheduleHint() { - if (Cesium.defined(hintTimer)) { + if (defined(hintTimer)) { window.clearTimeout(hintTimer); } hintTimer = setTimeout(clearErrorsAddHints, 550); @@ -391,14 +406,14 @@ require({ } function scheduleHintNoChange() { - if (Cesium.defined(hintTimer)) { + if (defined(hintTimer)) { window.clearTimeout(hintTimer); } hintTimer = setTimeout(clearErrorsAddHints, 550); } function scrollToLine(lineNumber) { - if (Cesium.defined(lineNumber)) { + if (defined(lineNumber)) { jsEditor.setCursor(lineNumber); // set selection twice in order to force the editor to scroll // to this location if the cursor is already there @@ -457,13 +472,13 @@ require({ function registerScroll(demoContainer) { if (document.onmousewheel !== undefined) { demoContainer.addEventListener('mousewheel', function(e) { - if (Cesium.defined(e.wheelDelta) && e.wheelDelta) { + if (defined(e.wheelDelta) && e.wheelDelta) { demoContainer.scrollLeft -= e.wheelDelta * 70 / 120; } }, false); } else { demoContainer.addEventListener('DOMMouseScroll', function(e) { - if (Cesium.defined(e.detail) && e.detail) { + if (defined(e.detail) && e.detail) { demoContainer.scrollLeft += e.detail * 70 / 3; } }, false); @@ -662,7 +677,7 @@ require({ function loadBucket(bucketName) { if (local.bucketName !== bucketName) { local.bucketName = bucketName; - if (Cesium.defined(bucketTypes[bucketName])) { + if (defined(bucketTypes[bucketName])) { local.headers = bucketTypes[bucketName]; } else { local.headers = ''; @@ -686,13 +701,13 @@ require({ var gistId = ioQuery.queryToObject(window.location.search.substring(1)).gist; if (window.location.search) { queryObject = ioQuery.queryToObject(window.location.search.substring(1)); - if (Cesium.defined(gistId)) { + if (defined(gistId)) { queryObject.gistId = gistId; } } else { queryObject.src = 'Hello World.html'; queryObject.label = 'Showcases'; - if (Cesium.defined(gistId)) { + if (defined(gistId)) { queryObject.gistId = gistId; } } @@ -731,13 +746,13 @@ require({ var scriptCode = scriptMatch[1]; demoCode = scriptCode.replace(/\s/g, ''); - if (Cesium.defined(queryObject.gistId)) { - Cesium.loadJsonp('https://api.github.com/gists/' + queryObject.gistId + '?access_token=dd8f755c2e5d9bbb26806bb93eaa2291f2047c60') + if (defined(queryObject.gistId)) { + loadJsonp('https://api.github.com/gists/' + queryObject.gistId + '?access_token=dd8f755c2e5d9bbb26806bb93eaa2291f2047c60') .then(function(data) { var files = data.data.files; var code = files['Cesium-Sandcastle.js'].content; var htmlFile = files['Cesium-Sandcastle.html']; - var html = Cesium.defined(htmlFile) ? htmlFile.content : defaultHtml; // Use the default html for old gists + var html = defined(htmlFile) ? htmlFile.content : defaultHtml; // Use the default html for old gists jsEditor.setValue(code); htmlEditor.setValue(html); demoCode = code.replace(/\s/g, ''); @@ -746,7 +761,7 @@ require({ gistHtml = html; previousCode = code; previousHtml = html; - sandcastleUrl = Cesium.getBaseUri(window.location.href) + '?src=Hello%20World.html&label=Showcases&gist=' + gistId; + sandcastleUrl = getBaseUri(window.location.href) + '?src=Hello%20World.html&label=Showcases&gist=' + gistId; CodeMirror.commands.runCesium(jsEditor); clearRun(); }).otherwise(function(error) { @@ -813,14 +828,14 @@ require({ appendConsole('consoleLog', 'Unable to load demo named ' + queryObject.src.replace('.html', '') + '. Redirecting to HelloWorld.\n', true); } } - } else if (Cesium.defined(e.data.log)) { + } else if (defined(e.data.log)) { // Console log messages from the iframe display in Sandcastle. appendConsole('consoleLog', e.data.log, false); - } else if (Cesium.defined(e.data.error)) { + } else if (defined(e.data.error)) { // Console error messages from the iframe display in Sandcastle var errorMsg = e.data.error; var lineNumber = e.data.lineNumber; - if (Cesium.defined(lineNumber)) { + if (defined(lineNumber)) { errorMsg += ' (on line '; if (e.data.url) { @@ -835,10 +850,10 @@ require({ } } appendConsole('consoleError', errorMsg, true); - } else if (Cesium.defined(e.data.warn)) { + } else if (defined(e.data.warn)) { // Console warning messages from the iframe display in Sandcastle. appendConsole('consoleWarn', e.data.warn, true); - } else if (Cesium.defined(e.data.highlight)) { + } else if (defined(e.data.highlight)) { // Hovering objects in the embedded Cesium window. highlightLine(e.data.highlight); } @@ -925,12 +940,12 @@ require({ } } }; - return Cesium.loadWithXhr({ + return loadWithXhr({ url : 'https://api.github.com/gists', data : JSON.stringify(data), method : 'POST' }).then(function(content) { - sandcastleUrl = Cesium.getBaseUri(window.location.href) + '?src=Hello%20World.html&label=Showcases&gist=' + JSON.parse(content).id; + sandcastleUrl = getBaseUri(window.location.href) + '?src=Hello%20World.html&label=Showcases&gist=' + JSON.parse(content).id; textArea.value = sandcastleUrl; textArea.select(); }).otherwise(function(error) { @@ -946,7 +961,7 @@ require({ if (gistIndex !== -1) { gistId = gistId.substring(gistIndex + gistParameter.length); } - window.location.href = Cesium.getBaseUri(window.location.href) + '?src=Hello%20World.html&label=Showcases&gist=' + gistId; + window.location.href = getBaseUri(window.location.href) + '?src=Hello%20World.html&label=Showcases&gist=' + gistId; }); registry.byId('buttonNew').on('click', function() { @@ -1093,7 +1108,7 @@ require({ demo.label = labels ? labels : ''; // Select the demo to load upon opening based on the query parameter. - if (Cesium.defined(queryObject.src)) { + if (defined(queryObject.src)) { var gistDemo = { name : 'Gist Import', code : demo.code, @@ -1101,7 +1116,7 @@ require({ }; if (demo.name === queryObject.src.replace('.html', '')) { loadFromGallery(demo).then(function() { - if (Cesium.defined(queryObject.gistId)) { + if (defined(queryObject.gistId)) { window.history.replaceState(gistDemo, gistDemo.name, '?src=Hello World.html&label=' + queryObject.label + '&gist=' + queryObject.gistId); document.title = 'Gist Import - Cesium Sandcastle'; } else { @@ -1126,7 +1141,7 @@ require({ var loading = true; function setSubtab(tabName) { - currentTab = Cesium.defined(tabName) && !loading ? tabName : queryObject.label; + currentTab = defined(tabName) && !loading ? tabName : queryObject.label; queryObject.label = tabName; loading = false; } @@ -1178,7 +1193,7 @@ require({ function createGalleryButton(demo, tabName) { var imgSrc = 'templates/Gallery_tile.jpg'; - if (Cesium.defined(demo.img)) { + if (defined(demo.img)) { imgSrc = 'gallery/' + demo.img; } @@ -1231,7 +1246,7 @@ require({ } var promise; - if (!Cesium.defined(gallery_demos)) { + if (!defined(gallery_demos)) { galleryErrorMsg.textContent = 'No demos found, please run the build script.'; galleryErrorMsg.style.display = 'inline-block'; } else { 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/Apps/Sandcastle/gallery/Classification.html b/Apps/Sandcastle/gallery/Classification.html index b5ec8301a0bc..6ea05df8bb97 100644 --- a/Apps/Sandcastle/gallery/Classification.html +++ b/Apps/Sandcastle/gallery/Classification.html @@ -19,10 +19,35 @@

Loading...

-
+
+ + + + + + + + + + + + + + + +
invert classification
inverted color alpha + + +
+
+ + + + + + + +
+
+
+

Loading...

+
+ + + + + diff --git a/Apps/Sandcastle/gallery/Imagery Layers Texture Filters.jpg b/Apps/Sandcastle/gallery/Imagery Layers Texture Filters.jpg new file mode 100644 index 000000000000..1b2318fe46a0 Binary files /dev/null and b/Apps/Sandcastle/gallery/Imagery Layers Texture Filters.jpg differ diff --git a/Apps/Sandcastle/index.html b/Apps/Sandcastle/index.html index 19851688af84..2f40003d957e 100644 --- a/Apps/Sandcastle/index.html +++ b/Apps/Sandcastle/index.html @@ -21,14 +21,14 @@ - + - - + + diff --git a/Apps/Sandcastle/templates/bucket-requirejs.html b/Apps/Sandcastle/templates/bucket-requirejs.html index 575e33fb77d0..75c88309f303 100644 --- a/Apps/Sandcastle/templates/bucket-requirejs.html +++ b/Apps/Sandcastle/templates/bucket-requirejs.html @@ -8,10 +8,12 @@ diff --git a/CHANGES.md b/CHANGES.md index 04f906719e49..a2263f7fe5c1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,10 +1,39 @@ 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) +* Added two new properties to `ImageryLayer` that allow for adjusting the texture sampler used for up- and down-sampling of image tiles, namely `minificationFilter` and `magnificationFilter` with possible values `LINEAR` (the default) and `NEAREST` defined in `TextureMinificationFilter` and `TextureMagnificationFilter`. [#5846](https://github.com/AnalyticalGraphicsInc/cesium/issues/5846) +* The enums `TextureMinificationFilter` and `TextureMagnificationFilter` have been made public to support the new texture filter properties mentioned above. +* 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) + ### 1.38 - 2017-10-02 +* Breaking changes + * `Scene/CullingVolume` has been removed. Use `Core/CullingVolume`. + * `Scene/OrthographicFrustum` has been removed. Use `Core/OrthographicFrustum`. + * `Scene/OrthographicOffCenterFrustum` has been removed. Use `Core/OrthographicOffCenterFrustum`. + * `Scene/PerspectiveFrustum` has been removed. Use `Core/PerspectiveFrustum`. + * `Scene/PerspectiveOffCenterFrustum` has been removed. Use `Core/PerspectiveOffCenterFrustum`. +* Added support in CZML for expressing `orientation` as the velocity vector of an entity, using `velocityReference` syntax. [#5807](https://github.com/AnalyticalGraphicsInc/cesium/pull/5807) +* Fixed CZML processing of `velocityReference` within an interval. [#5738](https://github.com/AnalyticalGraphicsInc/cesium/issues/5738) * Added ability to add an animation to `ModelAnimationCollection` by its index. [#5815](https://github.com/AnalyticalGraphicsInc/cesium/pull/5815) * Fixed a bug in `ModelAnimationCollection` that caused adding an animation by its name to throw an error. [#5815](https://github.com/AnalyticalGraphicsInc/cesium/pull/5815) -* Zoom about mouse now maintains camera heading, pitch, and roll [#4639](https://github.com/AnalyticalGraphicsInc/cesium/pull/5603) +* Fixed issue in Internet Explorer and Edge with loading unicode strings in typed arrays that impacted 3D Tiles Batch Table values. +* Zoom now maintains camera heading, pitch, and roll. [#4639](https://github.com/AnalyticalGraphicsInc/cesium/pull/5603) +* Fixed a bug in `PolylineCollection` preventing the display of more than 16K points in a single collection. [#5538](https://github.com/AnalyticalGraphicsInc/cesium/pull/5782) +* Fixed a 3D Tiles point cloud bug causing a stray point to appear at the center of the screen on certain hardware. [#5599](https://github.com/AnalyticalGraphicsInc/cesium/issues/5599) +* Fixed removing multiple event listeners within event callbacks. [#5827](https://github.com/AnalyticalGraphicsInc/cesium/issues/5827) +* Running `buildApps` now creates a built version of Sandcastle which uses the built version of Cesium for better performance. +* Fixed a tileset traversal bug when the `skipLevelOfDetail` optimization is off. [#5869](https://github.com/AnalyticalGraphicsInc/cesium/issues/5869) ### 1.37 - 2017-09-01 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 17c1e1d5d301..c3a5645c98b1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -55,7 +55,7 @@ Before we can merge a pull request, we require a signed Contributor License Agre * [individuals](Documentation/Contributors/CLAs/individual-cla-agi-v1.0.txt) and * [corporations](Documentation/Contributors/CLAs/corporate-cla-agi-v1.0.txt). -This only needs to be completed once. The CLA ensures you retain copyright to your contributions, and we have the right to use them and incorporate them into Cesium using the [Apache 2.0 License](LICENSE.md). +This only needs to be completed once, and enables contributions to all of the projects under the [Analytical Graphics Inc](https://github.com/AnalyticalGraphicsInc) organization, including Cesium. The CLA ensures you retain copyright to your contributions, and provides us the right to use, modify, and redistribute your contributions using the [Apache 2.0 License](LICENSE.md). Please email a completed CLA with all fields filled in to [cla@agi.com](mailto:cla@agi.com). Related questions are also welcome. @@ -82,6 +82,6 @@ Our code is our lifeblood so maintaining Cesium's high code quality is important # Code of Conduct -One of Cesium's strengths is our community. Our contributors and users are pushing the 3D geospatial field to amazing new levels. We rely on an open, friendly, inclusive environment to facilitate this. As such, we follow the [Contributor Covenant](http://contributor-covenant.org/)'s [Code of Conduct](http://contributor-covenant.org/version/1/4/code_of_conduct.md) to ensure a harassment-free experience in the Cesium community. Any unacceptable behavior can be confidentiality sent to the core team at pcozzi@agi.com. +One of Cesium's strengths is our community. Our contributors and users are pushing the 3D geospatial field to amazing new levels. We rely on an open, friendly, inclusive environment to facilitate this. As such, we follow the [Contributor Covenant](http://contributor-covenant.org/)'s [Code of Conduct](http://contributor-covenant.org/version/1/4/code_of_conduct.md) to ensure a harassment-free experience in the Cesium community. Any unacceptable behavior can be confidentially sent to the core team at pcozzi@agi.com. This applies to the main Cesium repo, forum, twitter, and all channels, including all repos in the [AnalyticalGraphicsInc](https://github.com/AnalyticalGraphicsInc) GitHub organization. diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 66b0f0a0c4fa..a9e5f51b5e3e 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -90,6 +90,11 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to Cesiu * [William Wall](https://github.com/wallw-bits) * [virtualcitySYSTEMS GmbH](https://www.virtualcitysystems.de) * [Jannes Bolling](https://github.com/jbo023) +* [Logilab](https://www.logilab.fr/) + * [Florent Cayré](https://github.com/fcayre/) +* [Novetta](http://www.novetta.com/) + * [Natanael Rivera](https://github.com/nrivera-Novetta/) + * [Justin Burr](https://github.com/jburr-nc/) ## [Individual CLA](Documentation/Contributors/CLAs/individual-cla-agi-v1.0.txt) * [Victor Berchet](https://github.com/vicb) @@ -156,4 +161,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to Cesiu * [Rishabh Shah](https://github.com/rms13) * [Rudraksha Shah](https://github.com/Rudraksha20) * [Cody Guldner](https://github.com/burn123) - +* [Nacho Carnicero](https://github.com/nacho-carnicero) diff --git a/Documentation/Contributors/CodingGuide/README.md b/Documentation/Contributors/CodingGuide/README.md index 48e41d0f636a..b5f5c943c313 100644 --- a/Documentation/Contributors/CodingGuide/README.md +++ b/Documentation/Contributors/CodingGuide/README.md @@ -138,9 +138,32 @@ function Model(options) { ## Linting -For syntax and style guidelines, we use the [ESLint](http://eslint.org/docs/rules/) recommended settings as a base and extend it with additional rules via a shared config Node module, [eslint-config-cesium](https://www.npmjs.com/package/eslint-config-cesium), which is maintained as part of the Cesium repository and also used throughout the Cesium ecosystem. For a list of which rules are enabled, look in [index.js](https://github.com/AnalyticalGraphicsInc/cesium/blob/master/Tools/eslint-config-cesium/index.js), [browser.js](https://github.com/AnalyticalGraphicsInc/cesium/blob/master/Tools/eslint-config-cesium/browser.js), and [node.js](https://github.com/AnalyticalGraphicsInc/cesium/blob/master/Tools/eslint-config-cesium/node.js). - -* When disabling linting for one line, use `//eslint-disable-line`: +For syntax and style guidelines, we use the ESLint recommended settings (the list of rules can be found [here](http://eslint.org/docs/rules/)) as a base and extend it with additional rules via a shared config Node module, [eslint-config-cesium](https://www.npmjs.com/package/eslint-config-cesium). This package is maintained as a part of the Cesium repository and is also used throughout the Cesium ecosystem. For a list of which rules are enabled, look in [index.js](https://github.com/AnalyticalGraphicsInc/cesium/blob/master/Tools/eslint-config-cesium/index.js), [browser.js](https://github.com/AnalyticalGraphicsInc/cesium/blob/master/Tools/eslint-config-cesium/browser.js), and [node.js](https://github.com/AnalyticalGraphicsInc/cesium/blob/master/Tools/eslint-config-cesium/node.js). + +**General rules:** +- [block-scoped-var](http://eslint.org/docs/rules/block-scoped-var) +- [no-alert](http://eslint.org/docs/rules/no-alert) +- [no-floating-decimal](http://eslint.org/docs/rules/no-floating-decimal) +- [no-implicit-globals](http://eslint.org/docs/rules/no-implicit-globals) +- [no-loop-func](http://eslint.org/docs/rules/no-loop-func) +- [no-use-before-define](http://eslint.org/docs/rules/no-use-before-define) to prevent using variables and functions before they are defined. +- [no-else-return](http://eslint.org/docs/rules/no-else-return) +- [no-undef-init](http://eslint.org/docs/rules/no-undef-init) +- [no-sequences](http://eslint.org/docs/rules/no-sequences) +- [no-unused-expressions](http://eslint.org/docs/rules/no-unused-expressions) +- [no-trailing-spaces](http://eslint.org/docs/rules/no-trailing-spaces) +- [no-lonely-if](http://eslint.org/docs/rules/no-lonely-if) +- [quotes](http://eslint.org/docs/rules/quotes) to enforce using single-quotes +- [no-sequences](http://eslint.org/docs/rules/no-sequences) +- [no-unused-expressions](http://eslint.org/docs/rules/no-unused-expressions) + +**Node-specific rules:** +- [global-require](http://eslint.org/docs/rules/global-require) +- [no-buffer-constructor](http://eslint.org/docs/rules/no-buffer-constructor) +- [no-new-require](http://eslint.org/docs/rules/no-new-require) + +**[Disabling Rules with Inline Comments](http://eslint.org/docs/user-guide/configuring#disabling-rules-with-inline-comments)** + * When disabling linting for one line, use `//eslint-disable-line`: ```js function exit(warningMessage) { window.alert('Cannot exit: ' + warningMessage); //eslint-disable-line no-alert @@ -157,8 +180,6 @@ try { /*eslint-enable no-empty*/ ``` -* See [Disabling Rules with Inline Comments](http://eslint.org/docs/user-guide/configuring#disabling-rules-with-inline-comments) for more examples. - ## Units * Cesium uses SI units: diff --git a/README.md b/README.md index 6143e463c93d..e1e69f8ca3b8 100644 --- a/README.md +++ b/README.md @@ -32,124 +32,135 @@ We appreciate attribution by including the Cesium logo and link in your app. ### Featured Demos ### -

-  -  -  -  +

+  +  +  +  +    -  -  -  +  +  +  +  + 

### Demos ###

-  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +    -  -  -  -  -  -  -  -  +  +  +  +  +  +  +  +    -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +   

- diff --git a/Source/Core/BingMapsApi.js b/Source/Core/BingMapsApi.js index f3ff31d96cb0..455d20853110 100644 --- a/Source/Core/BingMapsApi.js +++ b/Source/Core/BingMapsApi.js @@ -41,7 +41,7 @@ define([ console.log(errorString); printedBingWarning = true; } - return 'AsWE_wlRITl2b5Pr5oThzDwMg7Zh6ghwinCT-QinakkCBU9H2BUb7YQlpZXfPoo4'; + return 'Aig5SkZ4pNMN8b4rX-RUH2c_95mK-wjb4WL9k50K51faErEGnNsxgpWHXiqS3Rhe'; } return BingMapsApi.defaultKey; diff --git a/Source/Core/BoundingSphere.js b/Source/Core/BoundingSphere.js index f7f3dc731909..7372c40134be 100644 --- a/Source/Core/BoundingSphere.js +++ b/Source/Core/BoundingSphere.js @@ -72,7 +72,7 @@ define([ * The bounding sphere is computed by running two algorithms, a naive algorithm and * Ritter's algorithm. The smaller of the two spheres is used to ensure a tight fit. * - * @param {Cartesian3[]} positions An array of points that the bounding sphere will enclose. Each point must have x, y, and z properties. + * @param {Cartesian3[]} [positions] An array of points that the bounding sphere will enclose. Each point must have x, y, and z properties. * @param {BoundingSphere} [result] The object onto which to store the result. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if one was not provided. * @@ -223,7 +223,7 @@ define([ /** * Computes a bounding sphere from a rectangle projected in 2D. * - * @param {Rectangle} rectangle The rectangle around which to create a bounding sphere. + * @param {Rectangle} [rectangle] The rectangle around which to create a bounding sphere. * @param {Object} [projection=GeographicProjection] The projection used to project the rectangle into 2D. * @param {BoundingSphere} [result] The object onto which to store the result. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided. @@ -236,7 +236,7 @@ define([ * Computes a bounding sphere from a rectangle projected in 2D. The bounding sphere accounts for the * object's minimum and maximum heights over the rectangle. * - * @param {Rectangle} rectangle The rectangle around which to create a bounding sphere. + * @param {Rectangle} [rectangle] The rectangle around which to create a bounding sphere. * @param {Object} [projection=GeographicProjection] The projection used to project the rectangle into 2D. * @param {Number} [minimumHeight=0.0] The minimum height over the rectangle. * @param {Number} [maximumHeight=0.0] The maximum height over the rectangle. @@ -282,7 +282,7 @@ define([ * Computes a bounding sphere from a rectangle in 3D. The bounding sphere is created using a subsample of points * on the ellipsoid and contained in the rectangle. It may not be accurate for all rectangles on all types of ellipsoids. * - * @param {Rectangle} rectangle The valid rectangle used to create a bounding sphere. + * @param {Rectangle} [rectangle] The valid rectangle used to create a bounding sphere. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid used to determine positions of the rectangle. * @param {Number} [surfaceHeight=0.0] The height above the surface of the ellipsoid. * @param {BoundingSphere} [result] The object onto which to store the result. @@ -292,11 +292,17 @@ define([ ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84); surfaceHeight = defaultValue(surfaceHeight, 0.0); - var positions; - if (defined(rectangle)) { - positions = Rectangle.subsample(rectangle, ellipsoid, surfaceHeight, fromRectangle3DScratch); + if (!defined(result)) { + result = new BoundingSphere(); + } + + if (!defined(rectangle)) { + result.center = Cartesian3.clone(Cartesian3.ZERO, result.center); + result.radius = 0.0; + return result; } + var positions = Rectangle.subsample(rectangle, ellipsoid, surfaceHeight, fromRectangle3DScratch); return BoundingSphere.fromPoints(positions, result); }; @@ -306,7 +312,7 @@ define([ * algorithms, a naive algorithm and Ritter's algorithm. The smaller of the two spheres is used to * ensure a tight fit. * - * @param {Number[]} positions An array of points that the bounding sphere will enclose. Each point + * @param {Number[]} [positions] An array of points that the bounding sphere will enclose. Each point * is formed from three elements in the array in the order X, Y, Z. * @param {Cartesian3} [center=Cartesian3.ZERO] The position to which the positions are relative, which need not be the * origin of the coordinate system. This is useful when the positions are to be used for @@ -489,9 +495,9 @@ define([ * algorithms, a naive algorithm and Ritter's algorithm. The smaller of the two spheres is used to * ensure a tight fit. * - * @param {Number[]} positionsHigh An array of high bits of the encoded cartesians that the bounding sphere will enclose. Each point + * @param {Number[]} [positionsHigh] An array of high bits of the encoded cartesians that the bounding sphere will enclose. Each point * is formed from three elements in the array in the order X, Y, Z. - * @param {Number[]} positionsLow An array of low bits of the encoded cartesians that the bounding sphere will enclose. Each point + * @param {Number[]} [positionsLow] An array of low bits of the encoded cartesians that the bounding sphere will enclose. Each point * is formed from three elements in the array in the order X, Y, Z. * @param {BoundingSphere} [result] The object onto which to store the result. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if one was not provided. @@ -700,7 +706,7 @@ define([ /** * Computes a tight-fitting bounding sphere enclosing the provided array of bounding spheres. * - * @param {BoundingSphere[]} boundingSpheres The array of bounding spheres. + * @param {BoundingSphere[]} [boundingSpheres] The array of bounding spheres. * @param {BoundingSphere} [result] The object onto which to store the result. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided. */ diff --git a/Source/Core/CesiumTerrainProvider.js b/Source/Core/CesiumTerrainProvider.js index 9816f5adb63b..762c3ca5a5cb 100644 --- a/Source/Core/CesiumTerrainProvider.js +++ b/Source/Core/CesiumTerrainProvider.js @@ -20,6 +20,7 @@ define([ './QuantizedMeshTerrainData', './Request', './RequestType', + './RuntimeError', './TerrainProvider', './TileAvailability', './TileProviderError' @@ -45,11 +46,21 @@ define([ QuantizedMeshTerrainData, Request, RequestType, + RuntimeError, TerrainProvider, TileAvailability, TileProviderError) { 'use strict'; + function LayerInformation(layer) { + this.isHeightmap = layer.isHeightmap; + this.tileUrlTemplates = layer.tileUrlTemplates; + this.availability = layer.availability; + this.hasVertexNormals = layer.hasVertexNormals; + this.hasWaterMask = layer.hasWaterMask; + this.littleEndianExtensionSize = layer.littleEndianExtensionSize; + } + /** * A {@link TerrainProvider} that accesses terrain data in a Cesium terrain format. * The format is described on the @@ -114,14 +125,8 @@ define([ this._heightmapStructure = undefined; this._hasWaterMask = false; - - /** - * Boolean flag that indicates if the Terrain Server can provide vertex normals. - * @type {Boolean} - * @default false - * @private - */ this._hasVertexNormals = false; + /** * Boolean flag that indicates if the client should request vertex normals from the server. * @type {Boolean} @@ -129,7 +134,7 @@ define([ * @private */ this._requestVertexNormals = defaultValue(options.requestVertexNormals, false); - this._littleEndianExtensionSize = true; + /** * Boolean flag that indicates if the client should request tile watermasks from the server. * @type {Boolean} @@ -139,7 +144,6 @@ define([ this._requestWaterMask = defaultValue(options.requestWaterMask, false); this._errorEvent = new Event(); - this._availability = undefined; var credit = options.credit; if (typeof credit === 'string') { @@ -147,9 +151,12 @@ define([ } this._credit = credit; + this._availability = undefined; + this._ready = false; this._readyPromise = when.defer(); + var lastUrl = this._url; var metadataUrl = joinUrls(this._url, 'layer.json'); if (defined(this._proxy)) { metadataUrl = this._proxy.getURL(metadataUrl); @@ -158,7 +165,11 @@ define([ var that = this; var metadataError; - function metadataSuccess(data) { + var layers = this._layers = []; + var attribution = ''; + var overallAvailability = []; + + function parseMetadataSuccess(data) { var message; if (!data.format) { @@ -173,8 +184,14 @@ define([ return; } + var hasVertexNormals = false; + var hasWaterMask = false; + var littleEndianExtensionSize = true; + var isHeightmap = false; if (data.format === 'heightmap-1.0') { - that._heightmapStructure = { + isHeightmap = true; + if (!defined(that._heightmapStructure)) { + that._heightmapStructure = { heightScale : 1.0 / 5.0, heightOffset : -1000.0, elementsPerHeight : 1, @@ -184,7 +201,8 @@ define([ lowestEncodedHeight : 0, highestEncodedHeight : 256 * 256 - 1 }; - that._hasWaterMask = true; + } + hasWaterMask = true; that._requestWaterMask = true; } else if (data.format.indexOf('quantized-mesh-1.') !== 0) { message = 'The tile format "' + data.format + '" is invalid or not supported.'; @@ -192,37 +210,39 @@ define([ return; } - that._tileUrlTemplates = data.tiles; - for (var i = 0; i < that._tileUrlTemplates.length; ++i) { - var template = new Uri(that._tileUrlTemplates[i]); - var baseUri = new Uri(that._url); + var tileUrlTemplates = data.tiles; + for (var i = 0; i < tileUrlTemplates.length; ++i) { + var template = new Uri(tileUrlTemplates[i]); + var baseUri = new Uri(lastUrl); if (template.authority && !baseUri.authority) { baseUri.authority = template.authority; baseUri.scheme = template.scheme; } - that._tileUrlTemplates[i] = joinUrls(baseUri, template).toString().replace('{version}', data.version); + tileUrlTemplates[i] = joinUrls(baseUri, template).toString().replace('{version}', data.version); } var availableTiles = data.available; - + var availability; if (defined(availableTiles)) { - that._availability = new TileAvailability(that._tilingScheme, availableTiles.length); + availability = new TileAvailability(that._tilingScheme, availableTiles.length); for (var level = 0; level < availableTiles.length; ++level) { var rangesAtLevel = availableTiles[level]; var yTiles = that._tilingScheme.getNumberOfYTilesAtLevel(level); + if (!defined(overallAvailability[level])) { + overallAvailability[level] = []; + } for (var rangeIndex = 0; rangeIndex < rangesAtLevel.length; ++rangeIndex) { var range = rangesAtLevel[rangeIndex]; - that._availability.addAvailableTileRange(level, range.startX, yTiles - range.endY - 1, range.endX, yTiles - range.startY - 1); + var yStart = yTiles - range.endY - 1; + var yEnd = yTiles - range.startY - 1; + overallAvailability[level].push([range.startX, yStart, range.endX, yEnd]); + availability.addAvailableTileRange(level, range.startX, yStart, range.endX, yEnd); } } } - if (!defined(that._credit) && defined(data.attribution) && data.attribution !== null) { - that._credit = new Credit(data.attribution); - } - // The vertex normals defined in the 'octvertexnormals' extension is identical to the original // contents of the original 'vertexnormals' extension. 'vertexnormals' extension is now // deprecated, as the extensionLength for this extension was incorrectly using big endian. @@ -230,17 +250,82 @@ define([ // by setting the _littleEndianExtensionSize to false. Always prefer 'octvertexnormals' // over 'vertexnormals' if both extensions are supported by the server. if (defined(data.extensions) && data.extensions.indexOf('octvertexnormals') !== -1) { - that._hasVertexNormals = true; + hasVertexNormals = true; } else if (defined(data.extensions) && data.extensions.indexOf('vertexnormals') !== -1) { - that._hasVertexNormals = true; - that._littleEndianExtensionSize = false; + hasVertexNormals = true; + littleEndianExtensionSize = false; } if (defined(data.extensions) && data.extensions.indexOf('watermask') !== -1) { - that._hasWaterMask = true; + hasWaterMask = true; + } + + that._hasWaterMask = that._hasWaterMask || hasWaterMask; + that._hasVertexNormals = that._hasVertexNormals || hasVertexNormals; + if (defined(data.attribution)) { + if (attribution.length > 0) { + attribution += ' '; + } + attribution += data.attribution; + } + + layers.push(new LayerInformation({ + isHeightmap: isHeightmap, + tileUrlTemplates: tileUrlTemplates, + availability: availability, + hasVertexNormals: hasVertexNormals, + hasWaterMask: hasWaterMask, + littleEndianExtensionSize: littleEndianExtensionSize + })); + + var parentUrl = data.parentUrl; + if (defined(parentUrl)) { + if (!defined(availability)) { + console.log('A layer.json can\'t have a parentUrl if it does\'t have an available array.'); + return when.resolve(); + } + lastUrl = joinUrls(lastUrl, parentUrl); + metadataUrl = joinUrls(lastUrl, 'layer.json'); + if (defined(that._proxy)) { + metadataUrl = that._proxy.getURL(metadataUrl); + } + var parentMetadata = loadJson(metadataUrl); + return when(parentMetadata, parseMetadataSuccess, parseMetadataFailure); } - that._ready = true; - that._readyPromise.resolve(true); + return when.resolve(); + } + + function parseMetadataFailure(data) { + var message = 'An error occurred while accessing ' + metadataUrl + '.'; + metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata); + } + + function metadataSuccess(data) { + parseMetadataSuccess(data) + .then(function() { + if (defined(metadataError)) { + return; + } + + var length = overallAvailability.length; + if (length > 0) { + var availability = that._availability = new TileAvailability(that._tilingScheme, length); + for (var level = 0; level < length; ++level) { + var levelRanges = overallAvailability[level]; + for (var i = 0; i < levelRanges.length; ++i) { + var range = levelRanges[i]; + availability.addAvailableTileRange(level, range[0], range[1], range[2], range[3]); + } + } + } + + if (!defined(that._credit) && attribution.length > 0) { + that._credit = new Credit(attribution); + } + + that._ready = true; + that._readyPromise.resolve(true); + }); } function metadataFailure(data) { @@ -257,8 +342,7 @@ define([ }); return; } - var message = 'An error occurred while accessing ' + metadataUrl + '.'; - metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata); + parseMetadataFailure(data); } function requestMetadata() { @@ -320,7 +404,7 @@ define([ }); } - function createQuantizedMeshTerrainData(provider, buffer, level, x, y, tmsY) { + function createQuantizedMeshTerrainData(provider, buffer, level, x, y, tmsY, littleEndianExtensionSize) { var pos = 0; var cartesian3Elements = 3; var boundingSphereElements = cartesian3Elements + 1; @@ -431,7 +515,7 @@ define([ while (pos < view.byteLength) { var extensionId = view.getUint8(pos, true); pos += Uint8Array.BYTES_PER_ELEMENT; - var extensionLength = view.getUint32(pos, provider._littleEndianExtensionSize); + var extensionLength = view.getUint32(pos, littleEndianExtensionSize); pos += Uint32Array.BYTES_PER_ELEMENT; if (extensionId === QuantizedMeshExtensionIds.OCT_VERTEX_NORMALS && provider._requestVertexNormals) { @@ -505,7 +589,27 @@ define([ } //>>includeEnd('debug'); - var urlTemplates = this._tileUrlTemplates; + var layers = this._layers; + var layerToUse; + var layerCount = layers.length; + + if (layerCount === 1) { // Optimized path for single layers + layerToUse = layers[0]; + } else { + for (var i = 0; i < layerCount; ++i) { + var layer = layers[i]; + if (!defined(layer.availability) || layer.availability.isTileAvailable(level, x, y)) { + layerToUse = layer; + break; + } + } + } + + if (!defined(layerToUse)) { + return when.reject(new RuntimeError('Terrain tile doesn\'t exist')); + } + + var urlTemplates = layerToUse.tileUrlTemplates; if (urlTemplates.length === 0) { return undefined; } @@ -522,10 +626,10 @@ define([ } var extensionList = []; - if (this._requestVertexNormals && this._hasVertexNormals) { - extensionList.push(this._littleEndianExtensionSize ? 'octvertexnormals' : 'vertexnormals'); + if (this._requestVertexNormals && layerToUse.hasVertexNormals) { + extensionList.push(layerToUse.littleEndianExtensionSize ? 'octvertexnormals' : 'vertexnormals'); } - if (this._requestWaterMask && this._hasWaterMask) { + if (this._requestWaterMask && layerToUse.hasWaterMask) { extensionList.push('watermask'); } @@ -540,7 +644,7 @@ define([ if (defined(that._heightmapStructure)) { return createHeightmapTerrainData(that, buffer, level, x, y, tmsY); } - return createQuantizedMeshTerrainData(that, buffer, level, x, y, tmsY); + return createQuantizedMeshTerrainData(that, buffer, level, x, y, tmsY, layerToUse.littleEndianExtensionSize); }); }; @@ -723,10 +827,11 @@ define([ * @returns {Boolean} Undefined if not supported, otherwise true or false. */ CesiumTerrainProvider.prototype.getTileDataAvailable = function(x, y, level) { - if (!defined(this.availability)) { + if (!defined(this._availability)) { return undefined; } - return this.availability.isTileAvailable(level, x, y); + + return this._availability.isTileAvailable(level, x, y); }; return CesiumTerrainProvider; diff --git a/Source/Core/Event.js b/Source/Core/Event.js index 4244fca65768..2f5b6b810add 100644 --- a/Source/Core/Event.js +++ b/Source/Core/Event.js @@ -120,6 +120,10 @@ define([ return false; }; + function compareNumber(a,b) { + return b - a; + } + /** * Raises the event by calling each registered listener with all supplied arguments. * @@ -146,12 +150,15 @@ define([ //Actually remove items removed in removeEventListener. var toRemove = this._toRemove; length = toRemove.length; - for (i = 0; i < length; i++) { - var index = toRemove[i]; - listeners.splice(index, 1); - scopes.splice(index, 1); + if (length > 0) { + toRemove.sort(compareNumber); + for (i = 0; i < length; i++) { + var index = toRemove[i]; + listeners.splice(index, 1); + scopes.splice(index, 1); + } + toRemove.length = 0; } - toRemove.length = 0; this._insideRaiseEvent = false; }; 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/TaskProcessor.js b/Source/Core/TaskProcessor.js index 47b2f8f67fa5..9cd93627cfd7 100644 --- a/Source/Core/TaskProcessor.js +++ b/Source/Core/TaskProcessor.js @@ -137,7 +137,7 @@ define([ if (defined(TaskProcessor._loaderConfig)) { bootstrapMessage.loaderConfig = TaskProcessor._loaderConfig; - } else if (defined(require.toUrl)) { + } else if (defined(define.amd) && !define.amd.toUrlUndefined && defined(require.toUrl)) { bootstrapMessage.loaderConfig.baseUrl = getAbsoluteUri('..', buildModuleUrl('Workers/cesiumWorkerBootstrapper.js')); } else { diff --git a/Source/Core/buildModuleUrl.js b/Source/Core/buildModuleUrl.js index 509f9e2509e3..c39d5fb0ef7c 100644 --- a/Source/Core/buildModuleUrl.js +++ b/Source/Core/buildModuleUrl.js @@ -74,7 +74,7 @@ define([ function buildModuleUrl(moduleID) { if (!defined(implementation)) { //select implementation - if (defined(require.toUrl)) { + if (defined(define.amd) && !define.amd.toUrlUndefined && defined(require.toUrl)) { implementation = buildModuleUrlFromRequireToUrl; } else { implementation = buildModuleUrlFromBaseUrl; diff --git a/Source/Core/getStringFromTypedArray.js b/Source/Core/getStringFromTypedArray.js index a3d3c514910a..a866328d39a5 100644 --- a/Source/Core/getStringFromTypedArray.js +++ b/Source/Core/getStringFromTypedArray.js @@ -1,13 +1,14 @@ define([ './defaultValue', './defined', - './DeveloperError' + './DeveloperError', + './RuntimeError' ], function( defaultValue, defined, - DeveloperError) { + DeveloperError, + RuntimeError) { 'use strict'; - /*global TextDecoder*/ /** * @private @@ -42,20 +43,120 @@ define([ return decoder.decode(view); }; + getStringFromTypedArray.decodeWithFromCharCode = function(view) { var result = ''; - var length = view.length; - - // Convert one character at a time to avoid stack overflow on iPad. - // - // fromCharCode will not handle all legal Unicode values (up to 21 bits). See - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCharCode + var codePoints = utf8Handler(view); + var length = codePoints.length; for (var i = 0; i < length; ++i) { - result += String.fromCharCode(view[i]); + var cp = codePoints[i]; + if (cp <= 0xFFFF) { + result += String.fromCharCode(cp); + } else { + cp -= 0x10000; + result += String.fromCharCode((cp >> 10) + 0xD800, + (cp & 0x3FF) + 0xDC00); + } + } return result; }; + function inRange(a, min, max) { + return min <= a && a <= max; + } + + // This code is inspired by public domain code found here: https://github.com/inexorabletash/text-encoding + function utf8Handler(utfBytes) { + var codePoint = 0; + var bytesSeen = 0; + var bytesNeeded = 0; + var lowerBoundary = 0x80; + var upperBoundary = 0xBF; + + var codePoints = []; + var length = utfBytes.length; + for (var i = 0; i < length; ++i) { + var byte = utfBytes[i]; + + // If bytesNeeded = 0, then we are starting a new character + if (bytesNeeded === 0) { + // 1 Byte Ascii character + if (inRange(byte, 0x00, 0x7F)) { + // Return a code point whose value is byte. + codePoints.push(byte); + continue; + } + + // 2 Byte character + if (inRange(byte, 0xC2, 0xDF)) { + bytesNeeded = 1; + codePoint = byte & 0x1F; + continue; + } + + // 3 Byte character + if (inRange(byte, 0xE0, 0xEF)) { + // If byte is 0xE0, set utf-8 lower boundary to 0xA0. + if (byte === 0xE0) { + lowerBoundary = 0xA0; + } + // If byte is 0xED, set utf-8 upper boundary to 0x9F. + if (byte === 0xED) { + upperBoundary = 0x9F; + } + + bytesNeeded = 2; + codePoint = byte & 0xF; + continue; + } + + // 4 Byte character + if (inRange(byte, 0xF0, 0xF4)) { + // If byte is 0xF0, set utf-8 lower boundary to 0x90. + if (byte === 0xF0) { + lowerBoundary = 0x90; + } + // If byte is 0xF4, set utf-8 upper boundary to 0x8F. + if (byte === 0xF4) { + upperBoundary = 0x8F; + } + + bytesNeeded = 3; + codePoint = byte & 0x7; + continue; + } + + throw new RuntimeError('String decoding failed.'); + } + + // Out of range, so ignore the first part(s) of the character and continue with this byte on its own + if (!inRange(byte, lowerBoundary, upperBoundary)) { + codePoint = bytesNeeded = bytesSeen = 0; + lowerBoundary = 0x80; + upperBoundary = 0xBF; + --i; + continue; + } + + // Set appropriate boundaries, since we've now checked byte 2 of a potential longer character + lowerBoundary = 0x80; + upperBoundary = 0xBF; + + // Add byte to code point + codePoint = (codePoint << 6) | (byte & 0x3F); + + // We have the correct number of bytes, so push and reset for next character + ++bytesSeen; + if (bytesSeen === bytesNeeded) { + codePoints.push(codePoint); + codePoint = bytesNeeded = bytesSeen = 0; + } + } + + return codePoints; + } + if (typeof TextDecoder !== 'undefined') { getStringFromTypedArray.decode = getStringFromTypedArray.decodeWithTextDecoder; } else { 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/Core/sampleTerrain.js b/Source/Core/sampleTerrain.js index 4c83b02368b8..833adfdac1d8 100644 --- a/Source/Core/sampleTerrain.js +++ b/Source/Core/sampleTerrain.js @@ -16,7 +16,9 @@ define([ * or another error occurs, the height is set to undefined. As is typical of the * {@link Cartographic} type, the supplied height is a height above the reference ellipsoid * (such as {@link Ellipsoid.WGS84}) rather than an altitude above mean sea level. In other - * words, it will not necessarily be 0.0 if sampled in the ocean. + * words, it will not necessarily be 0.0 if sampled in the ocean. This function needs the + * terrain level of detail as input, if you need to get the altitude of the terrain as precisely + * as possible (i.e. with maximum level of detail) use {@link sampleTerrainMostDetailed}. * * @exports sampleTerrain * @@ -25,6 +27,8 @@ define([ * @param {Cartographic[]} positions The positions to update with terrain heights. * @returns {Promise.} A promise that resolves to the provided list of positions when terrain the query has completed. * + * @see sampleTerrainMostDetailed + * * @example * // Query the terrain height of two Cartographic positions * var terrainProvider = new Cesium.CesiumTerrainProvider({ 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/CzmlDataSource.js b/Source/DataSources/CzmlDataSource.js index 50e147bfa285..eee6518fc964 100644 --- a/Source/DataSources/CzmlDataSource.js +++ b/Source/DataSources/CzmlDataSource.js @@ -84,6 +84,7 @@ define([ './StripeOrientation', './TimeIntervalCollectionPositionProperty', './TimeIntervalCollectionProperty', + './VelocityOrientationProperty', './VelocityVectorProperty', './WallGraphics' ], function( @@ -172,23 +173,53 @@ define([ StripeOrientation, TimeIntervalCollectionPositionProperty, TimeIntervalCollectionProperty, + VelocityOrientationProperty, VelocityVectorProperty, WallGraphics) { 'use strict'; + // A marker type to distinguish CZML properties where we need to end up with a unit vector. + // The data is still loaded into Cartesian3 objects but they are normalized. + function UnitCartesian3() {} + UnitCartesian3.packedLength = Cartesian3.packedLength; + UnitCartesian3.unpack = Cartesian3.unpack; + UnitCartesian3.pack = Cartesian3.pack; + + // As a side note, for the purposes of CZML, Quaternion always indicates a unit quaternion. + var currentId; - function makeReference(collection, referenceString) { + function createReferenceProperty(entityCollection, referenceString) { if (referenceString[0] === '#') { referenceString = currentId + referenceString; } - return ReferenceProperty.fromString(collection, referenceString); + return ReferenceProperty.fromString(entityCollection, referenceString); + } + + function createSpecializedProperty(type, entityCollection, packetData) { + if (defined(packetData.reference)) { + return createReferenceProperty(entityCollection, packetData.reference); + } + + if (defined(packetData.velocityReference)) { + var referenceProperty = createReferenceProperty(entityCollection, packetData.velocityReference); + switch (type) { + case Cartesian3: + case UnitCartesian3: + return new VelocityVectorProperty(referenceProperty, type === UnitCartesian3); + case Quaternion: + return new VelocityOrientationProperty(referenceProperty); + } + } + + throw new RuntimeError(JSON.stringify(packetData) + ' is not valid CZML.'); } var scratchCartesian = new Cartesian3(); var scratchSpherical = new Spherical(); var scratchCartographic = new Cartographic(); var scratchTimeInterval = new TimeInterval(); + var scratchQuaternion = new Quaternion(); function unwrapColorInterval(czmlInterval) { var rgbaf = czmlInterval.rgbaf; @@ -398,17 +429,30 @@ define([ throw new RuntimeError(JSON.stringify(czmlInterval) + ' is not a valid CZML interval.'); } + function normalizePackedCartesianArray(array, startingIndex) { + Cartesian3.unpack(array, startingIndex, scratchCartesian); + Cartesian3.normalize(scratchCartesian, scratchCartesian); + Cartesian3.pack(scratchCartesian, array, startingIndex); + } + + function unwrapUnitCartesianInterval(czmlInterval) { + var cartesian = unwrapCartesianInterval(czmlInterval); + if (cartesian.length === 3) { + normalizePackedCartesianArray(cartesian, 0); + return cartesian; + } + + for (var i = 1; i < cartesian.length; i += 4) { + normalizePackedCartesianArray(cartesian, i); + } + + return cartesian; + } + function normalizePackedQuaternionArray(array, startingIndex) { - var x = array[startingIndex]; - var y = array[startingIndex + 1]; - var z = array[startingIndex + 2]; - var w = array[startingIndex + 3]; - - var inverseMagnitude = 1.0 / Math.sqrt(x * x + y * y + z * z + w * w); - array[startingIndex] = x * inverseMagnitude; - array[startingIndex + 1] = y * inverseMagnitude; - array[startingIndex + 2] = z * inverseMagnitude; - array[startingIndex + 3] = w * inverseMagnitude; + Quaternion.unpack(array, startingIndex, scratchQuaternion); + Quaternion.normalize(scratchQuaternion, scratchQuaternion); + Quaternion.pack(scratchQuaternion, array, startingIndex); } function unwrapQuaternionInterval(czmlInterval) { @@ -452,12 +496,13 @@ define([ } else if (czmlInterval.hasOwnProperty('cartesian2')) { return Cartesian2; } else if (czmlInterval.hasOwnProperty('cartesian') || - czmlInterval.hasOwnProperty('unitCartesian') || - czmlInterval.hasOwnProperty('unitSpherical') || czmlInterval.hasOwnProperty('spherical') || czmlInterval.hasOwnProperty('cartographicRadians') || czmlInterval.hasOwnProperty('cartographicDegrees')) { return Cartesian3; + } else if (czmlInterval.hasOwnProperty('unitCartesian') || + czmlInterval.hasOwnProperty('unitSpherical')) { + return UnitCartesian3; } else if (czmlInterval.hasOwnProperty('rgba') || czmlInterval.hasOwnProperty('rgbaf')) { return Color; @@ -514,6 +559,8 @@ define([ return czmlInterval.cartesian2; case Cartesian3: return unwrapCartesianInterval(czmlInterval); + case UnitCartesian3: + return unwrapUnitCartesianInterval(czmlInterval); case Color: return unwrapColorInterval(czmlInterval); case ColorBlendMode: @@ -614,10 +661,17 @@ define([ var isSampled; var unwrappedInterval; var unwrappedIntervalLength; - var isReference = defined(packetData.reference); + + // CZML properties can be defined in many ways. Most ways represent a structure for + // encoding a single value (number, string, cartesian, etc.) Regardless of the value type, + // if it encodes a single value it will get loaded into a ConstantProperty eventually. + // Alternatively, there are ways of defining a property that require specialized + // client-side representation. Currently, these are ReferenceProperty, + // and client-side velocity computation properties such as VelocityVectorProperty. + var isValue = !defined(packetData.reference) && !defined(packetData.velocityReference); var hasInterval = defined(combinedInterval) && !combinedInterval.equals(Iso8601.MAXIMUM_INTERVAL); - if (!isReference) { + if (isValue) { unwrappedInterval = unwrapInterval(type, packetData, sourceUri, query); packedLength = defaultValue(type.packedLength, 1); unwrappedIntervalLength = defaultValue(unwrappedInterval.length, 1); @@ -630,12 +684,10 @@ define([ //Any time a constant value is assigned, it completely blows away anything else. if (!isSampled && !hasInterval) { - if (isReference) { - object[propertyName] = makeReference(entityCollection, packetData.reference); - } else if (needsUnpacking) { - object[propertyName] = new ConstantProperty(type.unpack(unwrappedInterval, 0)); + if (isValue) { + object[propertyName] = new ConstantProperty(needsUnpacking ? type.unpack(unwrappedInterval, 0) : unwrappedInterval); } else { - object[propertyName] = new ConstantProperty(unwrappedInterval); + object[propertyName] = createSpecializedProperty(type, entityCollection, packetData); } return; } @@ -668,30 +720,30 @@ define([ if (!isSampled && hasInterval) { //Create a new interval for the constant value. combinedInterval = combinedInterval.clone(); - if (isReference) { - combinedInterval.data = makeReference(entityCollection, packetData.reference); - } else if (needsUnpacking) { - combinedInterval.data = type.unpack(unwrappedInterval, 0); + if (isValue) { + combinedInterval.data = needsUnpacking ? type.unpack(unwrappedInterval, 0) : unwrappedInterval; } else { - combinedInterval.data = unwrappedInterval; + combinedInterval.data = createSpecializedProperty(type, entityCollection, packetData); } //If no property exists, simply use a new interval collection if (!defined(property)) { - if (isReference) { - property = new CompositeProperty(); - } else { + if (isValue) { property = new TimeIntervalCollectionProperty(); + } else { + property = new CompositeProperty(); } object[propertyName] = property; } - if (!isReference && property instanceof TimeIntervalCollectionProperty) { + if (isValue && property instanceof TimeIntervalCollectionProperty) { //If we create a collection, or it already existed, use it. property.intervals.addInterval(combinedInterval); } else if (property instanceof CompositeProperty) { //If the collection was already a CompositeProperty, use it. - combinedInterval.data = isReference ? combinedInterval.data : new ConstantProperty(combinedInterval.data); + if (isValue) { + combinedInterval.data = new ConstantProperty(combinedInterval.data); + } property.intervals.addInterval(combinedInterval); } else { //Otherwise, create a CompositeProperty but preserve the existing data. @@ -708,7 +760,9 @@ define([ property.intervals.addInterval(interval); //Change the new data to a ConstantProperty and add it. - combinedInterval.data = isReference ? combinedInterval.data : new ConstantProperty(combinedInterval.data); + if (isValue) { + combinedInterval.data = new ConstantProperty(combinedInterval.data); + } property.intervals.addInterval(combinedInterval); } @@ -781,10 +835,10 @@ define([ var unwrappedIntervalLength; var numberOfDerivatives = defined(packetData.cartesianVelocity) ? 1 : 0; var packedLength = Cartesian3.packedLength * (numberOfDerivatives + 1); - var isReference = defined(packetData.reference); + var isValue = !defined(packetData.reference); var hasInterval = defined(combinedInterval) && !combinedInterval.equals(Iso8601.MAXIMUM_INTERVAL); - if (!isReference) { + if (isValue) { if (defined(packetData.referenceFrame)) { referenceFrame = ReferenceFrame[packetData.referenceFrame]; } @@ -796,10 +850,10 @@ define([ //Any time a constant value is assigned, it completely blows away anything else. if (!isSampled && !hasInterval) { - if (isReference) { - object[propertyName] = makeReference(entityCollection, packetData.reference); - } else { + if (isValue) { object[propertyName] = new ConstantPositionProperty(Cartesian3.unpack(unwrappedInterval), referenceFrame); + } else { + object[propertyName] = createReferenceProperty(entityCollection, packetData.reference); } return; } @@ -832,28 +886,30 @@ define([ if (!isSampled && hasInterval) { //Create a new interval for the constant value. combinedInterval = combinedInterval.clone(); - if (isReference) { - combinedInterval.data = makeReference(entityCollection, packetData.reference); - } else { + if (isValue) { combinedInterval.data = Cartesian3.unpack(unwrappedInterval); + } else { + combinedInterval.data = createReferenceProperty(entityCollection, packetData.reference); } //If no property exists, simply use a new interval collection if (!defined(property)) { - if (isReference) { - property = new CompositePositionProperty(referenceFrame); - } else { + if (isValue) { property = new TimeIntervalCollectionPositionProperty(referenceFrame); + } else { + property = new CompositePositionProperty(referenceFrame); } object[propertyName] = property; } - if (!isReference && property instanceof TimeIntervalCollectionPositionProperty && (defined(referenceFrame) && property.referenceFrame === referenceFrame)) { + if (isValue && property instanceof TimeIntervalCollectionPositionProperty && (defined(referenceFrame) && property.referenceFrame === referenceFrame)) { //If we create a collection, or it already existed, use it. property.intervals.addInterval(combinedInterval); } else if (property instanceof CompositePositionProperty) { //If the collection was already a CompositePositionProperty, use it. - combinedInterval.data = isReference ? combinedInterval.data : new ConstantPositionProperty(combinedInterval.data, referenceFrame); + if (isValue) { + combinedInterval.data = new ConstantPositionProperty(combinedInterval.data, referenceFrame); + } property.intervals.addInterval(combinedInterval); } else { //Otherwise, create a CompositePositionProperty but preserve the existing data. @@ -870,7 +926,9 @@ define([ property.intervals.addInterval(interval); //Change the new data to a ConstantPositionProperty and add it. - combinedInterval.data = isReference ? combinedInterval.data : new ConstantPositionProperty(combinedInterval.data, referenceFrame); + if (isValue) { + combinedInterval.data = new ConstantPositionProperty(combinedInterval.data, referenceFrame); + } property.intervals.addInterval(combinedInterval); } @@ -1117,7 +1175,7 @@ define([ var references = packetData.references; if (defined(references)) { var properties = references.map(function(reference) { - return makeReference(entityCollection, reference); + return createReferenceProperty(entityCollection, reference); }); var iso8601Interval = packetData.interval; @@ -1154,7 +1212,7 @@ define([ function processPositionsPacketData(object, propertyName, positionsData, entityCollection) { if (defined(positionsData.references)) { var properties = positionsData.references.map(function(reference) { - return makeReference(entityCollection, reference); + return createReferenceProperty(entityCollection, reference); }); var iso8601Interval = positionsData.interval; @@ -1230,11 +1288,7 @@ define([ return; } - if (defined(packetData.velocityReference)) { - billboard.alignedAxis = new VelocityVectorProperty(makeReference(entityCollection, packetData.velocityReference), true); - } else { - processPacketData(Cartesian3, billboard, 'alignedAxis', packetData, interval, sourceUri, entityCollection, query); - } + processPacketData(UnitCartesian3, billboard, 'alignedAxis', packetData, interval, sourceUri, entityCollection, query); } function processBillboard(entity, packet, entityCollection, sourceUri, query) { diff --git a/Source/DataSources/KmlDataSource.js b/Source/DataSources/KmlDataSource.js index 18873465eb5f..364b1b3b96e3 100644 --- a/Source/DataSources/KmlDataSource.js +++ b/Source/DataSources/KmlDataSource.js @@ -255,6 +255,33 @@ define([ return deferred.promise; } + function insertNamespaces(text) { + var namespaceMap = { + xsi : 'http://www.w3.org/2001/XMLSchema-instance' + }; + var firstPart, lastPart, reg, declaration; + + for (var key in namespaceMap) { + if (namespaceMap.hasOwnProperty(key)) { + reg = RegExp('[< ]' + key + ':'); + declaration = 'xmlns:' + key + '='; + if (reg.test(text) && text.indexOf(declaration) === -1) { + if (!defined(firstPart)) { + firstPart = text.substr(0, text.indexOf(' + * @memberof PolylineGraphics.prototype * @type {MaterialProperty} * @default undefined */ diff --git a/Source/Renderer/AutomaticUniforms.js b/Source/Renderer/AutomaticUniforms.js index 89dafdc31d3e..3e218afd105e 100644 --- a/Source/Renderer/AutomaticUniforms.js +++ b/Source/Renderer/AutomaticUniforms.js @@ -1588,6 +1588,20 @@ define([ getValue : function(uniformState) { return uniformState.minimumDisableDepthTestDistance; } + }), + + /** + * An automatic GLSL uniform that will be the highlight color of unclassified 3D Tiles. + * + * @alias czm_invertClassificationColor + * @glslUniform + */ + czm_invertClassificationColor : new AutomaticUniform({ + size : 1, + datatype : WebGLConstants.FLOAT_VEC4, + getValue : function(uniformState) { + return uniformState.invertClassificationColor; + } }) }; 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/Pass.js b/Source/Renderer/Pass.js index 3b3758834de2..f623fab44eec 100644 --- a/Source/Renderer/Pass.js +++ b/Source/Renderer/Pass.js @@ -23,10 +23,11 @@ define([ TERRAIN_CLASSIFICATION : 3, CESIUM_3D_TILE : 4, CESIUM_3D_TILE_CLASSIFICATION : 5, - OPAQUE : 6, - TRANSLUCENT : 7, - OVERLAY : 8, - NUMBER_OF_PASSES : 9 + CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW : 6, + OPAQUE : 7, + TRANSLUCENT : 8, + OVERLAY : 9, + NUMBER_OF_PASSES : 10 }; return freezeObject(Pass); 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/TextureMagnificationFilter.js b/Source/Renderer/TextureMagnificationFilter.js index ba87c508d991..edb9f3bf354d 100644 --- a/Source/Renderer/TextureMagnificationFilter.js +++ b/Source/Renderer/TextureMagnificationFilter.js @@ -7,12 +7,38 @@ define([ 'use strict'; /** - * @private + * Enumerates all possible filters used when magnifying WebGL textures, which takes places when zooming + * into imagery. Provides the possible values for the {@link ImageryLayer#magnificationFilter} property. + * + * @exports TextureMagnificationFilter + * + * @see TextureMinificationFilter + * @see ImageryLayer#magnificationFilter */ var TextureMagnificationFilter = { + /** + * Nearest neighbor sampling of image pixels to texture. + * + * @type {Number} + * @constant + */ NEAREST : WebGLConstants.NEAREST, + /** + * Bi-linear interpolation of image pixels to texture. + * + * @type {Number} + * @constant + */ LINEAR : WebGLConstants.LINEAR, + /** + * Validates the given textureMinificationFilter with respect to the possible enum values. + * + * @private + * + * @param textureMagnificationFilter + * @returns {Boolean} true if textureMagnificationFilter is valid. + */ validate : function(textureMagnificationFilter) { return ((textureMagnificationFilter === TextureMagnificationFilter.NEAREST) || (textureMagnificationFilter === TextureMagnificationFilter.LINEAR)); diff --git a/Source/Renderer/TextureMinificationFilter.js b/Source/Renderer/TextureMinificationFilter.js index 270d5d9ecc39..0f31ea0ee810 100644 --- a/Source/Renderer/TextureMinificationFilter.js +++ b/Source/Renderer/TextureMinificationFilter.js @@ -7,16 +7,66 @@ define([ 'use strict'; /** - * @private + * Enumerates all possible filters used when minifying WebGL textures, which takes places when zooming + * out of imagery. Provides the possible values for the {@link ImageryLayer#minificationFilter} property. + * + * @exports TextureMinificationFilter + * + * @see TextureMagnificationFilter + * @see ImageryLayer#minificationFilter */ var TextureMinificationFilter = { + /** + * Nearest neighbor sampling of image pixels to texture. + * + * @type {Number} + * @constant + */ NEAREST : WebGLConstants.NEAREST, + /** + * Bi-linear interpolation of image pixels to texture. + * + * @type {Number} + * @constant + */ LINEAR : WebGLConstants.LINEAR, + /** + * WebGL NEAREST_MIPMAP_NEAREST interpolation of image pixels to texture. + * + * @type {Number} + * @constant + */ NEAREST_MIPMAP_NEAREST : WebGLConstants.NEAREST_MIPMAP_NEAREST, + /** + * WebGL LINEAR_MIPMAP_NEAREST interpolation of image pixels to texture. + * + * @type {Number} + * @constant + */ LINEAR_MIPMAP_NEAREST : WebGLConstants.LINEAR_MIPMAP_NEAREST, + /** + * WebGL NEAREST_MIPMAP_LINEAR interpolation of image pixels to texture. + * + * @type {Number} + * @constant + */ NEAREST_MIPMAP_LINEAR : WebGLConstants.NEAREST_MIPMAP_LINEAR, + /** + * WebGL LINEAR_MIPMAP_LINEAR interpolation of image pixels to texture. + * + * @type {Number} + * @constant + */ LINEAR_MIPMAP_LINEAR : WebGLConstants.LINEAR_MIPMAP_LINEAR, + /** + * Validates the given textureMinificationFilter with respect to the possible enum values. + * + * @private + * + * @param textureMinificationFilter + * @returns {Boolean} true if textureMinificationFilter is valid. + */ validate : function(textureMinificationFilter) { return ((textureMinificationFilter === TextureMinificationFilter.NEAREST) || (textureMinificationFilter === TextureMinificationFilter.LINEAR) || diff --git a/Source/Renderer/UniformState.js b/Source/Renderer/UniformState.js index 0b2850daae4a..89c87d7a88b8 100644 --- a/Source/Renderer/UniformState.js +++ b/Source/Renderer/UniformState.js @@ -159,6 +159,8 @@ define([ this._fogDensity = undefined; + this._invertClassificationColor = undefined; + this._imagerySplitPosition = 0.0; this._pixelSizePerMeter = undefined; this._geometricToleranceOverMeter = undefined; @@ -847,6 +849,18 @@ define([ get : function() { return this._minimumDisableDepthTestDistance; } + }, + + /** + * The highlight color of unclassified 3D Tiles. + * + * @memberof UniformState.prototype + * @type {Color} + */ + invertClassificationColor : { + get : function() { + return this._invertClassificationColor; + } } }); @@ -1012,6 +1026,8 @@ define([ this._fogDensity = frameState.fog.density; + this._invertClassificationColor = frameState.invertClassificationColor; + this._frameState = frameState; this._temeToPseudoFixed = Transforms.computeTemeToPseudoFixedMatrix(frameState.time, this._temeToPseudoFixed); 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/Cesium3DTileBatchTable.js b/Source/Scene/Cesium3DTileBatchTable.js index f2b10bc06534..531ce6b2b9b2 100644 --- a/Source/Scene/Cesium3DTileBatchTable.js +++ b/Source/Scene/Cesium3DTileBatchTable.js @@ -1342,8 +1342,12 @@ define([ // selection depth to the stencil buffer to prevent ancestor tiles from drawing on top derivedCommand = DrawCommand.shallowClone(command); var rs = clone(derivedCommand.renderState, true); + // Stencil test is masked to the most significant 4 bits so the reference is shifted. + // This is to prevent clearing the stencil before classification which needs the least significant + // bits for increment/decrement operations. rs.stencilTest.enabled = true; - rs.stencilTest.reference = reference; + rs.stencilTest.mask = 0xF0; + rs.stencilTest.reference = reference << 4; rs.stencilTest.frontFunction = StencilFunction.GREATER_OR_EQUAL; rs.stencilTest.frontOperation.zPass = StencilOperation.REPLACE; derivedCommand.renderState = RenderState.fromCache(rs); diff --git a/Source/Scene/Cesium3DTileset.js b/Source/Scene/Cesium3DTileset.js index cca0bd85e6f7..c31894683961 100644 --- a/Source/Scene/Cesium3DTileset.js +++ b/Source/Scene/Cesium3DTileset.js @@ -1495,7 +1495,7 @@ define([ var addedCommandsLength = (lengthAfterUpdate - lengthBeforeUpdate); var backfaceCommandsLength = backfaceCommands.length; - commandList.length += backfaceCommands.length; + commandList.length += backfaceCommandsLength; // copy commands to the back of the commandList for (i = addedCommandsLength - 1; i >= 0; --i) { diff --git a/Source/Scene/Cesium3DTilesetTraversal.js b/Source/Scene/Cesium3DTilesetTraversal.js index c40334f96442..d7f759dce941 100644 --- a/Source/Scene/Cesium3DTilesetTraversal.js +++ b/Source/Scene/Cesium3DTilesetTraversal.js @@ -167,6 +167,9 @@ define([ * NOTE: this will no longer work when there is a chain of selected tiles that is longer than the size of the * stencil buffer (usually 8 bits). In other words, the subset of the tree containing only selected tiles must be * no deeper than 255. It is very, very unlikely this will cause a problem. + * + * NOTE: when the scene has inverted classification enabled, the stencil buffer will be masked to 4 bits. So, the + * selected tiles must be no deeper than 15. This is still very unlikely. */ function traverseAndSelect(tileset, root, frameState) { var stack = scratchStack; @@ -509,7 +512,7 @@ define([ if (!tile.hasTilesetContent) { if (tile.refine === Cesium3DTileRefine.ADD) { // Always load additive tiles - loadTile(tileset, tile, this.frameState); + loadTile(tileset, tile, this.frameState, true); if (hasAdditiveContent(tile)) { tileset._desiredTiles.push(tile); } @@ -635,9 +638,16 @@ define([ } } + function checkAdditiveVisibility(tileset, tile, frameState) { + if (defined(tile.parent) && (tile.parent.refine === Cesium3DTileRefine.ADD)) { + return isVisibleAndMeetsSSE(tileset, tile, frameState); + } + return true; + } + function loadTile(tileset, tile, frameState, checkVisibility) { if ((tile.contentUnloaded || tile.contentExpired) && tile._requestedFrame !== frameState.frameNumber) { - if (!checkVisibility || isVisibleAndMeetsSSE(tileset, tile, frameState)) { + if (!checkVisibility || checkAdditiveVisibility(tileset, tile, frameState)) { tile._requestedFrame = frameState.frameNumber; tileset._requestedTiles.push(tile); } diff --git a/Source/Scene/ClassificationPrimitive.js b/Source/Scene/ClassificationPrimitive.js index 49da56ec4403..7ca451d9bc5c 100644 --- a/Source/Scene/ClassificationPrimitive.js +++ b/Source/Scene/ClassificationPrimitive.js @@ -164,6 +164,7 @@ define([ this._uniformMap = options._uniformMap; this._sp = undefined; + this._spStencil = undefined; this._spPick = undefined; this._rsStencilPreloadPass = undefined; @@ -171,6 +172,8 @@ define([ this._rsColorPass = undefined; this._rsPickPass = undefined; + this._commandsIgnoreShow = []; + this._ready = false; this._readyPromise = when.defer(); @@ -344,6 +347,12 @@ define([ return scene.context.stencilBuffer; }; + // The stencil mask only uses the least significant 4 bits. + // This is so 3D Tiles with the skip LOD optimization, which uses the most significant 4 bits, + // can be classified. + var stencilMask = 0x0F; + var stencilReference = 0; + function getStencilPreloadRenderState(enableStencil) { return { colorMask : { @@ -366,8 +375,8 @@ define([ zFail : StencilOperation.INCREMENT_WRAP, zPass : StencilOperation.INCREMENT_WRAP }, - reference : 0, - mask : ~0 + reference : stencilReference, + mask : stencilMask }, depthTest : { enabled : false @@ -398,8 +407,8 @@ define([ zFail : StencilOperation.KEEP, zPass : StencilOperation.DECREMENT_WRAP }, - reference : 0, - mask : ~0 + reference : stencilReference, + mask : stencilMask }, depthTest : { enabled : true, @@ -426,8 +435,8 @@ define([ zFail : StencilOperation.KEEP, zPass : StencilOperation.DECREMENT_WRAP }, - reference : 0, - mask : ~0 + reference : stencilReference, + mask : stencilMask }, depthTest : { enabled : false @@ -452,8 +461,8 @@ define([ zFail : StencilOperation.KEEP, zPass : StencilOperation.DECREMENT_WRAP }, - reference : 0, - mask : ~0 + reference : stencilReference, + mask : stencilMask }, depthTest : { enabled : false @@ -510,7 +519,6 @@ define([ var primitive = classificationPrimitive._primitive; var vs = ShadowVolumeVS; vs = classificationPrimitive._primitive._batchTable.getVertexShaderCallback()(vs); - vs = Primitive._appendShowToShader(primitive, vs); vs = Primitive._appendDistanceDisplayConditionToShader(primitive, vs); vs = Primitive._modifyShaderPosition(classificationPrimitive, vs, frameState.scene3DOnly); vs = Primitive._updateColorAttribute(primitive, vs); @@ -530,9 +538,9 @@ define([ }); var attributeLocations = classificationPrimitive._primitive._attributeLocations; - classificationPrimitive._sp = ShaderProgram.replaceCache({ + classificationPrimitive._spStencil = ShaderProgram.replaceCache({ context : context, - shaderProgram : classificationPrimitive._sp, + shaderProgram : classificationPrimitive._spStencil, vertexShaderSource : vsSource, fragmentShaderSource : fsSource, attributeLocations : attributeLocations @@ -567,6 +575,20 @@ define([ attributeLocations : attributeLocations }); } + + vs = Primitive._appendShowToShader(primitive, vs); + vsSource = new ShaderSource({ + defines : [extrudedDefine], + sources : [vs] + }); + + classificationPrimitive._sp = ShaderProgram.replaceCache({ + context : context, + shaderProgram : classificationPrimitive._sp, + vertexShaderSource : vsSource, + fragmentShaderSource : fsSource, + attributeLocations : attributeLocations + }); } function createColorCommands(classificationPrimitive, colorCommands) { @@ -632,6 +654,24 @@ define([ command = colorCommands[length + i] = DrawCommand.shallowClone(colorCommands[i], colorCommands[length + i]); command.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION; } + + var commandsIgnoreShow = classificationPrimitive._commandsIgnoreShow; + var spStencil = classificationPrimitive._spStencil; + + var commandIndex = 0; + length = commandsIgnoreShow.length = length / 3 * 2; + + for (var j = 0; j < length; j += 2) { + var commandIgnoreShow = commandsIgnoreShow[j] = DrawCommand.shallowClone(colorCommands[commandIndex], commandsIgnoreShow[j]); + commandIgnoreShow.shaderProgram = spStencil; + commandIgnoreShow.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW; + + commandIgnoreShow = commandsIgnoreShow[j + 1] = DrawCommand.shallowClone(colorCommands[commandIndex + 1], commandsIgnoreShow[j + 1]); + commandIgnoreShow.shaderProgram = spStencil; + commandIgnoreShow.pass = Pass.CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW; + + commandIndex += 3; + } } function createPickCommands(classificationPrimitive, pickCommands) { @@ -665,7 +705,7 @@ define([ command.offset = offset; command.count = count; command.renderState = classificationPrimitive._rsStencilPreloadPass; - command.shaderProgram = classificationPrimitive._sp; + command.shaderProgram = classificationPrimitive._spStencil; command.uniformMap = uniformMap; command.pass = Pass.TERRAIN_CLASSIFICATION; @@ -682,7 +722,7 @@ define([ command.offset = offset; command.count = count; command.renderState = classificationPrimitive._rsStencilDepthPass; - command.shaderProgram = classificationPrimitive._sp; + command.shaderProgram = classificationPrimitive._spStencil; command.uniformMap = uniformMap; command.pass = Pass.TERRAIN_CLASSIFICATION; @@ -761,19 +801,21 @@ define([ var commandList = frameState.commandList; var passes = frameState.passes; + var i; var indices; var startIndex; var endIndex; var classificationType = classificationPrimitive.classificationType; if (passes.render) { + var colorCommand; var colorLength = colorCommands.length; indices = getCommandIndices(classificationType, colorLength); startIndex = indices.start; endIndex = indices.end; - for (var i = startIndex; i < endIndex; ++i) { - var colorCommand = colorCommands[i]; + for (i = startIndex; i < endIndex; ++i) { + colorCommand = colorCommands[i]; colorCommand.modelMatrix = modelMatrix; colorCommand.boundingVolume = boundingVolumes[boundingVolumeIndex(i, colorLength)]; colorCommand.cull = cull; @@ -781,6 +823,23 @@ define([ commandList.push(colorCommand); } + + if (frameState.invertClassification) { + var ignoreShowCommands = classificationPrimitive._commandsIgnoreShow; + startIndex = 0; + endIndex = ignoreShowCommands.length; + + for (i = startIndex; i < endIndex; ++i) { + var bvIndex = Math.floor(i / 2); + colorCommand = ignoreShowCommands[i]; + colorCommand.modelMatrix = modelMatrix; + colorCommand.boundingVolume = boundingVolumes[bvIndex]; + colorCommand.cull = cull; + colorCommand.debugShowBoundingVolume = debugShowBoundingVolume; + + commandList.push(colorCommand); + } + } } if (passes.pick) { @@ -790,9 +849,9 @@ define([ endIndex = indices.end; var pickOffsets = primitive._pickOffsets; - for (var j = startIndex; j < endIndex; ++j) { - var pickOffset = pickOffsets[boundingVolumeIndex(j, pickLength)]; - var pickCommand = pickCommands[j]; + for (i = startIndex; i < endIndex; ++i) { + var pickOffset = pickOffsets[boundingVolumeIndex(i, pickLength)]; + var pickCommand = pickCommands[i]; pickCommand.modelMatrix = modelMatrix; pickCommand.boundingVolume = boundingVolumes[pickOffset.index]; pickCommand.cull = cull; diff --git a/Source/Scene/CullingVolume.js b/Source/Scene/CullingVolume.js deleted file mode 100644 index 2df5d10254ec..000000000000 --- a/Source/Scene/CullingVolume.js +++ /dev/null @@ -1,21 +0,0 @@ -define([ - '../Core/CullingVolume', - '../Core/deprecationWarning' - ], function( - CullingVolume, - deprecationWarning) { - 'use strict'; - - function DeprecatedCullingVolume(planes) { - deprecationWarning('CullingVolume', 'Scene/CullingVolume is deprecated. It has moved to Core/CullingVolume in 1.36. Scene/CullingVolume will be removed in 1.38.'); - return new CullingVolume(planes); - } - - DeprecatedCullingVolume.fromBoundingSphere = CullingVolume.fromBoundingSphere; - - DeprecatedCullingVolume.MASK_OUTSIDE = CullingVolume.MASK_OUTSIDE; - DeprecatedCullingVolume.MASK_INSIDE = CullingVolume.MASK_INSIDE; - DeprecatedCullingVolume.MASK_INDETERMINATE = CullingVolume.MASK_INDETERMINATE; - - return DeprecatedCullingVolume; -}); diff --git a/Source/Scene/Expression.js b/Source/Scene/Expression.js index 479b4cd3b968..29d85c77f3ce 100644 --- a/Source/Scene/Expression.js +++ b/Source/Scene/Expression.js @@ -6,6 +6,7 @@ define([ '../Core/Color', '../Core/defined', '../Core/defineProperties', + '../Core/DeveloperError', '../Core/isArray', '../Core/Math', '../Core/RuntimeError', @@ -19,6 +20,7 @@ define([ Color, defined, defineProperties, + DeveloperError, isArray, CesiumMath, RuntimeError, @@ -1716,6 +1718,11 @@ define([ } break; case ExpressionNodeType.LITERAL_VECTOR: + //>>includeStart('debug', pragmas.debug); + if (!defined(left)) { + throw new DeveloperError('left should always be defined for type ExpressionNodeType.LITERAL_VECTOR'); + } + //>>includeEnd('debug'); var length = left.length; var vectorExpression = value + '('; for (var i = 0; i < length; ++i) { diff --git a/Source/Scene/FrameState.js b/Source/Scene/FrameState.js index 89e9d1343059..948a75d78637 100644 --- a/Source/Scene/FrameState.js +++ b/Source/Scene/FrameState.js @@ -296,6 +296,20 @@ define([ * @type {Number} */ this.minimumDisableDepthTestDistance = undefined; + + /** + * When false, 3D Tiles will render normally. When true, classified 3D Tile geometry will render normally and + * unclassified 3D Tile geometry will render with the color multiplied with {@link FrameState#invertClassificationColor}. + * @type {Boolean} + * @default false + */ + this.invertClassification = false; + + /** + * The highlight color of unclassified 3D Tile geometry when {@link FrameState#invertClassification} is true. + * @type {Color} + */ + this.invertClassificationColor = undefined; } /** diff --git a/Source/Scene/GetFeatureInfoFormat.js b/Source/Scene/GetFeatureInfoFormat.js index 83ff2f0545d5..1f169d46fd10 100644 --- a/Source/Scene/GetFeatureInfoFormat.js +++ b/Source/Scene/GetFeatureInfoFormat.js @@ -238,7 +238,9 @@ define([ break; } } - + if (!defined(layer)) { + throw new RuntimeError('Unable to find first child of the feature info xml document'); + } var featureMembers = layer.childNodes; for (var featureIndex = 0; featureIndex < featureMembers.length; ++featureIndex) { var featureMember = featureMembers[featureIndex]; 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/GroundPrimitive.js b/Source/Scene/GroundPrimitive.js index c024c6212fb3..de0224d2a979 100644 --- a/Source/Scene/GroundPrimitive.js +++ b/Source/Scene/GroundPrimitive.js @@ -597,7 +597,7 @@ define([ var boundingVolumes; if (frameState.mode === SceneMode.SCENE3D) { boundingVolumes = groundPrimitive._boundingVolumes; - } else if (frameState.mode !== SceneMode.SCENE3D && defined(groundPrimitive._boundingVolumes2D)) { + } else { boundingVolumes = groundPrimitive._boundingVolumes2D; } @@ -614,8 +614,11 @@ define([ startIndex = indices.start; endIndex = indices.end; - for (var i = startIndex; i < endIndex; ++i) { - var colorCommand = colorCommands[i]; + var i; + var colorCommand; + + for (i = startIndex; i < endIndex; ++i) { + colorCommand = colorCommands[i]; colorCommand.owner = groundPrimitive; colorCommand.modelMatrix = modelMatrix; colorCommand.boundingVolume = boundingVolumes[boundingVolumeIndex(i, colorLength)]; @@ -624,6 +627,23 @@ define([ commandList.push(colorCommand); } + + if (frameState.invertClassification) { + var ignoreShowCommands = groundPrimitive._primitive._commandsIgnoreShow; + startIndex = 0; + endIndex = ignoreShowCommands.length; + + for (i = startIndex; i < endIndex; ++i) { + var bvIndex = Math.floor(i / 2); + colorCommand = ignoreShowCommands[i]; + colorCommand.modelMatrix = modelMatrix; + colorCommand.boundingVolume = boundingVolumes[bvIndex]; + colorCommand.cull = cull; + colorCommand.debugShowBoundingVolume = debugShowBoundingVolume; + + commandList.push(colorCommand); + } + } } if (passes.pick) { diff --git a/Source/Scene/ImageryLayer.js b/Source/Scene/ImageryLayer.js index c03383ec04c1..839da40ee183 100644 --- a/Source/Scene/ImageryLayer.js +++ b/Source/Scene/ImageryLayer.js @@ -136,6 +136,14 @@ define([ * the gamma value to use for the tile. The function is executed for every * frame and for every tile, so it must be fast. * @param {ImagerySplitDirection|Function} [options.splitDirection=ImagerySplitDirection.NONE] The {@link ImagerySplitDirection} split to apply to this layer. + * @param {TextureMinificationFilter} [options.minificationFilter=TextureMinificationFilter.LINEAR] The + * texture minification filter to apply to this layer. Possible values + * are TextureMinificationFilter.LINEAR and + * TextureMinificationFilter.NEAREST. + * @param {TextureMagnificationFilter} [options.magnificationFilter=TextureMagnificationFilter.LINEAR] The + * texture minification filter to apply to this layer. Possible values + * are TextureMagnificationFilter.LINEAR and + * TextureMagnificationFilter.NEAREST. * @param {Boolean} [options.show=true] True if the layer is shown; otherwise, false. * @param {Number} [options.maximumAnisotropy=maximum supported] The maximum anisotropy level to use * for texture filtering. If this parameter is not specified, the maximum anisotropy supported @@ -211,6 +219,32 @@ define([ */ this.splitDirection = defaultValue(options.splitDirection, defaultValue(imageryProvider.defaultSplit, ImageryLayer.DEFAULT_SPLIT)); + /** + * The {@link TextureMinificationFilter} to apply to this layer. + * Possible values are {@link TextureMinificationFilter.LINEAR} (the default) + * and {@link TextureMinificationFilter.NEAREST}. + * + * To take effect, this property must be set immediately after adding the imagery layer. + * Once a texture is loaded it won't be possible to change the texture filter used. + * + * @type {TextureMinificationFilter} + * @default {@link ImageryLayer.DEFAULT_MINIFICATION_FILTER} + */ + this.minificationFilter = defaultValue(options.minificationFilter, defaultValue(imageryProvider.defaultMinificationFilter, ImageryLayer.DEFAULT_MINIFICATION_FILTER)); + + /** + * The {@link TextureMagnificationFilter} to apply to this layer. + * Possible values are {@link TextureMagnificationFilter.LINEAR} (the default) + * and {@link TextureMagnificationFilter.NEAREST}. + * + * To take effect, this property must be set immediately after adding the imagery layer. + * Once a texture is loaded it won't be possible to change the texture filter used. + * + * @type {TextureMagnificationFilter} + * @default {@link ImageryLayer.DEFAULT_MAGNIFICATION_FILTER} + */ + this.magnificationFilter = defaultValue(options.magnificationFilter, defaultValue(imageryProvider.defaultMagnificationFilter, ImageryLayer.DEFAULT_MAGNIFICATION_FILTER)); + /** * Determines if this layer is shown. * @@ -309,13 +343,29 @@ define([ ImageryLayer.DEFAULT_GAMMA = 1.0; /** - * This value is used as the default spliat for the imagery layer if one is not provided during construction + * This value is used as the default split for the imagery layer if one is not provided during construction * or by the imagery provider. * @type {ImagerySplitDirection} * @default ImagerySplitDirection.NONE */ ImageryLayer.DEFAULT_SPLIT = ImagerySplitDirection.NONE; + /** + * This value is used as the default texture minification filter for the imagery layer if one is not provided + * during construction or by the imagery provider. + * @type {TextureMinificationFilter} + * @default TextureMinificationFilter.LINEAR + */ + ImageryLayer.DEFAULT_MINIFICATION_FILTER = TextureMinificationFilter.LINEAR; + + /** + * This value is used as the default texture magnification filter for the imagery layer if one is not provided + * during construction or by the imagery provider. + * @type {TextureMagnificationFilter} + * @default TextureMagnificationFilter.LINEAR + */ + ImageryLayer.DEFAULT_MAGNIFICATION_FILTER = TextureMagnificationFilter.LINEAR; + /** * Gets a value indicating whether this layer is the base layer in the * {@link ImageryLayerCollection}. The base layer is the one that underlies all @@ -764,6 +814,11 @@ define([ } } + var sampler = new Sampler({ + minificationFilter : this.minificationFilter, + magnificationFilter : this.magnificationFilter + }); + // Imagery does not need to be discarded, so upload it to WebGL. var texture; if (defined(image.internalFormat)) { @@ -774,13 +829,15 @@ define([ height : image.height, source : { arrayBufferView : image.bufferView - } + }, + sampler : sampler }); } else { texture = new Texture({ context : context, source : image, - pixelFormat : imageryProvider.hasAlphaChannel ? PixelFormat.RGBA : PixelFormat.RGB + pixelFormat : imageryProvider.hasAlphaChannel ? PixelFormat.RGBA : PixelFormat.RGB, + sampler : sampler }); } @@ -793,30 +850,52 @@ define([ imagery.state = ImageryState.TEXTURE_LOADED; }; + function getSamplerKey(minificationFilter, magnificationFilter, maximumAnisotropy) { + return minificationFilter + ':' + magnificationFilter + ':' + maximumAnisotropy; + } + function finalizeReprojectTexture(imageryLayer, context, imagery, texture) { + var minificationFilter = imageryLayer.minificationFilter; + var magnificationFilter = imageryLayer.magnificationFilter; + var usesLinearTextureFilter = minificationFilter === TextureMinificationFilter.LINEAR && magnificationFilter === TextureMagnificationFilter.LINEAR; // Use mipmaps if this texture has power-of-two dimensions. - if (!PixelFormat.isCompressedFormat(texture.pixelFormat) && CesiumMath.isPowerOfTwo(texture.width) && CesiumMath.isPowerOfTwo(texture.height)) { - var mipmapSampler = context.cache.imageryLayer_mipmapSampler; + // In addition, mipmaps are only generated if the texture filters are both LINEAR. + if (usesLinearTextureFilter && !PixelFormat.isCompressedFormat(texture.pixelFormat) && CesiumMath.isPowerOfTwo(texture.width) && CesiumMath.isPowerOfTwo(texture.height)) { + minificationFilter = TextureMinificationFilter.LINEAR_MIPMAP_LINEAR; + var maximumSupportedAnisotropy = ContextLimits.maximumTextureFilterAnisotropy; + var maximumAnisotropy = Math.min(maximumSupportedAnisotropy, defaultValue(imageryLayer._maximumAnisotropy, maximumSupportedAnisotropy)); + var mipmapSamplerKey = getSamplerKey(minificationFilter, magnificationFilter, maximumAnisotropy); + var mipmapSamplers = context.cache.imageryLayerMipmapSamplers; + if (!defined(mipmapSamplers)) { + mipmapSamplers = {}; + context.cache.imageryLayerMipmapSamplers = mipmapSamplers; + } + var mipmapSampler = mipmapSamplers[mipmapSamplerKey]; if (!defined(mipmapSampler)) { - var maximumSupportedAnisotropy = ContextLimits.maximumTextureFilterAnisotropy; - mipmapSampler = context.cache.imageryLayer_mipmapSampler = new Sampler({ + mipmapSampler = mipmapSamplers[mipmapSamplerKey] = new Sampler({ wrapS : TextureWrap.CLAMP_TO_EDGE, wrapT : TextureWrap.CLAMP_TO_EDGE, - minificationFilter : TextureMinificationFilter.LINEAR_MIPMAP_LINEAR, - magnificationFilter : TextureMagnificationFilter.LINEAR, - maximumAnisotropy : Math.min(maximumSupportedAnisotropy, defaultValue(imageryLayer._maximumAnisotropy, maximumSupportedAnisotropy)) + minificationFilter : minificationFilter, + magnificationFilter : magnificationFilter, + maximumAnisotropy : maximumAnisotropy }); } texture.generateMipmap(MipmapHint.NICEST); texture.sampler = mipmapSampler; } else { - var nonMipmapSampler = context.cache.imageryLayer_nonMipmapSampler; + var nonMipmapSamplerKey = getSamplerKey(minificationFilter, magnificationFilter, 0); + var nonMipmapSamplers = context.cache.imageryLayerNonMipmapSamplers; + if (!defined(nonMipmapSamplers)) { + nonMipmapSamplers = {}; + context.cache.imageryLayerNonMipmapSamplers = nonMipmapSamplers; + } + var nonMipmapSampler = nonMipmapSamplers[nonMipmapSamplerKey]; if (!defined(nonMipmapSampler)) { - nonMipmapSampler = context.cache.imageryLayer_nonMipmapSampler = new Sampler({ + nonMipmapSampler = nonMipmapSamplers[nonMipmapSamplerKey] = new Sampler({ wrapS : TextureWrap.CLAMP_TO_EDGE, wrapT : TextureWrap.CLAMP_TO_EDGE, - minificationFilter : TextureMinificationFilter.LINEAR, - magnificationFilter : TextureMagnificationFilter.LINEAR + minificationFilter : minificationFilter, + magnificationFilter : magnificationFilter }); } texture.sampler = nonMipmapSampler; diff --git a/Source/Scene/ImageryProvider.js b/Source/Scene/ImageryProvider.js index 3cfdc11e9ace..efb784ee01fb 100644 --- a/Source/Scene/ImageryProvider.js +++ b/Source/Scene/ImageryProvider.js @@ -93,6 +93,22 @@ define([ */ this.defaultGamma = undefined; + /** + * The default texture minification filter to apply to this provider. + * + * @type {TextureMinificationFilter} + * @default undefined + */ + this.defaultMinificationFilter = undefined; + + /** + * The default texture magnification filter to apply to this provider. + * + * @type {TextureMagnificationFilter} + * @default undefined + */ + this.defaultMagnificationFilter = undefined; + DeveloperError.throwInstantiationError(); } diff --git a/Source/Scene/InvertClassification.js b/Source/Scene/InvertClassification.js new file mode 100644 index 000000000000..e0cfd4d6776f --- /dev/null +++ b/Source/Scene/InvertClassification.js @@ -0,0 +1,372 @@ +define([ + '../Core/Color', + '../Core/defined', + '../Core/defineProperties', + '../Core/destroyObject', + '../Core/PixelFormat', + '../Renderer/ClearCommand', + '../Renderer/Framebuffer', + '../Renderer/PixelDatatype', + '../Renderer/RenderState', + '../Renderer/Sampler', + '../Renderer/ShaderSource', + '../Renderer/Texture', + '../Renderer/TextureMagnificationFilter', + '../Renderer/TextureMinificationFilter', + '../Renderer/TextureWrap', + '../Shaders/PostProcessFilters/PassThrough', + './BlendingState', + './StencilFunction', + './StencilOperation' + ], function( + Color, + defined, + defineProperties, + destroyObject, + PixelFormat, + ClearCommand, + Framebuffer, + PixelDatatype, + RenderState, + Sampler, + ShaderSource, + Texture, + TextureMagnificationFilter, + TextureMinificationFilter, + TextureWrap, + PassThrough, + BlendingState, + StencilFunction, + StencilOperation) { + 'use strict'; + + /** + * @private + */ + function InvertClassification() { + this.previousFramebuffer = undefined; + this._previousFramebuffer = undefined; + + this._texture = undefined; + this._classifiedTexture = undefined; + this._depthStencilTexture = undefined; + this._fbo = undefined; + this._fboClassified = undefined; + + this._rsUnclassified = undefined; + this._rsClassified = undefined; + + this._unclassifiedCommand = undefined; + this._classifiedCommand = undefined; + this._translucentCommand = undefined; + + this._clearColorCommand = new ClearCommand({ + color : new Color(0.0, 0.0, 0.0, 0.0), + owner : this + }); + this._clearCommand = new ClearCommand({ + color : new Color(0.0, 0.0, 0.0, 0.0), + depth : 1.0, + stencil : 0 + }); + + var that = this; + this._uniformMap = { + u_texture : function() { + return that._texture; + }, + u_depth : function() { + return that._depthStencilTexture; + }, + u_classified : function() { + return that._classifiedTexture; + } + }; + } + + defineProperties(InvertClassification.prototype, { + unclassifiedCommand : { + get : function() { + return this._unclassifiedCommand; + } + } + }); + + InvertClassification.isTranslucencySupported = function(context) { + return context.depthTexture && context.fragmentDepth; + }; + + // The stencil mask only uses the least significant 4 bits. + // This is so 3D Tiles with the skip LOD optimization, which uses the most significant 4 bits, + // can be classified. + var stencilMask = 0x0F; + var stencilReference = 0; + + var rsUnclassified = { + depthMask : false, + stencilTest : { + enabled : true, + frontFunction : StencilFunction.EQUAL, + frontOperation : { + fail : StencilOperation.KEEP, + zFail : StencilOperation.KEEP, + zPass : StencilOperation.KEEP + }, + backFunction : StencilFunction.NEVER, + reference : stencilReference, + mask : stencilMask + }, + blending : BlendingState.ALPHA_BLEND + }; + + var rsClassified = { + depthMask : false, + stencilTest : { + enabled : true, + frontFunction : StencilFunction.NOT_EQUAL, + frontOperation : { + fail : StencilOperation.KEEP, + zFail : StencilOperation.KEEP, + zPass : StencilOperation.KEEP + }, + backFunction : StencilFunction.NEVER, + reference : stencilReference, + mask : stencilMask + }, + blending : BlendingState.ALPHA_BLEND + }; + + var rsDefault = { + depthMask : true, + depthTest : { + enabled : true + }, + blending : BlendingState.ALPHA_BLEND + }; + + var translucentFS = + '#extension GL_EXT_frag_depth : enable\n'+ + 'uniform sampler2D u_texture;\n' + + 'uniform sampler2D u_depth;\n' + + 'uniform sampler2D u_classified;\n' + + 'varying vec2 v_textureCoordinates;\n' + + 'void main()\n' + + '{\n' + + ' vec4 color = texture2D(u_texture, v_textureCoordinates);\n' + + ' if (color.a == 0.0)\n' + + ' {\n' + + ' discard;\n' + + ' }\n' + + ' bool isClassified = all(equal(texture2D(u_classified, v_textureCoordinates), vec4(0.0)));\n' + + '#ifdef UNCLASSIFIED\n' + + ' vec4 highlightColor = czm_invertClassificationColor;\n' + + ' if (isClassified)\n' + + ' {\n' + + ' discard;\n' + + ' }\n' + + '#else\n' + + ' vec4 highlightColor = vec4(1.0);\n' + + ' if (!isClassified)\n' + + ' {\n' + + ' discard;\n' + + ' }\n' + + '#endif\n' + + ' gl_FragColor = color * highlightColor;\n' + + ' gl_FragDepthEXT = texture2D(u_depth, v_textureCoordinates).r;\n' + + '}\n'; + + var opaqueFS = + 'uniform sampler2D u_texture;\n' + + 'varying vec2 v_textureCoordinates;\n' + + 'void main()\n' + + '{\n' + + ' vec4 color = texture2D(u_texture, v_textureCoordinates);\n' + + ' if (color.a == 0.0)\n' + + ' {\n' + + ' discard;\n' + + ' }\n' + + '#ifdef UNCLASSIFIED\n' + + ' gl_FragColor = color * czm_invertClassificationColor;\n' + + '#else\n' + + ' gl_FragColor = color;\n' + + '#endif\n' + + '}\n'; + + InvertClassification.prototype.update = function(context) { + var texture = this._texture; + var previousFramebufferChanged = !defined(texture) || this.previousFramebuffer !== this._previousFramebuffer; + this._previousFramebuffer = this.previousFramebuffer; + + var width = context.drawingBufferWidth; + var height = context.drawingBufferHeight; + + var textureChanged = !defined(texture) || texture.width !== width || texture.height !== height; + if (textureChanged || previousFramebufferChanged) { + this._texture = this._texture && this._texture.destroy(); + this._classifiedTexture = this._classifiedTexture && this._classifiedTexture.destroy(); + this._depthStencilTexture = this._depthStencilTexture && this._depthStencilTexture.destroy(); + + this._texture = new Texture({ + context : context, + width : width, + height : height, + pixelFormat : PixelFormat.RGBA, + pixelDatatype : PixelDatatype.UNSIGNED_BYTE, + sampler : new Sampler({ + wrapS : TextureWrap.CLAMP_TO_EDGE, + wrapT : TextureWrap.CLAMP_TO_EDGE, + minificationFilter : TextureMinificationFilter.LINEAR, + magnificationFilter : TextureMagnificationFilter.LINEAR + }) + }); + + if (previousFramebufferChanged && !defined(this._previousFramebuffer)) { + this._classifiedTexture = new Texture({ + context : context, + width : width, + height : height, + pixelFormat : PixelFormat.RGBA, + pixelDatatype : PixelDatatype.UNSIGNED_BYTE, + sampler : new Sampler({ + wrapS : TextureWrap.CLAMP_TO_EDGE, + wrapT : TextureWrap.CLAMP_TO_EDGE, + minificationFilter : TextureMinificationFilter.LINEAR, + magnificationFilter : TextureMagnificationFilter.LINEAR + }) + }); + this._depthStencilTexture = new Texture({ + context : context, + width : width, + height : height, + pixelFormat : PixelFormat.DEPTH_STENCIL, + pixelDatatype : PixelDatatype.UNSIGNED_INT_24_8 + }); + } + } + + if (!defined(this._fbo) || textureChanged || previousFramebufferChanged) { + this._fbo = this._fbo && this._fbo.destroy(); + this._fboClassified = this._fboClassified && this._fboClassified.destroy(); + + var depthStencilTexture; + var depthStencilRenderbuffer; + if (defined(this._previousFramebuffer)) { + depthStencilTexture = this._previousFramebuffer.depthStencilTexture; + depthStencilRenderbuffer = this._previousFramebuffer.depthStencilRenderbuffer; + } else { + depthStencilTexture = this._depthStencilTexture; + } + + this._fbo = new Framebuffer({ + context : context, + colorTextures : [this._texture], + depthStencilTexture : depthStencilTexture, + depthStencilRenderbuffer : depthStencilRenderbuffer, + destroyAttachments : false + }); + + if (!defined(this._previousFramebuffer)) { + this._fboClassified = new Framebuffer({ + context : context, + colorTextures : [this._classifiedTexture], + depthStencilTexture : depthStencilTexture, + destroyAttachments : false + }); + } + } + + if (!defined(this._rsUnclassified)) { + this._rsUnclassified = RenderState.fromCache(rsUnclassified); + this._rsClassified = RenderState.fromCache(rsClassified); + this._rsDefault = RenderState.fromCache(rsDefault); + } + + if (!defined(this._unclassifiedCommand) || previousFramebufferChanged) { + if (defined(this._unclassifiedCommand)) { + this._unclassifiedCommand.shaderProgram = this._unclassifiedCommand.shaderProgram && this._unclassifiedCommand.shaderProgram.destroy(); + this._classifiedCommand.shaderProgram = this._classifiedCommand.shaderProgram && this._classifiedCommand.shaderProgram.destroy(); + } + + var fs = defined(this._previousFramebuffer) ? opaqueFS : translucentFS; + var unclassifiedFSSource = new ShaderSource({ + defines : ['UNCLASSIFIED'], + sources : [fs] + }); + var classifiedFSSource = new ShaderSource({ + sources : [fs] + }); + this._unclassifiedCommand = context.createViewportQuadCommand(unclassifiedFSSource, { + renderState : defined(this._previousFramebuffer) ? this._rsUnclassified : this._rsDefault, + uniformMap : this._uniformMap, + owner : this + }); + this._classifiedCommand = context.createViewportQuadCommand(classifiedFSSource, { + renderState : defined(this._previousFramebuffer) ? this._rsClassified : this._rsDefault, + uniformMap : this._uniformMap, + owner : this + }); + + if (defined(this._translucentCommand)) { + this._translucentCommand.shaderProgram = this._translucentCommand.shaderProgram && this._translucentCommand.shaderProgram.destroy(); + } + if (!defined(this._previousFramebuffer)) { + this._translucentCommand = context.createViewportQuadCommand(PassThrough, { + renderState : this._rsUnclassified, + uniformMap : this._uniformMap, + owner : this + }); + } + } + }; + + InvertClassification.prototype.clear = function(context, passState) { + var framebuffer = passState.framebuffer; + + if (defined(this._previousFramebuffer)) { + passState.framebuffer = this._fbo; + this._clearColorCommand.execute(context, passState); + } else { + passState.framebuffer = this._fbo; + this._clearCommand.execute(context, passState); + passState.framebuffer = this._fboClassified; + this._clearCommand.execute(context, passState); + } + + passState.framebuffer = framebuffer; + }; + + InvertClassification.prototype.executeClassified = function(context, passState) { + if (!defined(this._previousFramebuffer)) { + var framebuffer = passState.framebuffer; + + passState.framebuffer = this._fboClassified; + this._translucentCommand.execute(context, passState); + + passState.framebuffer = framebuffer; + } + this._classifiedCommand.execute(context, passState); + }; + + InvertClassification.prototype.executeUnclassified = function(context, passState) { + this._unclassifiedCommand.execute(context, passState); + }; + + InvertClassification.prototype.isDestroyed = function() { + return false; + }; + + InvertClassification.prototype.destroy = function() { + this._fbo = this._fbo && this._fbo.destroy(); + this._texture = this._texture && this._texture.destroy(); + this._depthStencilTexture = this._depthStencilTexture && this._depthStencilTexture.destroy(); + + if (defined(this._unclassifiedCommand)) { + this._unclassifiedCommand.shaderProgram = this._unclassifiedCommand.shaderProgram && this._unclassifiedCommand.shaderProgram.destroy(); + this._classifiedCommand.shaderProgram = this._classifiedCommand.shaderProgram && this._classifiedCommand.shaderProgram.destroy(); + } + + return destroyObject(this); + }; + + return InvertClassification; +}); diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js index 5001d1c5c14d..a8432665400d 100644 --- a/Source/Scene/Model.js +++ b/Source/Scene/Model.js @@ -2306,16 +2306,16 @@ define([ sampler : sampler, flipY : false }); - } - // GLTF_SPEC: Support TEXTURE_CUBE_MAP. https://github.com/KhronosGroup/glTF/issues/40 - - if (mipmap) { - tx.generateMipmap(); + // GLTF_SPEC: Support TEXTURE_CUBE_MAP. https://github.com/KhronosGroup/glTF/issues/40 + if (mipmap) { + tx.generateMipmap(); + } } } - - model._rendererResources.textures[gltfTexture.id] = tx; - model._texturesByteLength += tx.sizeInBytes; + if (defined(tx)) { + model._rendererResources.textures[gltfTexture.id] = tx; + model._texturesByteLength += tx.sizeInBytes; + } } var scratchCreateTextureJob = new CreateTextureJob(); diff --git a/Source/Scene/OIT.js b/Source/Scene/OIT.js index ba47d94211eb..c7a38d68700d 100644 --- a/Source/Scene/OIT.js +++ b/Source/Scene/OIT.js @@ -441,20 +441,20 @@ define([ // shader compilation errors. fs.sources.splice(0, 0, - (source.indexOf('gl_FragData') !== -1 ? '#extension GL_EXT_draw_buffers : enable \n' : '') + - 'vec4 czm_gl_FragColor;\n' + - 'bool czm_discard = false;\n'); + (source.indexOf('gl_FragData') !== -1 ? '#extension GL_EXT_draw_buffers : enable \n' : '') + + 'vec4 czm_gl_FragColor;\n' + + 'bool czm_discard = false;\n'); fs.sources.push( - 'void main()\n' + - '{\n' + - ' czm_translucent_main();\n' + - ' if (czm_discard)\n' + - ' {\n' + - ' discard;\n' + - ' }\n' + - source + - '}\n'); + 'void main()\n' + + '{\n' + + ' czm_translucent_main();\n' + + ' if (czm_discard)\n' + + ' {\n' + + ' discard;\n' + + ' }\n' + + source + + '}\n'); shader = context.shaderCache.createDerivedShaderProgram(shaderProgram, keyword, { vertexShaderSource : shaderProgram.vertexShaderSource, @@ -533,7 +533,7 @@ define([ return result; }; - function executeTranslucentCommandsSortedMultipass(oit, scene, executeFunction, passState, commands) { + function executeTranslucentCommandsSortedMultipass(oit, scene, executeFunction, passState, commands, invertClassification) { var command; var derivedCommand; var j; @@ -558,6 +558,12 @@ define([ executeFunction(derivedCommand, scene, context, passState, debugFramebuffer); } + if (defined(invertClassification)) { + command = invertClassification.unclassifiedCommand; + derivedCommand = (shadowsEnabled && command.receiveShadows) ? command.derivedCommands.oit.shadows.translucentCommand : command.derivedCommands.oit.translucentCommand; + executeFunction(derivedCommand, scene, context, passState, debugFramebuffer); + } + passState.framebuffer = oit._alphaFBO; for (j = 0; j < length; ++j) { @@ -566,10 +572,16 @@ define([ executeFunction(derivedCommand, scene, context, passState, debugFramebuffer); } + if (defined(invertClassification)) { + command = invertClassification.unclassifiedCommand; + derivedCommand = (shadowsEnabled && command.receiveShadows) ? command.derivedCommands.oit.shadows.alphaCommand : command.derivedCommands.oit.alphaCommand; + executeFunction(derivedCommand, scene, context, passState, debugFramebuffer); + } + passState.framebuffer = framebuffer; } - function executeTranslucentCommandsSortedMRT(oit, scene, executeFunction, passState, commands) { + function executeTranslucentCommandsSortedMRT(oit, scene, executeFunction, passState, commands, invertClassification) { var context = scene.context; var framebuffer = passState.framebuffer; var length = commands.length; @@ -582,22 +594,31 @@ define([ var debugFramebuffer = oit._opaqueFBO; passState.framebuffer = oit._translucentFBO; + var command; + var derivedCommand; + for (var j = 0; j < length; ++j) { - var command = commands[j]; - var derivedCommand = (shadowsEnabled && command.receiveShadows) ? command.derivedCommands.oit.shadows.translucentCommand : command.derivedCommands.oit.translucentCommand; + command = commands[j]; + derivedCommand = (shadowsEnabled && command.receiveShadows) ? command.derivedCommands.oit.shadows.translucentCommand : command.derivedCommands.oit.translucentCommand; + executeFunction(derivedCommand, scene, context, passState, debugFramebuffer); + } + + if (defined(invertClassification)) { + command = invertClassification.unclassifiedCommand; + derivedCommand = (shadowsEnabled && command.receiveShadows) ? command.derivedCommands.oit.shadows.translucentCommand : command.derivedCommands.oit.translucentCommand; executeFunction(derivedCommand, scene, context, passState, debugFramebuffer); } passState.framebuffer = framebuffer; } - OIT.prototype.executeCommands = function(scene, executeFunction, passState, commands) { + OIT.prototype.executeCommands = function(scene, executeFunction, passState, commands, invertClassification) { if (this._translucentMRTSupport) { - executeTranslucentCommandsSortedMRT(this, scene, executeFunction, passState, commands); + executeTranslucentCommandsSortedMRT(this, scene, executeFunction, passState, commands, invertClassification); return; } - executeTranslucentCommandsSortedMultipass(this, scene, executeFunction, passState, commands); + executeTranslucentCommandsSortedMultipass(this, scene, executeFunction, passState, commands, invertClassification); }; OIT.prototype.execute = function(context, passState) { diff --git a/Source/Scene/OrthographicFrustum.js b/Source/Scene/OrthographicFrustum.js deleted file mode 100644 index bbb36ec006ac..000000000000 --- a/Source/Scene/OrthographicFrustum.js +++ /dev/null @@ -1,15 +0,0 @@ -define([ - '../Core/deprecationWarning', - '../Core/OrthographicFrustum' - ], function( - deprecationWarning, - OrthographicFrustum) { - 'use strict'; - - function DeprecatedOrthographicFrustum(options) { - deprecationWarning('OrthographicFrustum', 'Scene/OrthographicFrustum is deprecated. It has moved to Core/OrthographicFrustum in 1.36. Scene/OrthographicFrustum will be removed in 1.38.'); - return new OrthographicFrustum(options); - } - - return DeprecatedOrthographicFrustum; -}); diff --git a/Source/Scene/OrthographicOffCenterFrustum.js b/Source/Scene/OrthographicOffCenterFrustum.js deleted file mode 100644 index 54d53cf14321..000000000000 --- a/Source/Scene/OrthographicOffCenterFrustum.js +++ /dev/null @@ -1,15 +0,0 @@ -define([ - '../Core/deprecationWarning', - '../Core/OrthographicOffCenterFrustum' - ], function( - deprecationWarning, - OrthographicOffCenterFrustum) { - 'use strict'; - - function DeprecatedOrthographicOffCenterFrustum(options) { - deprecationWarning('OrthographicOffCenterFrustum', 'Scene/OrthographicOffCenterFrustum is deprecated. It has moved to Core/OrthographicOffCenterFrustum in 1.36. Scene/OrthographicOffCenterFrustum will be removed in 1.38.'); - return new OrthographicOffCenterFrustum(options); - } - - return DeprecatedOrthographicOffCenterFrustum; -}); diff --git a/Source/Scene/PerspectiveFrustum.js b/Source/Scene/PerspectiveFrustum.js deleted file mode 100644 index 5030940f5c5c..000000000000 --- a/Source/Scene/PerspectiveFrustum.js +++ /dev/null @@ -1,15 +0,0 @@ -define([ - '../Core/deprecationWarning', - '../Core/PerspectiveFrustum' - ], function( - deprecationWarning, - PerspectiveFrustum) { - 'use strict'; - - function DeprecatedPerspectiveFrustum(options) { - deprecationWarning('PerspectiveFrustum', 'Scene/PerspectiveFrustum is deprecated. It has moved to Core/PerspectiveFrustum in 1.36. Scene/PerspectiveFrustum will be removed in 1.38.'); - return new PerspectiveFrustum(options); - } - - return DeprecatedPerspectiveFrustum; -}); diff --git a/Source/Scene/PerspectiveOffCenterFrustum.js b/Source/Scene/PerspectiveOffCenterFrustum.js deleted file mode 100644 index e8496b4ef925..000000000000 --- a/Source/Scene/PerspectiveOffCenterFrustum.js +++ /dev/null @@ -1,15 +0,0 @@ -define([ - '../Core/deprecationWarning', - '../Core/PerspectiveOffCenterFrustum' - ], function( - deprecationWarning, - PerspectiveOffCenterFrustum) { - 'use strict'; - - function DeprecatedPerspectiveOffCenterFrustum(options) { - deprecationWarning('PerspectiveOffCenterFrustum', 'Scene/PerspectiveOffCenterFrustum is deprecated. It has moved to Core/PerspectiveOffCenterFrustum in 1.36. Scene/PerspectiveOffCenterFrustum will be removed in 1.38.'); - return new PerspectiveOffCenterFrustum(options); - } - - return DeprecatedPerspectiveOffCenterFrustum; -}); diff --git a/Source/Scene/PointCloud3DTileContent.js b/Source/Scene/PointCloud3DTileContent.js index 7e447c28412f..d82a88667bb4 100644 --- a/Source/Scene/PointCloud3DTileContent.js +++ b/Source/Scene/PointCloud3DTileContent.js @@ -1018,11 +1018,13 @@ define([ if (hasNormals && backFaceCulling) { vs += ' float visible = step(-normal.z, 0.0); \n' + - ' gl_Position *= visible; \n'; + ' gl_Position *= visible; \n' + + ' gl_PointSize *= visible; \n'; } if (hasShowStyle) { - vs += ' gl_Position *= show; \n'; + vs += ' gl_Position *= show; \n' + + ' gl_PointSize *= show; \n'; } vs += '} \n'; diff --git a/Source/Scene/PolylineCollection.js b/Source/Scene/PolylineCollection.js index c35652348eba..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) { @@ -1457,7 +1467,7 @@ define([ for ( var j = 0; j < numberOfSegments; ++j) { var segmentLength = segments[j] - 1.0; for ( var k = 0; k < segmentLength; ++k) { - if (indicesCount + 4 >= CesiumMath.SIXTY_FOUR_KILOBYTES - 2) { + if (indicesCount + 4 > CesiumMath.SIXTY_FOUR_KILOBYTES) { polyline._locatorBuckets.push({ locator : bucketLocator, count : segmentIndexCount @@ -1489,7 +1499,7 @@ define([ count : segmentIndexCount }); - if (indicesCount + 4 >= CesiumMath.SIXTY_FOUR_KILOBYTES - 2) { + if (indicesCount + 4 > CesiumMath.SIXTY_FOUR_KILOBYTES) { vertexBufferOffset.push(0); indices = []; totalIndices.push(indices); diff --git a/Source/Scene/PrimitivePipeline.js b/Source/Scene/PrimitivePipeline.js index 53fe041e8e81..353a6a2e072a 100644 --- a/Source/Scene/PrimitivePipeline.js +++ b/Source/Scene/PrimitivePipeline.js @@ -272,19 +272,18 @@ define([ var attributeLocations; var instances = parameters.instances; var length = instances.length; + var pickOffsets; if (length > 0) { geometries = geometryPipeline(parameters); if (geometries.length > 0) { attributeLocations = GeometryPipeline.createAttributeLocations(geometries[0]); + if (parameters.createPickOffsets) { + pickOffsets = createInstancePickOffsets(instances, geometries); + } } } - var pickOffsets; - if (parameters.createPickOffsets && geometries.length > 0) { - pickOffsets = createInstancePickOffsets(instances, geometries); - } - var boundingSpheres = new Array(length); var boundingSpheresCV = new Array(length); for (var i = 0; i < length; ++i) { 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 2e649fa00944..6329d5364404 100644 --- a/Source/Scene/Scene.js +++ b/Source/Scene/Scene.js @@ -63,6 +63,7 @@ define([ './FrustumCommands', './FXAA', './GlobeDepth', + './InvertClassification', './JobScheduler', './MapMode2D', './OIT', @@ -143,6 +144,7 @@ define([ FrustumCommands, FXAA, GlobeDepth, + InvertClassification, JobScheduler, MapMode2D, OIT, @@ -631,6 +633,38 @@ define([ enabled : defaultValue(options.shadows, false) }); + /** + * When false, 3D Tiles will render normally. When true, classified 3D Tile geometry will render normally and + * unclassified 3D Tile geometry will render with the color multiplied by {@link Scene#invertClassificationColor}. + * @type {Boolean} + * @default false + */ + this.invertClassification = false; + + /** + * The highlight color of unclassified 3D Tile geometry when {@link Scene#invertClassification} is true. + *

When the color's alpha is less than 1.0, the unclassified portions of the 3D Tiles will not blend correctly with the classified positions of the 3D Tiles.

+ *

Also, when the color's alpha is less than 1.0, the WEBGL_depth_texture and EXT_frag_depth WebGL extensions must be supported.

+ * @type {Color} + * @default Color.WHITE + */ + this.invertClassificationColor = Color.clone(Color.WHITE); + + 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); @@ -666,7 +700,8 @@ define([ originalFramebuffer : undefined, useGlobeDepthFramebuffer : false, useOIT : false, - useFXAA : false + useFXAA : false, + useInvertClassification : false }; this._useWebVR = false; @@ -1164,7 +1199,7 @@ define([ } }, - /** + /** * Gets or sets the position of the Imagery splitter within the viewport. Valid values are between 0.0 and 1.0. * @memberof Scene.prototype * @@ -1229,10 +1264,10 @@ define([ Cartesian3.multiplyByScalar(camera0.position, scalar, scratchPosition0); Cartesian3.multiplyByScalar(camera1.position, scalar, scratchPosition1); return Cartesian3.equalsEpsilon(scratchPosition0, scratchPosition1, epsilon) && - Cartesian3.equalsEpsilon(camera0.direction, camera1.direction, epsilon) && - Cartesian3.equalsEpsilon(camera0.up, camera1.up, epsilon) && - Cartesian3.equalsEpsilon(camera0.right, camera1.right, epsilon) && - Matrix4.equalsEpsilon(camera0.transform, camera1.transform, epsilon); + Cartesian3.equalsEpsilon(camera0.direction, camera1.direction, epsilon) && + Cartesian3.equalsEpsilon(camera0.up, camera1.up, epsilon) && + Cartesian3.equalsEpsilon(camera0.right, camera1.right, epsilon) && + Matrix4.equalsEpsilon(camera0.transform, camera1.transform, epsilon); } function updateDerivedCommands(scene, command) { @@ -1315,6 +1350,15 @@ define([ frameState.occluder = getOccluder(scene); frameState.terrainExaggeration = scene._terrainExaggeration; frameState.minimumDisableDepthTestDistance = scene._minimumDisableDepthTestDistance; + frameState.invertClassification = scene.invertClassification; + + scene._actualInvertClassificationColor = Color.clone(scene.invertClassificationColor, scene._actualInvertClassificationColor); + if (!InvertClassification.isTranslucencySupported(scene._context)) { + scene._actualInvertClassificationColor.alpha = 1.0; + } + + frameState.invertClassificationColor = scene._actualInvertClassificationColor; + if (defined(scene.globe)) { frameState.maximumScreenSpaceError = scene.globe.maximumScreenSpaceError; } else { @@ -1767,11 +1811,15 @@ define([ return b.boundingVolume.distanceSquaredTo(position) - a.boundingVolume.distanceSquaredTo(position); } - function executeTranslucentCommandsSorted(scene, executeFunction, passState, commands) { + function executeTranslucentCommandsSorted(scene, executeFunction, passState, commands, invertClassification) { var context = scene.context; mergeSort(commands, translucentCompare, scene._camera.positionWC); + if (defined(invertClassification)) { + executeFunction(invertClassification.unclassifiedCommand, scene, context, passState); + } + var length = commands.length; for (var j = 0; j < length; ++j) { executeFunction(commands[j], scene, context, passState); @@ -1870,8 +1918,8 @@ define([ var executeTranslucentCommands; if (environmentState.useOIT) { if (!defined(scene._executeOITFunction)) { - scene._executeOITFunction = function(scene, executeFunction, passState, commands) { - scene._oit.executeCommands(scene, executeFunction, passState, commands); + scene._executeOITFunction = function(scene, executeFunction, passState, commands, invertClassification) { + scene._oit.executeCommands(scene, executeFunction, passState, commands, invertClassification); }; } executeTranslucentCommands = scene._executeOITFunction; @@ -1919,6 +1967,7 @@ define([ } clearDepth.execute(context, passState); + scene._stencilClearCommand.execute(context, passState); us.updatePass(Pass.GLOBE); var commands = frustumCommands.commands[Pass.GLOBE]; @@ -1947,31 +1996,112 @@ define([ clearDepth.execute(context, passState); } - us.updatePass(Pass.CESIUM_3D_TILE); - commands = frustumCommands.commands[Pass.CESIUM_3D_TILE]; - length = frustumCommands.indices[Pass.CESIUM_3D_TILE]; - for (j = 0; j < length; ++j) { - executeCommand(commands[j], scene, context, passState); + if (!environmentState.useInvertClassification || picking) { + // Common/fastest path. Draw 3D Tiles and classification normally. + + // Draw 3D Tiles + us.updatePass(Pass.CESIUM_3D_TILE); + commands = frustumCommands.commands[Pass.CESIUM_3D_TILE]; + length = frustumCommands.indices[Pass.CESIUM_3D_TILE]; + for (j = 0; j < length; ++j) { + executeCommand(commands[j], scene, context, passState); + } + + // Draw classifications. Modifies 3D Tiles color. + us.updatePass(Pass.CESIUM_3D_TILE_CLASSIFICATION); + commands = frustumCommands.commands[Pass.CESIUM_3D_TILE_CLASSIFICATION]; + length = frustumCommands.indices[Pass.CESIUM_3D_TILE_CLASSIFICATION]; + for (j = 0; j < length; ++j) { + executeCommand(commands[j], scene, context, passState); + } + } else { + // When the invert classification color is opaque: + // Main FBO (FBO1): Main_Color + Main_DepthStencil + // Invert classification FBO (FBO2) : Invert_Color + Main_DepthStencil + // + // 1. Clear FBO2 color to vec4(0.0) for each frustum + // 2. Draw 3D Tiles to FBO2 + // 3. Draw classification to FBO2 + // 4. Fullscreen pass to FBO1, draw Invert_Color when: + // * Main_DepthStencil has the stencil bit set > 0 (classified) + // 5. Fullscreen pass to FBO1, draw Invert_Color * czm_invertClassificationColor when: + // * Main_DepthStencil has stencil bit set to 0 (unclassified) and + // * Invert_Color !== vec4(0.0) + // + // When the invert classification color is translucent: + // Main FBO (FBO1): Main_Color + Main_DepthStencil + // Invert classification FBO (FBO2): Invert_Color + Invert_DepthStencil + // IsClassified FBO (FBO3): IsClassified_Color + Invert_DepthStencil + // + // 1. Clear FBO2 and FBO3 color to vec4(0.0), stencil to 0, and depth to 1.0 + // 2. Draw 3D Tiles to FBO2 + // 3. Draw classification to FBO2 + // 4. Fullscreen pass to FBO3, draw any color when + // * Invert_DepthStencil has the stencil bit set > 0 (classified) + // 5. Fullscreen pass to FBO1, draw Invert_Color when: + // * Invert_Color !== vec4(0.0) and + // * IsClassified_Color !== vec4(0.0) + // 6. Fullscreen pass to FBO1, draw Invert_Color * czm_invertClassificationColor when: + // * Invert_Color !== vec4(0.0) and + // * IsClassified_Color === vec4(0.0) + // + // NOTE: Step six when translucent invert color occurs after the TRANSLUCENT pass + // + scene._invertClassification.clear(context, passState); + + var opaqueClassificationFramebuffer = passState.framebuffer; + passState.framebuffer = scene._invertClassification._fbo; + + // Draw normally + us.updatePass(Pass.CESIUM_3D_TILE); + commands = frustumCommands.commands[Pass.CESIUM_3D_TILE]; + length = frustumCommands.indices[Pass.CESIUM_3D_TILE]; + for (j = 0; j < length; ++j) { + executeCommand(commands[j], scene, context, passState); + } + + // Set stencil + us.updatePass(Pass.CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW); + commands = frustumCommands.commands[Pass.CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW]; + length = frustumCommands.indices[Pass.CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW]; + for (j = 0; j < length; ++j) { + executeCommand(commands[j], scene, context, passState); + } + + passState.framebuffer = opaqueClassificationFramebuffer; + + // Fullscreen pass to copy classified fragments + scene._invertClassification.executeClassified(context, passState); + if (scene.frameState.invertClassificationColor.alpha === 1.0) { + // Fullscreen pass to copy unclassified fragments when alpha == 1.0 + scene._invertClassification.executeUnclassified(context, passState); + } + + // Clear stencil set by the classification for the next classification pass + if (length > 0 && context.stencilBuffer) { + scene._stencilClearCommand.execute(context, passState); + } + + // Draw style over classification. + us.updatePass(Pass.CESIUM_3D_TILE_CLASSIFICATION); + commands = frustumCommands.commands[Pass.CESIUM_3D_TILE_CLASSIFICATION]; + length = frustumCommands.indices[Pass.CESIUM_3D_TILE_CLASSIFICATION]; + for (j = 0; j < length; ++j) { + executeCommand(commands[j], scene, context, passState); + } } if (length > 0 && context.stencilBuffer) { scene._stencilClearCommand.execute(context, passState); } - us.updatePass(Pass.CESIUM_3D_TILE_CLASSIFICATION); - commands = frustumCommands.commands[Pass.CESIUM_3D_TILE_CLASSIFICATION]; - length = frustumCommands.indices[Pass.CESIUM_3D_TILE_CLASSIFICATION]; - for (j = 0; j < length; ++j) { - executeCommand(commands[j], scene, context, passState); - } - if (clearGlobeDepth && useDepthPlane) { depthPlane.execute(context, passState); } // Execute commands in order by pass up to the translucent pass. // Translucent geometry needs special handling (sorting/OIT). - var startPass = Pass.CESIUM_3D_TILE_CLASSIFICATION + 1; + var startPass = Pass.CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW + 1; var endPass = Pass.TRANSLUCENT; for (var pass = startPass; pass < endPass; ++pass) { us.updatePass(pass); @@ -1988,10 +2118,17 @@ define([ us.updateFrustum(frustum); } + var invertClassification; + if (!picking && environmentState.useInvertClassification && scene.frameState.invertClassificationColor.alpha < 1.0) { + // Fullscreen pass to copy unclassified fragments when alpha < 1.0. + // Not executed when undefined. + invertClassification = scene._invertClassification; + } + us.updatePass(Pass.TRANSLUCENT); commands = frustumCommands.commands[Pass.TRANSLUCENT]; commands.length = frustumCommands.indices[Pass.TRANSLUCENT]; - executeTranslucentCommands(scene, executeCommand, passState, commands); + executeTranslucentCommands(scene, executeCommand, passState, commands, invertClassification); if (defined(globeDepth) && (environmentState.useGlobeDepthFramebuffer || depthOnly) && scene.useDepthPicking) { // PERFORMANCE_IDEA: Use MRT to avoid the extra copy. @@ -2157,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; @@ -2528,6 +2665,28 @@ define([ if (defined(passState.framebuffer)) { clear.execute(context, passState); } + + var useInvertClassification = environmentState.useInvertClassification = defined(passState.framebuffer) && scene.invertClassification; + if (useInvertClassification) { + var depthFramebuffer; + if (scene.frameState.invertClassificationColor.alpha === 1.0) { + if (environmentState.useGlobeDepthFramebuffer) { + depthFramebuffer = scene._globeDepth.framebuffer; + } else if (environmentState.useFXAA) { + depthFramebuffer = scene._fxaa.getColorFramebuffer(); + } + } + + scene._invertClassification.previousFramebuffer = depthFramebuffer; + scene._invertClassification.update(context); + scene._invertClassification.clear(context, passState); + + if (scene.frameState.invertClassificationColor.alpha < 1.0 && useOIT) { + var command = scene._invertClassification.unclassifiedCommand; + var derivedCommands = command.derivedCommands; + derivedCommands.oit = scene._oit.createDerivedCommands(command, context, derivedCommands.oit); + } + } } function resolveFramebuffers(scene, passState) { @@ -2860,6 +3019,7 @@ define([ // Update with previous frame's number and time, assuming that render is called before picking. updateFrameState(this, frameState.frameNumber, frameState.time); frameState.cullingVolume = getPickCullingVolume(this, drawingBufferPosition, rectangleWidth, rectangleHeight); + frameState.invertClassification = false; frameState.passes.pick = true; us.update(frameState); @@ -3377,7 +3537,7 @@ define([ return destroyObject(this); }; - /** + /** * Transforms a position in cartesian coordinates to canvas coordinates. This is commonly used to place an * HTML element at the same screen position as an object in the scene. * 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/Source/Scene/createTileMapServiceImageryProvider.js b/Source/Scene/createTileMapServiceImageryProvider.js index 15b971f504a8..5eb5d03a6bf8 100644 --- a/Source/Scene/createTileMapServiceImageryProvider.js +++ b/Source/Scene/createTileMapServiceImageryProvider.js @@ -129,6 +129,16 @@ define([ } } + var message; + if (!defined(tilesets) || !defined(bbox)) { + message = 'Unable to find expected tilesets or bbox attributes in ' + joinUrls(url, 'tilemapresource.xml') + '.'; + metadataError = TileProviderError.handleError(metadataError, imageryProvider, imageryProvider.errorEvent, message, undefined, undefined, undefined, requestMetadata); + if(!metadataError.retry) { + deferred.reject(new RuntimeError(message)); + } + return; + } + var fileExtension = defaultValue(options.fileExtension, format.getAttribute('extension')); var tileWidth = defaultValue(options.tileWidth, parseInt(format.getAttribute('width'), 10)); var tileHeight = defaultValue(options.tileHeight, parseInt(format.getAttribute('height'), 10)); @@ -143,7 +153,7 @@ define([ } else if (tilingSchemeName === 'mercator' || tilingSchemeName === 'global-mercator') { tilingScheme = new WebMercatorTilingScheme({ ellipsoid : options.ellipsoid }); } else { - var message = joinUrls(url, 'tilemapresource.xml') + 'specifies an unsupported profile attribute, ' + tilingSchemeName + '.'; + message = joinUrls(url, 'tilemapresource.xml') + 'specifies an unsupported profile attribute, ' + tilingSchemeName + '.'; metadataError = TileProviderError.handleError(metadataError, imageryProvider, imageryProvider.errorEvent, message, undefined, undefined, undefined, requestMetadata); if(!metadataError.retry) { deferred.reject(new RuntimeError(message)); diff --git a/Source/Shaders/Builtin/Constants/passCesium3DTileClassificationIgnoreShow.glsl b/Source/Shaders/Builtin/Constants/passCesium3DTileClassificationIgnoreShow.glsl new file mode 100644 index 000000000000..fee859e683ae --- /dev/null +++ b/Source/Shaders/Builtin/Constants/passCesium3DTileClassificationIgnoreShow.glsl @@ -0,0 +1,9 @@ +/** + * The automatic GLSL constant for {@link Pass#CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW} + * + * @name czm_passCesium3DTileClassificationIgnoreShow + * @glslConstant + * + * @see czm_pass + */ +const float czm_passCesium3DTileClassificationIgnoreShow = 6.0; diff --git a/Source/Shaders/Builtin/Constants/passOpaque.glsl b/Source/Shaders/Builtin/Constants/passOpaque.glsl index 4e3994f4ff3c..8465b01838d1 100644 --- a/Source/Shaders/Builtin/Constants/passOpaque.glsl +++ b/Source/Shaders/Builtin/Constants/passOpaque.glsl @@ -6,4 +6,4 @@ * * @see czm_pass */ -const float czm_passOpaque = 6.0; +const float czm_passOpaque = 7.0; diff --git a/Source/Shaders/Builtin/Constants/passOverlay.glsl b/Source/Shaders/Builtin/Constants/passOverlay.glsl index e04091b33848..e104cb08dd74 100644 --- a/Source/Shaders/Builtin/Constants/passOverlay.glsl +++ b/Source/Shaders/Builtin/Constants/passOverlay.glsl @@ -6,4 +6,4 @@ * * @see czm_pass */ -const float czm_passOverlay = 8.0; +const float czm_passOverlay = 9.0; diff --git a/Source/Shaders/Builtin/Constants/passTranslucent.glsl b/Source/Shaders/Builtin/Constants/passTranslucent.glsl index 2f25f8c07a7d..78cf93eb138f 100644 --- a/Source/Shaders/Builtin/Constants/passTranslucent.glsl +++ b/Source/Shaders/Builtin/Constants/passTranslucent.glsl @@ -6,4 +6,4 @@ * * @see czm_pass */ -const float czm_passTranslucent = 7.0; +const float czm_passTranslucent = 8.0; diff --git a/Source/ThirdParty/GltfPipeline/ForEach.js b/Source/ThirdParty/GltfPipeline/ForEach.js index 814af92e5e7b..7c20fc07e679 100644 --- a/Source/ThirdParty/GltfPipeline/ForEach.js +++ b/Source/ThirdParty/GltfPipeline/ForEach.js @@ -6,9 +6,8 @@ define([ /** * Contains traversal functions for processing elements of the glTF hierarchy. - * @constructor */ - function ForEach() {} + var ForEach = {}; ForEach.object = function(arrayOfObjects, handler) { if (defined(arrayOfObjects)) { @@ -211,5 +210,6 @@ define([ ForEach.texture = function(gltf, handler) { ForEach.topLevel(gltf, 'textures', handler); }; + return ForEach; }); diff --git a/Source/ThirdParty/GltfPipeline/addDefaults.js b/Source/ThirdParty/GltfPipeline/addDefaults.js index edb4f5d80ef9..a7ccb751e03a 100644 --- a/Source/ThirdParty/GltfPipeline/addDefaults.js +++ b/Source/ThirdParty/GltfPipeline/addDefaults.js @@ -57,13 +57,13 @@ define([ var defaults = { ambient: [0.0, 0.0, 0.0, 1.0], emission: [0.0, 0.0, 0.0, 1.0], - transparency: [1.0] + transparency: 1.0 }; if (technique !== 'CONSTANT') { defaults.diffuse = [0.0, 0.0, 0.0, 1.0]; if (technique !== 'LAMBERT') { defaults.specular = [0.0, 0.0, 0.0, 1.0]; - defaults.shininess = [0.0]; + defaults.shininess = 0.0; } } return { @@ -384,14 +384,8 @@ define([ } function selectDefaultScene(gltf) { - var scenes = gltf.scenes; - - if (!defined(gltf.scene)) { - var scenesLength = scenes.length; - for (var sceneId = 0; sceneId < scenesLength; sceneId++) { - gltf.scene = sceneId; - break; - } + if (defined(gltf.scenes) && !defined(gltf.scene)) { + gltf.scene = 0; } } diff --git a/Source/ThirdParty/GltfPipeline/getUniqueId.js b/Source/ThirdParty/GltfPipeline/getUniqueId.js deleted file mode 100644 index 59f7a36cdf5b..000000000000 --- a/Source/ThirdParty/GltfPipeline/getUniqueId.js +++ /dev/null @@ -1,31 +0,0 @@ -define([ - '../../Core/defined' - ], function( - defined) { - 'use strict'; - - /** - * Given a prefix for a new ID, checks the glTF asset for matching prefixes in top-level objects with IDs and returns a unique ID. - * - * @param {Object} gltf A javascript object containing a glTF asset. - * @param {String} prefix The string to try to use as the id. - * @returns {String} A unique id beginning with prefix. - */ - function getUniqueId(gltf, prefix) { - var id = prefix; - var appendIndex = 0; - for (var topLevelGroupId in gltf) { - if (gltf.hasOwnProperty(topLevelGroupId)) { - var topLevelGroup = gltf[topLevelGroupId]; - var match = topLevelGroup[id]; - while (defined(match)) { - id = prefix + '_' + appendIndex; - match = topLevelGroup[id]; - appendIndex++; - } - } - } - return id; - } - return getUniqueId; -}); diff --git a/Source/ThirdParty/GltfPipeline/parseBinaryGltf.js b/Source/ThirdParty/GltfPipeline/parseBinaryGltf.js index ccd7fde98cb4..fd2000d6c8f9 100644 --- a/Source/ThirdParty/GltfPipeline/parseBinaryGltf.js +++ b/Source/ThirdParty/GltfPipeline/parseBinaryGltf.js @@ -105,7 +105,6 @@ define([ } // Load Binary chunk else if (chunkType === 0x004E4942) { - // Clone just the binary chunk so the underlying buffer can be freed binaryBuffer = chunkBuffer; } } diff --git a/Source/ThirdParty/GltfPipeline/processModelMaterialsCommon.js b/Source/ThirdParty/GltfPipeline/processModelMaterialsCommon.js index 9608b4de179d..aea81842eeb7 100644 --- a/Source/ThirdParty/GltfPipeline/processModelMaterialsCommon.js +++ b/Source/ThirdParty/GltfPipeline/processModelMaterialsCommon.js @@ -541,7 +541,7 @@ define([ } else { fragmentLightingBlock += ' vec3 l = vec3(0.0, 0.0, 1.0);\n'; } - var minimumLighting = optimizeForCesium ? 0.2 : 0.0; + var minimumLighting = optimizeForCesium ? '0.2' : '0.0'; // Use strings instead of values as 0.0 -> 0 when stringified fragmentLightingBlock += ' diffuseLight += vec3(1.0, 1.0, 1.0) * max(dot(normal,l), ' + minimumLighting + ');\n'; if (hasSpecular) { diff --git a/Source/ThirdParty/GltfPipeline/processPbrMetallicRoughness.js b/Source/ThirdParty/GltfPipeline/processPbrMetallicRoughness.js index 2f772bef85ea..b9ccf6496c66 100644 --- a/Source/ThirdParty/GltfPipeline/processPbrMetallicRoughness.js +++ b/Source/ThirdParty/GltfPipeline/processPbrMetallicRoughness.js @@ -164,7 +164,7 @@ define([ for (var name in parameterValues) { //generate shader parameters if (parameterValues.hasOwnProperty(name)) { - var valType = getPBRValueType(name, parameterValues[name]); + var valType = getPBRValueType(name); if (!hasTexCoords && (valType === WebGLConstants.SAMPLER_2D)) { hasTexCoords = true; } @@ -373,37 +373,37 @@ define([ fragmentShader += 'const float M_PI = 3.141592653589793;\n'; fragmentShader += 'vec3 lambertianDiffuse(vec3 baseColor) \n' + - '{\n' + - ' return baseColor / M_PI;\n' + - '}\n\n'; + '{\n' + + ' return baseColor / M_PI;\n' + + '}\n\n'; fragmentShader += 'vec3 fresnelSchlick2(vec3 f0, vec3 f90, float VdotH) \n' + - '{\n' + - ' return f0 + (f90 - f0) * pow(clamp(1.0 - VdotH, 0.0, 1.0), 5.0);\n' + - '}\n\n'; + '{\n' + + ' return f0 + (f90 - f0) * pow(clamp(1.0 - VdotH, 0.0, 1.0), 5.0);\n' + + '}\n\n'; fragmentShader += 'vec3 fresnelSchlick(float metalness, float VdotH) \n' + - '{\n' + - ' return metalness + (vec3(1.0) - metalness) * pow(1.0 - VdotH, 5.0);\n' + - '}\n\n'; + '{\n' + + ' return metalness + (vec3(1.0) - metalness) * pow(1.0 - VdotH, 5.0);\n' + + '}\n\n'; fragmentShader += 'float smithVisibilityG1(float NdotV, float roughness) \n' + - '{\n' + - ' float k = (roughness + 1.0) * (roughness + 1.0) / 8.0;\n' + - ' return NdotV / (NdotV * (1.0 - k) + k);\n' + - '}\n\n'; + '{\n' + + ' float k = (roughness + 1.0) * (roughness + 1.0) / 8.0;\n' + + ' return NdotV / (NdotV * (1.0 - k) + k);\n' + + '}\n\n'; fragmentShader += 'float smithVisibilityGGX(float roughness, float NdotL, float NdotV) \n' + - '{\n' + - ' return smithVisibilityG1(NdotL, roughness) * smithVisibilityG1(NdotV, roughness);\n' + - '}\n\n'; + '{\n' + + ' return smithVisibilityG1(NdotL, roughness) * smithVisibilityG1(NdotV, roughness);\n' + + '}\n\n'; fragmentShader += 'float GGX(float roughness, float NdotH) \n' + - '{\n' + - ' float roughnessSquared = roughness * roughness;\n' + - ' float f = (NdotH * roughnessSquared - NdotH) * NdotH + 1.0;\n' + - ' return roughnessSquared / (M_PI * f * f);\n' + - '}\n\n'; + '{\n' + + ' float roughnessSquared = roughness * roughness;\n' + + ' float f = (NdotH * roughnessSquared - NdotH) * NdotH + 1.0;\n' + + ' return roughnessSquared / (M_PI * f * f);\n' + + '}\n\n'; fragmentShader += 'void main(void) \n{\n'; @@ -421,9 +421,9 @@ define([ } else { // Add standard derivatives extension fragmentShader = '#ifdef GL_OES_standard_derivatives\n' + - '#extension GL_OES_standard_derivatives : enable\n' + - '#endif\n' + - fragmentShader; + '#extension GL_OES_standard_derivatives : enable\n' + + '#endif\n' + + fragmentShader; // Compute tangents fragmentShader += '#ifdef GL_OES_standard_derivatives\n'; fragmentShader += ' vec3 pos_dx = dFdx(v_positionEC);\n'; @@ -675,9 +675,7 @@ define([ return techniqueId; } - function getPBRValueType(paramName, paramValue) { - var value; - + function getPBRValueType(paramName) { switch (paramName) { case 'baseColorFactor': return WebGLConstants.FLOAT_VEC4; diff --git a/Source/ThirdParty/GltfPipeline/updateVersion.js b/Source/ThirdParty/GltfPipeline/updateVersion.js index e357b0e8cf37..2292007d5fdb 100644 --- a/Source/ThirdParty/GltfPipeline/updateVersion.js +++ b/Source/ThirdParty/GltfPipeline/updateVersion.js @@ -1,12 +1,13 @@ define([ './addExtensionsRequired', './addToArray', - './findAccessorMinMax', './ForEach', './getAccessorByteStride', + './numberOfComponentsForType', '../../Core/Cartesian3', '../../Core/Math', '../../Core/clone', + '../../Core/ComponentDatatype', '../../Core/defaultValue', '../../Core/defined', '../../Core/Quaternion', @@ -14,12 +15,13 @@ define([ ], function( addExtensionsRequired, addToArray, - findAccessorMinMax, ForEach, getAccessorByteStride, + numberOfComponentsForType, Cartesian3, CesiumMath, clone, + ComponentDatatype, defaultValue, defined, Quaternion, @@ -135,6 +137,55 @@ define([ } } + function updateAnimations(gltf) { + var animations = gltf.animations; + var accessors = gltf.accessors; + var bufferViews = gltf.bufferViews; + var buffers = gltf.buffers; + var updatedAccessors = {}; + var axis = new Cartesian3(); + var quat = new Quaternion(); + for (var animationId in animations) { + if (animations.hasOwnProperty(animationId)) { + var animation = animations[animationId]; + var channels = animation.channels; + var parameters = animation.parameters; + var samplers = animation.samplers; + if (defined(channels)) { + var channelsLength = channels.length; + for (var i = 0; i < channelsLength; ++i) { + var channel = channels[i]; + if (channel.target.path === 'rotation') { + var accessorId = parameters[samplers[channel.sampler].output]; + if (defined(updatedAccessors[accessorId])) { + continue; + } + updatedAccessors[accessorId] = true; + var accessor = accessors[accessorId]; + var bufferView = bufferViews[accessor.bufferView]; + var buffer = buffers[bufferView.buffer]; + var source = buffer.extras._pipeline.source; + var byteOffset = source.byteOffset + bufferView.byteOffset + accessor.byteOffset; + var componentType = accessor.componentType; + var count = accessor.count; + var componentsLength = numberOfComponentsForType(accessor.type); + var length = accessor.count * componentsLength; + var typedArray = ComponentDatatype.createArrayBufferView(componentType, source.buffer, byteOffset, length); + + for (var j = 0; j < count; j++) { + var offset = j * componentsLength; + Cartesian3.unpack(typedArray, offset, axis); + var angle = typedArray[offset + 3]; + Quaternion.fromAxisAngle(axis, angle, quat); + Quaternion.pack(quat, typedArray, offset); + } + } + } + } + } + } + } + function removeTechniquePasses(gltf) { var techniques = gltf.techniques; for (var techniqueId in techniques) { @@ -179,6 +230,8 @@ define([ // node rotation should be quaternion, not axis-angle // node.instanceSkin is deprecated updateNodes(gltf); + // animations that target rotations should be quaternion, not axis-angle + updateAnimations(gltf); // technique.pass and techniques.passes are deprecated removeTechniquePasses(gltf); // gltf.lights -> khrMaterialsCommon.lights @@ -521,7 +574,7 @@ define([ compressedImage.mimeType = compressedBinaryGltf.mimeType; delete compressedExtensions.KHR_binary_glTF; } - if (Object.keys(extensions).length === 0) { + if (Object.keys(compressedExtensions).length === 0) { delete compressedImage.extensions; } } @@ -645,17 +698,6 @@ define([ }); } - function makeTechniqueValuesArrays(gltf) { - ForEach.technique(gltf, function(technique) { - ForEach.techniqueParameter(technique, function(parameter) { - var value = parameter.value; - if (defined(value) && !Array.isArray(value)) { - parameter.value = [value]; - } - }); - }); - } - function removeScissorFromTechniques(gltf) { ForEach.technique(gltf, function(technique) { var techniqueStates = technique.states; @@ -754,6 +796,7 @@ define([ var bufferViewShiftMap = {}; var bufferViewRemovalCount = 0; + /* jshint unused:vars */ ForEach.bufferView(gltf, function(bufferView, bufferViewId) { if (defined(bufferViewsToDelete[bufferViewId])) { bufferViewRemovalCount++; @@ -805,16 +848,6 @@ define([ }); } - function requireAccessorMinMax(gltf) { - ForEach.accessor(gltf, function(accessor) { - if (!defined(accessor.min) || !defined(accessor.max)) { - var minMax = findAccessorMinMax(gltf, accessor); - accessor.min = minMax.min; - accessor.max = minMax.max; - } - }); - } - function stripTechniqueAttributeValues(gltf) { ForEach.technique(gltf, function(technique) { ForEach.techniqueAttribute(technique, function(attribute) { @@ -872,8 +905,6 @@ define([ requireAttributeSetIndex(gltf); // Add underscores to application-specific parameters underscoreApplicationSpecificSemantics(gltf); - // technique.parameters.value should be arrays - makeTechniqueValuesArrays(gltf); // remove scissor from techniques removeScissorFromTechniques(gltf); // clamp technique function states to min/max @@ -887,6 +918,5 @@ define([ // add KHR_technique_webgl extension addKHRTechniqueExtension(gltf); } - return updateVersion; }); diff --git a/Specs/Core/CesiumTerrainProviderSpec.js b/Specs/Core/CesiumTerrainProviderSpec.js index c9c8a0b32b02..f6999c85bf15 100644 --- a/Specs/Core/CesiumTerrainProviderSpec.js +++ b/Specs/Core/CesiumTerrainProviderSpec.js @@ -73,6 +73,20 @@ defineSuite([ return returnTileJson('Data/CesiumTerrainTileJson/PartialAvailability.tile.json'); } + function returnParentUrlTileJson() { + var paths = ['Data/CesiumTerrainTileJson/ParentUrl.tile.json', + 'Data/CesiumTerrainTileJson/Parent.tile.json']; + var i = 0; + var oldLoad = loadWithXhr.load; + loadWithXhr.load = function(url, responseType, method, data, headers, deferred, overrideMimeType) { + if (url.indexOf('layer.json') >= 0) { + loadWithXhr.defaultLoad(paths[i++], responseType, method, data, headers, deferred); + } else { + return oldLoad(url, responseType, method, data, headers, deferred, overrideMimeType); + } + }; + } + function waitForTile(level, x, y, requestNormals, requestWaterMask, f) { var terrainProvider = new CesiumTerrainProvider({ url : 'made/up/url', @@ -247,6 +261,42 @@ defineSuite([ }); }); + it('requests parent layer.json', function() { + returnParentUrlTileJson(); + + var provider = new CesiumTerrainProvider({ + url : 'made/up/url', + requestVertexNormals : true, + requestWaterMask : true + }); + + return pollToPromise(function() { + return provider.ready; + }).then(function() { + expect(provider.credit.text).toBe('This is a child tileset! This amazing data is courtesy The Amazing Data Source!'); + expect(provider.requestVertexNormals).toBe(true); + expect(provider.requestWaterMask).toBe(true); + expect(provider.hasVertexNormals).toBe(false); // Neither tileset has them + expect(provider.hasWaterMask).toBe(true); // The child tileset has them + expect(provider.availability.isTileAvailable(1, 2, 1)).toBe(true); // Both have this + expect(provider.availability.isTileAvailable(1, 3, 1)).toBe(true); // Parent has this, but child doesn't + expect(provider.availability.isTileAvailable(2, 0, 0)).toBe(false); // Neither has this + + var layers = provider._layers; + expect(layers.length).toBe(2); + expect(layers[0].hasVertexNormals).toBe(false); + expect(layers[0].hasWaterMask).toBe(true); + expect(layers[0].availability.isTileAvailable(1, 2, 1)).toBe(true); + expect(layers[0].availability.isTileAvailable(1, 3, 1)).toBe(false); + expect(layers[0].availability.isTileAvailable(2, 0, 0)).toBe(false); + expect(layers[1].hasVertexNormals).toBe(false); + expect(layers[1].hasWaterMask).toBe(false); + expect(layers[1].availability.isTileAvailable(1, 2, 1)).toBe(true); + expect(layers[1].availability.isTileAvailable(1, 3, 1)).toBe(true); + expect(layers[1].availability.isTileAvailable(2, 0, 0)).toBe(false); + }); + }); + it('raises an error if layer.json does not specify a format', function() { returnTileJson('Data/CesiumTerrainTileJson/NoFormat.tile.json'); diff --git a/Specs/Core/EventSpec.js b/Specs/Core/EventSpec.js index 944a04f61a2e..1134fe10d034 100644 --- a/Specs/Core/EventSpec.js +++ b/Specs/Core/EventSpec.js @@ -45,7 +45,7 @@ defineSuite([ expect(spyListener).not.toHaveBeenCalled(); }); - it('can remove from withing a callback', function() { + it('can remove from within a callback', function() { var doNothing = function(evt) { }; @@ -67,6 +67,25 @@ defineSuite([ expect(event.numberOfListeners).toEqual(0); }); + it('can remove multiple listeners within a callback', function() { + var removeEvent0 = event.addEventListener(function() { removeEvent0(); }); + event.addEventListener(function() {}); + var removeEvent2 = event.addEventListener(function() { removeEvent2(); }); + event.addEventListener(function() {}); + var removeEvent4 = event.addEventListener(function() { removeEvent4(); }); + event.addEventListener(function() {}); + var removeEvent6 = event.addEventListener(function() { removeEvent6(); }); + event.addEventListener(function() {}); + var removeEvent8 = event.addEventListener(function() { removeEvent8(); }); + event.addEventListener(function() {}); + + expect(event.numberOfListeners).toEqual(10); + event.raiseEvent(); + expect(event.numberOfListeners).toEqual(5); + event.raiseEvent(); + expect(event.numberOfListeners).toEqual(5); + }); + it('addEventListener and removeEventListener works with same function of different scopes', function() { var Scope = function() { this.timesCalled = 0; 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/Core/getStringFromTypedArraySpec.js b/Specs/Core/getStringFromTypedArraySpec.js index 446348eae7a5..1b34db25f50e 100644 --- a/Specs/Core/getStringFromTypedArraySpec.js +++ b/Specs/Core/getStringFromTypedArraySpec.js @@ -19,12 +19,9 @@ defineSuite([ }); it('converts a typed array to string when forced to use fromCharCode', function() { - var previous = getStringFromTypedArray.decode; - getStringFromTypedArray.decode = getStringFromTypedArray.decodeWithFromCharCode; + spyOn(getStringFromTypedArray, 'decode').and.callFake(getStringFromTypedArray.decodeWithFromCharCode); verifyString(); - - getStringFromTypedArray.decode = previous; }); it('converts a sub-region of a typed array to a string', function() { @@ -59,4 +56,40 @@ defineSuite([ getStringFromTypedArray(); }).toThrowDeveloperError(); }); + + it('Unicode 2-byte characters work', function() { + var arr = new Uint8Array([90, 195, 188, 114, 105, 99, 104]); + expect(getStringFromTypedArray(arr)).toEqual('Zürich'); + }); + + it('Unicode 2-byte characters work with decodeWithFromCharCode forced', function() { + spyOn(getStringFromTypedArray, 'decode').and.callFake(getStringFromTypedArray.decodeWithFromCharCode); + + var arr = new Uint8Array([90, 195, 188, 114, 105, 99, 104]); + expect(getStringFromTypedArray(arr)).toEqual('Zürich'); + }); + + it('Unicode 3-byte characters work', function() { + var arr = new Uint8Array([224, 162, 160]); + expect(getStringFromTypedArray(arr)).toEqual('ࢠ'); + }); + + it('Unicode 3-byte characters work with decodeWithFromCharCode forced', function() { + spyOn(getStringFromTypedArray, 'decode').and.callFake(getStringFromTypedArray.decodeWithFromCharCode); + + var arr = new Uint8Array([224, 162, 160]); + expect(getStringFromTypedArray(arr)).toEqual('ࢠ'); + }); + + it('Unicode 4-byte characters work', function() { + var arr = new Uint8Array([240, 144, 138, 129]); + expect(getStringFromTypedArray(arr)).toEqual('𐊁'); + }); + + it('Unicode 4-byte characters work with decodeWithFromCharCode forced', function() { + spyOn(getStringFromTypedArray, 'decode').and.callFake(getStringFromTypedArray.decodeWithFromCharCode); + + var arr = new Uint8Array([240, 144, 138, 129]); + expect(getStringFromTypedArray(arr)).toEqual('𐊁'); + }); }); diff --git a/Specs/Data/CesiumTerrainTileJson/Parent.tile.json b/Specs/Data/CesiumTerrainTileJson/Parent.tile.json new file mode 100644 index 000000000000..7651c494254b --- /dev/null +++ b/Specs/Data/CesiumTerrainTileJson/Parent.tile.json @@ -0,0 +1,28 @@ +{ + "tilejson": "2.1.0", + "format" : "quantized-mesh-1.0", + "version" : "1.0.0", + "scheme" : "tms", + "attribution" : "This amazing data is courtesy The Amazing Data Source!", + "tiles" : [ + "{z}/{x}/{y}.terrain?v={version}" + ], + "available" : [ + [ + { + "startX" : 0, + "startY" : 0, + "endX" : 1, + "endY" : 0 + } + ], + [ + { + "startX" : 0, + "startY" : 0, + "endX" : 3, + "endY" : 1 + } + ] + ] +} diff --git a/Specs/Data/CesiumTerrainTileJson/ParentUrl.tile.json b/Specs/Data/CesiumTerrainTileJson/ParentUrl.tile.json new file mode 100644 index 000000000000..baf406ba4b0c --- /dev/null +++ b/Specs/Data/CesiumTerrainTileJson/ParentUrl.tile.json @@ -0,0 +1,33 @@ +{ + "tilejson": "2.1.0", + "format" : "quantized-mesh-1.0", + "version" : "1.0.0", + "scheme" : "tms", + "attribution" : "This is a child tileset!", + "tiles" : [ + "{z}/{x}/{y}.terrain?v={version}" + ], + "extensions" : [ + "watermask" + ], + "available" : [ + [ + { + "startX" : 0, + "startY" : 0, + "endX" : 1, + "endY" : 0 + } + ], + [ + { + "startX" : 0, + "startY" : 0, + "endX" : 2, + "endY" : 1 + } + ] + ], + "parentUrl": "./" +} + diff --git a/Specs/Data/KML/undeclaredNamespaces.kml b/Specs/Data/KML/undeclaredNamespaces.kml new file mode 100644 index 000000000000..d1107f9c05c3 --- /dev/null +++ b/Specs/Data/KML/undeclaredNamespaces.kml @@ -0,0 +1,18 @@ + + + + + + image.png]]> + + 1,2,3 + + + + diff --git a/Specs/DataSources/CzmlDataSourceSpec.js b/Specs/DataSources/CzmlDataSourceSpec.js index ca23bc64af48..5768b37c2ae9 100644 --- a/Specs/DataSources/CzmlDataSourceSpec.js +++ b/Specs/DataSources/CzmlDataSourceSpec.js @@ -23,6 +23,7 @@ defineSuite([ 'Core/RuntimeError', 'Core/Spherical', 'Core/TimeInterval', + 'Core/Transforms', 'Core/TranslationRotationScale', 'DataSources/CompositeEntityCollection', 'DataSources/EntityCollection', @@ -60,6 +61,7 @@ defineSuite([ RuntimeError, Spherical, TimeInterval, + Transforms, TranslationRotationScale, CompositeEntityCollection, EntityCollection, @@ -191,53 +193,59 @@ defineSuite([ it('name returns CZML defined name', function() { var dataSource = new CzmlDataSource(); - dataSource.load(nameCzml); - expect(dataSource.name).toEqual('czmlName'); + return dataSource.load(nameCzml).then(function(dataSource) { + expect(dataSource.name).toEqual('czmlName'); + }); }); it('name uses source name if CZML name is undefined', function() { var dataSource = new CzmlDataSource(); - dataSource.load(clockCzml, { - sourceUri : 'Gallery/simple.czml?asd=true' + return dataSource.load(clockCzml, { + sourceUri: 'Gallery/simple.czml?asd=true' + }).then(function(dataSource) { + expect(dataSource.name).toEqual('simple.czml'); }); - expect(dataSource.name).toEqual('simple.czml'); }); it('does not overwrite existing name if CZML name is undefined', function() { var dataSource = new CzmlDataSource('myName'); - dataSource.load(clockCzml, { - sourceUri : 'Gallery/simple.czml' + return dataSource.load(clockCzml, { + sourceUri: 'Gallery/simple.czml' + }).then(function(dataSource) { + expect(dataSource.name).toEqual('myName'); }); - expect(dataSource.name).toEqual('myName'); }); it('clock returns undefined for static CZML', function() { var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(staticCzml)); - expect(dataSource.clock).toBeUndefined(); + return dataSource.load(makePacket(staticCzml)).then(function(dataSource) { + expect(dataSource.clock).toBeUndefined(); + }); }); it('clock returns CZML defined clock', function() { var dataSource = new CzmlDataSource(); - dataSource.load(clockCzml); - - var clock = dataSource.clock; - expect(clock).toBeDefined(); - expect(clock.startTime).toEqual(parsedClock.interval.start); - expect(clock.stopTime).toEqual(parsedClock.interval.stop); - expect(clock.currentTime).toEqual(parsedClock.currentTime); - expect(clock.clockRange).toEqual(parsedClock.range); - expect(clock.clockStep).toEqual(parsedClock.step); - expect(clock.multiplier).toEqual(parsedClock.multiplier); - - dataSource.process(clockCzml2); - expect(clock).toBeDefined(); - expect(clock.startTime).toEqual(parsedClock2.interval.start); - expect(clock.stopTime).toEqual(parsedClock2.interval.stop); - expect(clock.currentTime).toEqual(parsedClock2.currentTime); - expect(clock.clockRange).toEqual(parsedClock2.range); - expect(clock.clockStep).toEqual(parsedClock2.step); - expect(clock.multiplier).toEqual(parsedClock2.multiplier); + return dataSource.load(clockCzml).then(function(dataSource) { + var clock = dataSource.clock; + expect(clock).toBeDefined(); + expect(clock.startTime).toEqual(parsedClock.interval.start); + expect(clock.stopTime).toEqual(parsedClock.interval.stop); + expect(clock.currentTime).toEqual(parsedClock.currentTime); + expect(clock.clockRange).toEqual(parsedClock.range); + expect(clock.clockStep).toEqual(parsedClock.step); + expect(clock.multiplier).toEqual(parsedClock.multiplier); + + return dataSource.process(clockCzml2); + }).then(function(dataSource) { + var clock = dataSource.clock; + expect(clock).toBeDefined(); + expect(clock.startTime).toEqual(parsedClock2.interval.start); + expect(clock.stopTime).toEqual(parsedClock2.interval.stop); + expect(clock.currentTime).toEqual(parsedClock2.currentTime); + expect(clock.clockRange).toEqual(parsedClock2.range); + expect(clock.clockStep).toEqual(parsedClock2.step); + expect(clock.multiplier).toEqual(parsedClock2.multiplier); + }); }); it('clock returns data interval if no clock defined', function() { @@ -246,39 +254,45 @@ defineSuite([ }); var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(dynamicCzml)); - var clock = dataSource.clock; - expect(clock).toBeDefined(); - expect(clock.startTime).toEqual(interval.start); - expect(clock.stopTime).toEqual(interval.stop); - expect(clock.currentTime).toEqual(interval.start); - expect(clock.clockRange).toEqual(ClockRange.LOOP_STOP); - expect(clock.clockStep).toEqual(ClockStep.SYSTEM_CLOCK_MULTIPLIER); - expect(clock.multiplier).toEqual(JulianDate.secondsDifference(interval.stop, interval.start) / 120.0); + return dataSource.load(makePacket(dynamicCzml)).then(function(dataSource) { + var clock = dataSource.clock; + expect(clock).toBeDefined(); + expect(clock.startTime).toEqual(interval.start); + expect(clock.stopTime).toEqual(interval.stop); + expect(clock.currentTime).toEqual(interval.start); + expect(clock.clockRange).toEqual(ClockRange.LOOP_STOP); + expect(clock.clockStep).toEqual(ClockStep.SYSTEM_CLOCK_MULTIPLIER); + expect(clock.multiplier).toEqual(JulianDate.secondsDifference(interval.stop, interval.start) / 120.0); + }); }); it('process loads expected data', function() { var dataSource = new CzmlDataSource(); - dataSource.process(simple); - expect(dataSource.entities.values.length).toEqual(10); + return dataSource.process(simple).then(function(dataSource) { + expect(dataSource.entities.values.length).toEqual(10); + }); }); it('process loads data on top of existing', function() { var dataSource = new CzmlDataSource(); - dataSource.process(simple); - expect(dataSource.entities.values.length === 10); + return dataSource.process(simple).then(function(dataSource) { + expect(dataSource.entities.values.length === 10); - dataSource.process(vehicle, vehicleUrl); - expect(dataSource.entities.values.length === 11); + return dataSource.process(vehicle, vehicleUrl); + }).then(function(dataSource) { + expect(dataSource.entities.values.length === 11); + }); }); it('load replaces data', function() { var dataSource = new CzmlDataSource(); - dataSource.process(simple); - expect(dataSource.entities.values.length).toEqual(10); + return dataSource.process(simple).then(function(dataSource) { + expect(dataSource.entities.values.length).toEqual(10); - dataSource.load(vehicle, vehicleUrl); - expect(dataSource.entities.values.length).toEqual(1); + return dataSource.load(vehicle, vehicleUrl); + }).then(function(dataSource) { + expect(dataSource.entities.values.length).toEqual(1); + }); }); it('process throws with undefined CZML', function() { @@ -301,48 +315,49 @@ defineSuite([ var spy = jasmine.createSpy('changedEvent'); dataSource.changedEvent.addEventListener(spy); - dataSource.load(clockCzml); - - expect(spy).toHaveBeenCalledWith(dataSource); + return dataSource.load(clockCzml).then(function(dataSource) { + expect(spy).toHaveBeenCalledWith(dataSource); + }); }); it('raises changed event when name changes in CZML', function() { var dataSource = new CzmlDataSource(); + var spy = jasmine.createSpy('changedEvent'); var originalCzml = { id : 'document', version : '1.0', name : 'czmlName' }; - dataSource.load(originalCzml); - var spy = jasmine.createSpy('changedEvent'); - dataSource.changedEvent.addEventListener(spy); + return dataSource.load(originalCzml).then(function(dataSource) { + dataSource.changedEvent.addEventListener(spy); - var newCzml = { - id : 'document', - name : 'newCzmlName' - }; - dataSource.process(newCzml); - - expect(spy).toHaveBeenCalledWith(dataSource); + var newCzml = { + id : 'document', + name : 'newCzmlName' + }; + return dataSource.process(newCzml); + }).then(function(dataSource) { + expect(spy).toHaveBeenCalledWith(dataSource); + }); }); it('does not raise changed event when name does not change in CZML', function() { var dataSource = new CzmlDataSource(); - - dataSource.load(nameCzml); - var spy = jasmine.createSpy('changedEvent'); - dataSource.changedEvent.addEventListener(spy); - - dataSource.load(nameCzml); - expect(spy).not.toHaveBeenCalled(); + return dataSource.load(nameCzml).then(function(dataSource) { + dataSource.changedEvent.addEventListener(spy); + return dataSource.load(nameCzml); + }).then(function(dataSource) { + expect(spy).not.toHaveBeenCalled(); + }); }); it('raises changed event when clock changes in CZML', function() { var dataSource = new CzmlDataSource(); + var spy = jasmine.createSpy('changedEvent'); var originalCzml = { id : 'document', @@ -355,38 +370,38 @@ defineSuite([ step : 'SYSTEM_CLOCK_MULTIPLIER' } }; - dataSource.load(originalCzml); - - var spy = jasmine.createSpy('changedEvent'); - dataSource.changedEvent.addEventListener(spy); - - var newCzml = { - id : 'document', - version : '1.0', - clock : { - interval : '2013-03-15T10:00:00Z/2013-03-16T10:00:00Z', - currentTime : '2012-03-15T10:00:00Z', - multiplier : 60.0, - range : 'LOOP_STOP', - step : 'SYSTEM_CLOCK_MULTIPLIER' - } - }; - dataSource.load(newCzml); - expect(spy).toHaveBeenCalledWith(dataSource); + return dataSource.load(originalCzml).then(function(dataSource) { + dataSource.changedEvent.addEventListener(spy); + + var newCzml = { + id: 'document', + version: '1.0', + clock : { + interval : '2013-03-15T10:00:00Z/2013-03-16T10:00:00Z', + currentTime : '2012-03-15T10:00:00Z', + multiplier : 60.0, + range : 'LOOP_STOP', + step : 'SYSTEM_CLOCK_MULTIPLIER' + } + }; + return dataSource.load(newCzml); + }).then(function(dataSource) { + expect(spy).toHaveBeenCalledWith(dataSource); + }); }); it('does not raise changed event when clock does not change in CZML', function() { var dataSource = new CzmlDataSource(); - - dataSource.load(clockCzml); - var spy = jasmine.createSpy('changedEvent'); - dataSource.changedEvent.addEventListener(spy); - dataSource.load(clockCzml); + return dataSource.load(clockCzml).then(function(dataSource) { + dataSource.changedEvent.addEventListener(spy); - expect(spy).not.toHaveBeenCalled(); + return dataSource.load(clockCzml); + }).then(function(dataSource) { + expect(spy).not.toHaveBeenCalled(); + }); }); it('raises error when an error occurs in load', function() { @@ -410,7 +425,7 @@ defineSuite([ dataSource.errorEvent.addEventListener(spy); // Blue.png is not JSON - dataSource.process('Data/Images/Blue.png').then(function() { + return dataSource.process('Data/Images/Blue.png').then(function() { fail('should not be called'); }).otherwise(function() { expect(spy).toHaveBeenCalledWith(dataSource, jasmine.any(Error)); @@ -459,30 +474,31 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(billboardPacket), { - sourceUri : sourceUri + return dataSource.load(makePacket(billboardPacket), { + sourceUri: sourceUri + }).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.billboard).toBeDefined(); + expect(entity.billboard.image.getValue(Iso8601.MINIMUM_VALUE)).toEqual(sourceUri + 'image.png'); + expect(entity.billboard.rotation.getValue(Iso8601.MINIMUM_VALUE)).toEqual(billboardPacket.billboard.rotation); + expect(entity.billboard.scale.getValue(Iso8601.MINIMUM_VALUE)).toEqual(billboardPacket.billboard.scale); + expect(entity.billboard.heightReference.getValue(Iso8601.MINIMUM_VALUE)).toEqual(HeightReference.CLAMP_TO_GROUND); + expect(entity.billboard.horizontalOrigin.getValue(Iso8601.MINIMUM_VALUE)).toEqual(HorizontalOrigin.CENTER); + expect(entity.billboard.verticalOrigin.getValue(Iso8601.MINIMUM_VALUE)).toEqual(VerticalOrigin.CENTER); + expect(entity.billboard.color.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(1.0, 1.0, 1.0, 1.0)); + expect(entity.billboard.eyeOffset.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Cartesian3(3.0, 4.0, 5.0)); + expect(entity.billboard.pixelOffset.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Cartesian2(1.0, 2.0)); + expect(entity.billboard.alignedAxis.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Cartesian3(1.0, 0.0, 0.0)); + expect(entity.billboard.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); + expect(entity.billboard.sizeInMeters.getValue(Iso8601.MINIMUM_VALUE)).toEqual(false); + expect(entity.billboard.width.getValue(Iso8601.MINIMUM_VALUE)).toEqual(10); + expect(entity.billboard.height.getValue(Iso8601.MINIMUM_VALUE)).toEqual(11); + expect(entity.billboard.scaleByDistance.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new NearFarScalar(1.0, 2.0, 10000.0, 3.0)); + expect(entity.billboard.translucencyByDistance.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new NearFarScalar(1.0, 1.0, 10000.0, 0.0)); + expect(entity.billboard.pixelOffsetScaleByDistance.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new NearFarScalar(1.0, 20.0, 10000.0, 30.0)); + expect(entity.billboard.imageSubRegion.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new BoundingRectangle(20, 30, 10, 11)); }); - var entity = dataSource.entities.values[0]; - - expect(entity.billboard).toBeDefined(); - expect(entity.billboard.image.getValue(Iso8601.MINIMUM_VALUE)).toEqual(sourceUri + 'image.png'); - expect(entity.billboard.rotation.getValue(Iso8601.MINIMUM_VALUE)).toEqual(billboardPacket.billboard.rotation); - expect(entity.billboard.scale.getValue(Iso8601.MINIMUM_VALUE)).toEqual(billboardPacket.billboard.scale); - expect(entity.billboard.heightReference.getValue(Iso8601.MINIMUM_VALUE)).toEqual(HeightReference.CLAMP_TO_GROUND); - expect(entity.billboard.horizontalOrigin.getValue(Iso8601.MINIMUM_VALUE)).toEqual(HorizontalOrigin.CENTER); - expect(entity.billboard.verticalOrigin.getValue(Iso8601.MINIMUM_VALUE)).toEqual(VerticalOrigin.CENTER); - expect(entity.billboard.color.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(1.0, 1.0, 1.0, 1.0)); - expect(entity.billboard.eyeOffset.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Cartesian3(3.0, 4.0, 5.0)); - expect(entity.billboard.pixelOffset.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Cartesian2(1.0, 2.0)); - expect(entity.billboard.alignedAxis.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Cartesian3(1.0, 0.0, 0.0)); - expect(entity.billboard.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); - expect(entity.billboard.sizeInMeters.getValue(Iso8601.MINIMUM_VALUE)).toEqual(false); - expect(entity.billboard.width.getValue(Iso8601.MINIMUM_VALUE)).toEqual(10); - expect(entity.billboard.height.getValue(Iso8601.MINIMUM_VALUE)).toEqual(11); - expect(entity.billboard.scaleByDistance.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new NearFarScalar(1.0, 2.0, 10000.0, 3.0)); - expect(entity.billboard.translucencyByDistance.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new NearFarScalar(1.0, 1.0, 10000.0, 0.0)); - expect(entity.billboard.pixelOffsetScaleByDistance.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new NearFarScalar(1.0, 20.0, 10000.0, 30.0)); - expect(entity.billboard.imageSubRegion.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new BoundingRectangle(20, 30, 10, 11)); }); it('can handle aligned axis expressed as a cartesian', function() { @@ -498,11 +514,12 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(billboardPacket)); - var entity = dataSource.entities.values[0]; + return dataSource.load(makePacket(billboardPacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; - expect(entity.billboard).toBeDefined(); - expect(entity.billboard.alignedAxis.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Cartesian3(1.0, 0.0, 0.0)); + expect(entity.billboard).toBeDefined(); + expect(entity.billboard.alignedAxis.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Cartesian3(1.0, 0.0, 0.0)); + }); }); it('can handle aligned axis expressed as a velocity reference', function() { @@ -520,15 +537,58 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - var entity = dataSource.entities.values[0]; - var property = entity.billboard.alignedAxis; + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + var property = entity.billboard.alignedAxis; - var expectedVelocity = new Cartesian3(1.0, 2.0, 3.0); - var expectedVelocityDirection = Cartesian3.normalize(expectedVelocity, new Cartesian3()); + var expectedVelocity = new Cartesian3(1.0, 2.0, 3.0); + var expectedVelocityDirection = Cartesian3.normalize(expectedVelocity, new Cartesian3()); - expect(property.getValue(JulianDate.fromIso8601('2016-06-17T12:00:00Z'))).toEqualEpsilon(expectedVelocityDirection, CesiumMath.EPSILON15); - expect(property.getValue(JulianDate.fromIso8601('2016-06-17T12:00:30Z'))).toEqualEpsilon(expectedVelocityDirection, CesiumMath.EPSILON15); + expect(property.getValue(JulianDate.fromIso8601('2016-06-17T12:00:00Z'))).toEqualEpsilon(expectedVelocityDirection, CesiumMath.EPSILON15); + expect(property.getValue(JulianDate.fromIso8601('2016-06-17T12:00:30Z'))).toEqualEpsilon(expectedVelocityDirection, CesiumMath.EPSILON15); + }); + }); + + it('can handle aligned axis expressed as a velocity reference within an interval', function() { + var packet = { + "position": { + "epoch": "2016-06-17T12:00:00Z", + "cartesian": [0, 1, 2, 3, + 60, 61, 122, 183] + }, + "billboard": { + "alignedAxis": [ + { + "interval": "2016-06-17T12:00:00Z/2016-06-17T12:00:30Z", + "unitCartesian": [ + 0, + 1, + 0 + ] + }, + { + "interval": "2016-06-17T12:00:30Z/2016-06-17T12:01:00Z", + "velocityReference": "#position" + } + ] + } + }; + + var dataSource = new CzmlDataSource(); + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + var property = entity.billboard.alignedAxis; + + var expected = new Cartesian3(0, 1, 0); + expect(property.getValue(JulianDate.fromIso8601('2016-06-17T12:00:00Z'))).toEqual(expected); + expect(property.getValue(JulianDate.fromIso8601('2016-06-17T12:00:29Z'))).toEqual(expected); + + var expectedVelocity = new Cartesian3(1.0, 2.0, 3.0); + var expectedVelocityDirection = Cartesian3.normalize(expectedVelocity, new Cartesian3()); + + expect(property.getValue(JulianDate.fromIso8601('2016-06-17T12:00:30Z'))).toEqualEpsilon(expectedVelocityDirection, CesiumMath.EPSILON15); + expect(property.getValue(JulianDate.fromIso8601('2016-06-17T12:01:00Z'))).toEqualEpsilon(expectedVelocityDirection, CesiumMath.EPSILON12); + }); }); it('can handle image intervals both of type uri and image', function() { @@ -546,13 +606,14 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet), { - sourceUri : source + return dataSource.load(makePacket(packet), { + sourceUri: source + }).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + var imageProperty = entity.billboard.image; + expect(imageProperty.getValue(JulianDate.fromIso8601('2013-01-01T00:00:00Z'))).toEqual(source + 'image.png'); + expect(imageProperty.getValue(JulianDate.fromIso8601('2013-01-01T01:00:00Z'))).toEqual(source + 'image2.png'); }); - var entity = dataSource.entities.values[0]; - var imageProperty = entity.billboard.image; - expect(imageProperty.getValue(JulianDate.fromIso8601('2013-01-01T00:00:00Z'))).toEqual(source + 'image.png'); - expect(imageProperty.getValue(JulianDate.fromIso8601('2013-01-01T01:00:00Z'))).toEqual(source + 'image2.png'); }); it('appends query to all uri', function() { @@ -570,17 +631,18 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet), { - sourceUri : source, - query : { - token : 34570, - password : "Passw0rd" + return dataSource.load(makePacket(packet), { + sourceUri: source, + query: { + token: 34570, + password: "Passw0rd" } + }).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + var imageProperty = entity.billboard.image; + expect(imageProperty.getValue(JulianDate.fromIso8601('2013-01-01T00:00:00Z'))).toEqual(source + 'image.png' + '?token=34570&password=Passw0rd'); + expect(imageProperty.getValue(JulianDate.fromIso8601('2013-01-01T01:00:00Z'))).toEqual(source + 'image2.png' + '?token=34570&password=Passw0rd'); }); - var entity = dataSource.entities.values[0]; - var imageProperty = entity.billboard.image; - expect(imageProperty.getValue(JulianDate.fromIso8601('2013-01-01T00:00:00Z'))).toEqual(source + 'image.png' + '?token=34570&password=Passw0rd'); - expect(imageProperty.getValue(JulianDate.fromIso8601('2013-01-01T01:00:00Z'))).toEqual(source + 'image2.png' + '?token=34570&password=Passw0rd'); }); it('appends query tokens to source URL', function() { @@ -592,10 +654,12 @@ defineSuite([ deferred.reject(); }); - dataSource.process(simpleUrl, { query : { - "token" : 30203, - "pass" : "passw0rd" - }}); + dataSource.process(simpleUrl, { + query: { + "token": 30203, + "pass": "passw0rd" + } + }); return requestNetworkLink.promise.then(function(url) { expect(url).toEqual(simpleUrl + '?token=30203&pass=passw0rd'); }); @@ -628,29 +692,30 @@ defineSuite([ var invalidTime = JulianDate.addSeconds(validTime, -1, new JulianDate()); var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(billboardPacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.billboard).toBeDefined(); - expect(entity.billboard.image.getValue(validTime)).toEqual(billboardPacket.billboard.image); - expect(entity.billboard.scale.getValue(validTime)).toEqual(billboardPacket.billboard.scale); - expect(entity.billboard.horizontalOrigin.getValue(validTime)).toEqual(HorizontalOrigin.CENTER); - expect(entity.billboard.verticalOrigin.getValue(validTime)).toEqual(VerticalOrigin.CENTER); - expect(entity.billboard.color.getValue(validTime)).toEqual(new Color(1.0, 1.0, 1.0, 1.0)); - expect(entity.billboard.eyeOffset.getValue(validTime)).toEqual(new Cartesian3(3.0, 4.0, 5.0)); - expect(entity.billboard.pixelOffset.getValue(validTime)).toEqual(new Cartesian2(1.0, 2.0)); - - expect(entity.billboard.show.getValue(validTime)).toEqual(true); - - expect(entity.billboard).toBeDefined(); - expect(entity.billboard.image.getValue(invalidTime)).toBeUndefined(); - expect(entity.billboard.scale.getValue(invalidTime)).toBeUndefined(); - expect(entity.billboard.horizontalOrigin.getValue(invalidTime)).toBeUndefined(); - expect(entity.billboard.verticalOrigin.getValue(invalidTime)).toBeUndefined(); - expect(entity.billboard.color.getValue(invalidTime)).toBeUndefined(); - expect(entity.billboard.eyeOffset.getValue(invalidTime)).toBeUndefined(); - expect(entity.billboard.pixelOffset.getValue(invalidTime)).toBeUndefined(); - expect(entity.billboard.show.getValue(invalidTime)).toBeUndefined(); + return dataSource.load(makePacket(billboardPacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.billboard).toBeDefined(); + expect(entity.billboard.image.getValue(validTime)).toEqual(billboardPacket.billboard.image); + expect(entity.billboard.scale.getValue(validTime)).toEqual(billboardPacket.billboard.scale); + expect(entity.billboard.horizontalOrigin.getValue(validTime)).toEqual(HorizontalOrigin.CENTER); + expect(entity.billboard.verticalOrigin.getValue(validTime)).toEqual(VerticalOrigin.CENTER); + expect(entity.billboard.color.getValue(validTime)).toEqual(new Color(1.0, 1.0, 1.0, 1.0)); + expect(entity.billboard.eyeOffset.getValue(validTime)).toEqual(new Cartesian3(3.0, 4.0, 5.0)); + expect(entity.billboard.pixelOffset.getValue(validTime)).toEqual(new Cartesian2(1.0, 2.0)); + + expect(entity.billboard.show.getValue(validTime)).toEqual(true); + + expect(entity.billboard).toBeDefined(); + expect(entity.billboard.image.getValue(invalidTime)).toBeUndefined(); + expect(entity.billboard.scale.getValue(invalidTime)).toBeUndefined(); + expect(entity.billboard.horizontalOrigin.getValue(invalidTime)).toBeUndefined(); + expect(entity.billboard.verticalOrigin.getValue(invalidTime)).toBeUndefined(); + expect(entity.billboard.color.getValue(invalidTime)).toBeUndefined(); + expect(entity.billboard.eyeOffset.getValue(invalidTime)).toBeUndefined(); + expect(entity.billboard.pixelOffset.getValue(invalidTime)).toBeUndefined(); + expect(entity.billboard.show.getValue(invalidTime)).toBeUndefined(); + }); }); it('can handle sampled billboard pixelOffset.', function() { @@ -667,16 +732,17 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(billboardPacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.billboard).toBeDefined(); - var date1 = epoch; - var date2 = JulianDate.addSeconds(epoch, 0.5, new JulianDate()); - var date3 = JulianDate.addSeconds(epoch, 1.0, new JulianDate()); - expect(entity.billboard.pixelOffset.getValue(date1)).toEqual(new Cartesian2(1.0, 2.0)); - expect(entity.billboard.pixelOffset.getValue(date2)).toEqual(new Cartesian2(2.0, 3.0)); - expect(entity.billboard.pixelOffset.getValue(date3)).toEqual(new Cartesian2(3.0, 4.0)); + return dataSource.load(makePacket(billboardPacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.billboard).toBeDefined(); + var date1 = epoch; + var date2 = JulianDate.addSeconds(epoch, 0.5, new JulianDate()); + var date3 = JulianDate.addSeconds(epoch, 1.0, new JulianDate()); + expect(entity.billboard.pixelOffset.getValue(date1)).toEqual(new Cartesian2(1.0, 2.0)); + expect(entity.billboard.pixelOffset.getValue(date2)).toEqual(new Cartesian2(2.0, 3.0)); + expect(entity.billboard.pixelOffset.getValue(date3)).toEqual(new Cartesian2(3.0, 4.0)); + }); }); it('can handle interval billboard scaleByDistance.', function() { @@ -693,12 +759,13 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(billboardPacket)); - var entity = dataSource.entities.values[0]; + return dataSource.load(makePacket(billboardPacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; - expect(entity.billboard).toBeDefined(); - expect(entity.billboard.scaleByDistance.getValue(JulianDate.fromIso8601('2013-01-01T00:00:00Z'))).toEqual(new NearFarScalar(1.0, 2.0, 10000.0, 3.0)); - expect(entity.billboard.scaleByDistance.getValue(JulianDate.fromIso8601('2013-01-01T01:00:00Z'))).toEqual(new NearFarScalar(2.0, 3.0, 20000.0, 4.0)); + expect(entity.billboard).toBeDefined(); + expect(entity.billboard.scaleByDistance.getValue(JulianDate.fromIso8601('2013-01-01T00:00:00Z'))).toEqual(new NearFarScalar(1.0, 2.0, 10000.0, 3.0)); + expect(entity.billboard.scaleByDistance.getValue(JulianDate.fromIso8601('2013-01-01T01:00:00Z'))).toEqual(new NearFarScalar(2.0, 3.0, 20000.0, 4.0)); + }); }); it('can handle sampled billboard scaleByDistance.', function() { @@ -717,16 +784,17 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(billboardPacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.billboard).toBeDefined(); - var date1 = epoch; - var date2 = JulianDate.addSeconds(epoch, 1.0, new JulianDate()); - var date3 = JulianDate.addSeconds(epoch, 2.0, new JulianDate()); - expect(entity.billboard.scaleByDistance.getValue(date1)).toEqual(new NearFarScalar(1.0, 2.0, 10000.0, 3.0)); - expect(entity.billboard.scaleByDistance.getValue(date2)).toEqual(new NearFarScalar(1.5, 2.5, 15000.0, 3.5)); - expect(entity.billboard.scaleByDistance.getValue(date3)).toEqual(new NearFarScalar(2.0, 3.0, 20000.0, 4.0)); + return dataSource.load(makePacket(billboardPacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.billboard).toBeDefined(); + var date1 = epoch; + var date2 = JulianDate.addSeconds(epoch, 1.0, new JulianDate()); + var date3 = JulianDate.addSeconds(epoch, 2.0, new JulianDate()); + expect(entity.billboard.scaleByDistance.getValue(date1)).toEqual(new NearFarScalar(1.0, 2.0, 10000.0, 3.0)); + expect(entity.billboard.scaleByDistance.getValue(date2)).toEqual(new NearFarScalar(1.5, 2.5, 15000.0, 3.5)); + expect(entity.billboard.scaleByDistance.getValue(date3)).toEqual(new NearFarScalar(2.0, 3.0, 20000.0, 4.0)); + }); }); it('can handle sampled billboard color rgba.', function() { @@ -743,16 +811,17 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(billboardPacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.billboard).toBeDefined(); - var date1 = epoch; - var date2 = JulianDate.addSeconds(epoch, 1.0, new JulianDate()); - var date3 = JulianDate.addSeconds(epoch, 2.0, new JulianDate()); - expect(entity.billboard.color.getValue(date1)).toEqual(Color.fromBytes(200, 202, 204, 206)); - expect(entity.billboard.color.getValue(date2)).toEqual(Color.fromBytes(100, 101, 102, 103)); - expect(entity.billboard.color.getValue(date3)).toEqual(Color.fromBytes(0, 0, 0, 0)); + return dataSource.load(makePacket(billboardPacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.billboard).toBeDefined(); + var date1 = epoch; + var date2 = JulianDate.addSeconds(epoch, 1.0, new JulianDate()); + var date3 = JulianDate.addSeconds(epoch, 2.0, new JulianDate()); + expect(entity.billboard.color.getValue(date1)).toEqual(Color.fromBytes(200, 202, 204, 206)); + expect(entity.billboard.color.getValue(date2)).toEqual(Color.fromBytes(100, 101, 102, 103)); + expect(entity.billboard.color.getValue(date3)).toEqual(Color.fromBytes(0, 0, 0, 0)); + }); }); it('can handle clock data.', function() { @@ -777,15 +846,16 @@ defineSuite([ var step = ClockStep[clockPacket.clock.step]; var dataSource = new CzmlDataSource(); - dataSource.load(clockPacket); - - expect(dataSource.clock).toBeDefined(); - expect(dataSource.clock.startTime).toEqual(interval.start); - expect(dataSource.clock.stopTime).toEqual(interval.stop); - expect(dataSource.clock.currentTime).toEqual(currentTime); - expect(dataSource.clock.clockRange).toEqual(range); - expect(dataSource.clock.clockStep).toEqual(step); - expect(dataSource.clock.multiplier).toEqual(multiplier); + return dataSource.load(clockPacket).then(function(dataSource) { + + expect(dataSource.clock).toBeDefined(); + expect(dataSource.clock.startTime).toEqual(interval.start); + expect(dataSource.clock.stopTime).toEqual(interval.stop); + expect(dataSource.clock.currentTime).toEqual(currentTime); + expect(dataSource.clock.clockRange).toEqual(range); + expect(dataSource.clock.clockStep).toEqual(step); + expect(dataSource.clock.multiplier).toEqual(multiplier); + }); }); it('can handle position specified as constant cartographicsDegrees.', function() { @@ -796,11 +866,11 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(czml)); - - var entity = dataSource.entities.values[0]; - var resultCartesian = entity.position.getValue(JulianDate.now()); - expect(resultCartesian).toEqual(Cartesian3.fromDegrees(34, 117, 10000)); + return dataSource.load(makePacket(czml)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + var resultCartesian = entity.position.getValue(JulianDate.now()); + expect(resultCartesian).toEqual(Cartesian3.fromDegrees(34, 117, 10000)); + }); }); it('can handle position specified as sampled cartographicsDegrees.', function() { @@ -815,14 +885,14 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(czml)); - - var entity = dataSource.entities.values[0]; - var resultCartesian = entity.position.getValue(epoch); - expect(resultCartesian).toEqual(Cartesian3.fromDegrees(34, 117, 10000)); + return dataSource.load(makePacket(czml)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + var resultCartesian = entity.position.getValue(epoch); + expect(resultCartesian).toEqual(Cartesian3.fromDegrees(34, 117, 10000)); - resultCartesian = entity.position.getValue(JulianDate.addSeconds(epoch, 1, new JulianDate())); - expect(resultCartesian).toEqual(Cartesian3.fromDegrees(34, 117, 20000)); + resultCartesian = entity.position.getValue(JulianDate.addSeconds(epoch, 1, new JulianDate())); + expect(resultCartesian).toEqual(Cartesian3.fromDegrees(34, 117, 20000)); + }); }); it('can handle position specified as sampled cartographicDegrees without epoch.', function() { @@ -837,14 +907,14 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(czml)); - - var entity = dataSource.entities.values[0]; - var resultCartesian = entity.position.getValue(firstDate); - expect(resultCartesian).toEqual(Cartesian3.fromDegrees(34, 117, 10000)); + return dataSource.load(makePacket(czml)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + var resultCartesian = entity.position.getValue(firstDate); + expect(resultCartesian).toEqual(Cartesian3.fromDegrees(34, 117, 10000)); - resultCartesian = entity.position.getValue(lastDate); - expect(resultCartesian).toEqual(Cartesian3.fromDegrees(34, 117, 20000)); + resultCartesian = entity.position.getValue(lastDate); + expect(resultCartesian).toEqual(Cartesian3.fromDegrees(34, 117, 20000)); + }); }); it('can handle position specified as constant cartographicRadians.', function() { @@ -855,11 +925,11 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(czml)); - - var entity = dataSource.entities.values[0]; - var resultCartesian = entity.position.getValue(JulianDate.now()); - expect(resultCartesian).toEqual(Cartesian3.fromRadians(1, 2, 10000)); + return dataSource.load(makePacket(czml)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + var resultCartesian = entity.position.getValue(JulianDate.now()); + expect(resultCartesian).toEqual(Cartesian3.fromRadians(1, 2, 10000)); + }); }); it('can handle position specified as sampled cartographicRadians.', function() { @@ -874,14 +944,14 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(czml)); - - var entity = dataSource.entities.values[0]; - var resultCartesian = entity.position.getValue(epoch); - expect(resultCartesian).toEqual(Cartesian3.fromRadians(2, 0.3, 10000)); + return dataSource.load(makePacket(czml)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + var resultCartesian = entity.position.getValue(epoch); + expect(resultCartesian).toEqual(Cartesian3.fromRadians(2, 0.3, 10000)); - resultCartesian = entity.position.getValue(JulianDate.addSeconds(epoch, 1, new JulianDate())); - expect(resultCartesian).toEqual(Cartesian3.fromRadians(0.2, 0.5, 20000)); + resultCartesian = entity.position.getValue(JulianDate.addSeconds(epoch, 1, new JulianDate())); + expect(resultCartesian).toEqual(Cartesian3.fromRadians(0.2, 0.5, 20000)); + }); }); it('Can set reference frame', function() { @@ -896,21 +966,23 @@ defineSuite([ } }; - dataSource.load(makePacket(czml)); - var entity = dataSource.entities.values[0]; - expect(entity.position.referenceFrame).toBe(ReferenceFrame.INERTIAL); + return dataSource.load(makePacket(czml)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + expect(entity.position.referenceFrame).toBe(ReferenceFrame.INERTIAL); - czml = { - position : { - referenceFrame : 'FIXED', - epoch : JulianDate.toIso8601(epoch), - cartesian : [1.0, 2.0, 3.0] - } - }; + czml = { + position: { + referenceFrame: 'FIXED', + epoch: JulianDate.toIso8601(epoch), + cartesian: [1.0, 2.0, 3.0] + } + }; - dataSource.load(makePacket(czml)); - entity = dataSource.entities.values[0]; - expect(entity.position.referenceFrame).toBe(ReferenceFrame.FIXED); + return dataSource.load(makePacket(czml)); + }).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + expect(entity.position.referenceFrame).toBe(ReferenceFrame.FIXED); + }); }); it('uses FIXED as default if not specified in CZML', function() { @@ -924,9 +996,10 @@ defineSuite([ } }; - dataSource.load(makePacket(czml)); - var entity = dataSource.entities.values[0]; - expect(entity.position.referenceFrame).toBe(ReferenceFrame.FIXED); + return dataSource.load(makePacket(czml)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + expect(entity.position.referenceFrame).toBe(ReferenceFrame.FIXED); + }); }); it('Default reference frame on existing interval does not reset value to FIXED.', function() { @@ -941,19 +1014,21 @@ defineSuite([ } }; - dataSource.process(makePacket(czml)); - var entity = dataSource.entities.values[0]; - expect(entity.position.referenceFrame).toBe(ReferenceFrame.INERTIAL); + return dataSource.process(makePacket(czml)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + expect(entity.position.referenceFrame).toBe(ReferenceFrame.INERTIAL); - var czml2 = { - position : { - epoch : JulianDate.toIso8601(epoch), - cartesian : [1.0, 2.0, 3.0] - } - }; - dataSource.process(czml2); - - expect(entity.position.referenceFrame).toBe(ReferenceFrame.INERTIAL); + var czml2 = { + position: { + epoch: JulianDate.toIso8601(epoch), + cartesian: [1.0, 2.0, 3.0] + } + }; + return dataSource.process(czml2); + }).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + expect(entity.position.referenceFrame).toBe(ReferenceFrame.INERTIAL); + }); }); it('can handle a number specified as sampled values without epoch.', function() { @@ -971,13 +1046,14 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(ellipsePacket)); - var entity = dataSource.entities.values[0]; + return dataSource.load(makePacket(ellipsePacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; - expect(entity.ellipse).toBeDefined(); - expect(entity.ellipse.semiMajorAxis.getValue(firstDate)).toEqual(0); - expect(entity.ellipse.semiMajorAxis.getValue(midDate)).toEqual(5); - expect(entity.ellipse.semiMajorAxis.getValue(lastDate)).toEqual(10); + expect(entity.ellipse).toBeDefined(); + expect(entity.ellipse.semiMajorAxis.getValue(firstDate)).toEqual(0); + expect(entity.ellipse.semiMajorAxis.getValue(midDate)).toEqual(5); + expect(entity.ellipse.semiMajorAxis.getValue(lastDate)).toEqual(10); + }); }); it('can handle a direction specified as constant unitSpherical', function() { @@ -990,11 +1066,11 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(czml)); - - var entity = dataSource.entities.values[0]; - var resultCartesian = entity.billboard.alignedAxis.getValue(JulianDate.now()); - expect(resultCartesian).toEqual(Cartesian3.fromSpherical(new Spherical(1.0, 2.0))); + return dataSource.load(makePacket(czml)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + var resultCartesian = entity.billboard.alignedAxis.getValue(JulianDate.now()); + expect(resultCartesian).toEqual(Cartesian3.fromSpherical(new Spherical(1.0, 2.0))); + }); }); it('can handle a direction specified as sampled unitSpherical.', function() { @@ -1011,14 +1087,14 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(czml)); + return dataSource.load(makePacket(czml)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + var resultCartesian = entity.billboard.alignedAxis.getValue(epoch); + expect(resultCartesian).toEqual(Cartesian3.fromSpherical(new Spherical(1.0, 2.0))); - var entity = dataSource.entities.values[0]; - var resultCartesian = entity.billboard.alignedAxis.getValue(epoch); - expect(resultCartesian).toEqual(Cartesian3.fromSpherical(new Spherical(1.0, 2.0))); - - resultCartesian = entity.billboard.alignedAxis.getValue(JulianDate.addSeconds(epoch, 1, new JulianDate())); - expect(resultCartesian).toEqual(Cartesian3.fromSpherical(new Spherical(-1.0, -2.0))); + resultCartesian = entity.billboard.alignedAxis.getValue(JulianDate.addSeconds(epoch, 1, new JulianDate())); + expect(resultCartesian).toEqual(Cartesian3.fromSpherical(new Spherical(-1.0, -2.0))); + }); }); it('can handle a direction specified as constant spherical', function() { @@ -1031,11 +1107,13 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(czml)); - - var entity = dataSource.entities.values[0]; - var resultCartesian = entity.billboard.alignedAxis.getValue(JulianDate.now()); - expect(resultCartesian).toEqual(Cartesian3.fromSpherical(new Spherical(1.0, 2.0, 30.0))); + return dataSource.load(makePacket(czml)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + var resultCartesian = entity.billboard.alignedAxis.getValue(JulianDate.now()); + var expected = Cartesian3.fromSpherical(new Spherical(1.0, 2.0, 30.0)); + Cartesian3.normalize(expected, expected); + expect(resultCartesian).toEqual(expected); + }); }); it('can handle a direction specified as sampled spherical.', function() { @@ -1052,14 +1130,18 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(czml)); - - var entity = dataSource.entities.values[0]; - var resultCartesian = entity.billboard.alignedAxis.getValue(epoch); - expect(resultCartesian).toEqual(Cartesian3.fromSpherical(new Spherical(1.0, 2.0, 30.0))); - - resultCartesian = entity.billboard.alignedAxis.getValue(JulianDate.addSeconds(epoch, 1, new JulianDate())); - expect(resultCartesian).toEqual(Cartesian3.fromSpherical(new Spherical(-1.0, -2.0, 40.0))); + return dataSource.load(makePacket(czml)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + var resultCartesian = entity.billboard.alignedAxis.getValue(epoch); + var expected = Cartesian3.fromSpherical(new Spherical(1.0, 2.0, 30.0)); + Cartesian3.normalize(expected, expected); + expect(resultCartesian).toEqual(expected); + + resultCartesian = entity.billboard.alignedAxis.getValue(JulianDate.addSeconds(epoch, 1, new JulianDate())); + expected = Cartesian3.fromSpherical(new Spherical(-1.0, -2.0, 40.0)); + Cartesian3.normalize(expected, expected); + expect(resultCartesian).toEqual(expected); + }); }); it('CZML adds data for infinite ellipse.', function() { @@ -1078,17 +1160,18 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(ellipsePacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.ellipse).toBeDefined(); - expect(entity.ellipse.semiMajorAxis.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ellipsePacket.ellipse.semiMajorAxis); - expect(entity.ellipse.semiMinorAxis.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ellipsePacket.ellipse.semiMinorAxis); - expect(entity.ellipse.rotation.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ellipsePacket.ellipse.rotation); - expect(entity.ellipse.outline.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); - expect(entity.ellipse.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); - expect(entity.ellipse.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(6); - expect(entity.ellipse.shadows.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ShadowMode.ENABLED); + return dataSource.load(makePacket(ellipsePacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.ellipse).toBeDefined(); + expect(entity.ellipse.semiMajorAxis.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ellipsePacket.ellipse.semiMajorAxis); + expect(entity.ellipse.semiMinorAxis.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ellipsePacket.ellipse.semiMinorAxis); + expect(entity.ellipse.rotation.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ellipsePacket.ellipse.rotation); + expect(entity.ellipse.outline.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); + expect(entity.ellipse.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); + expect(entity.ellipse.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(6); + expect(entity.ellipse.shadows.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ShadowMode.ENABLED); + }); }); it('CZML adds data for constrained ellipse.', function() { @@ -1103,24 +1186,25 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(ellipsePacketInterval)); - var entity = dataSource.entities.values[0]; - - var validTime = TimeInterval.fromIso8601({ - iso8601 : ellipsePacketInterval.ellipse.interval - }).start; - var invalidTime = JulianDate.addSeconds(validTime, -1, new JulianDate()); - - expect(entity.ellipse).toBeDefined(); - expect(entity.ellipse.semiMajorAxis.getValue(validTime)).toEqual(ellipsePacketInterval.ellipse.semiMajorAxis); - expect(entity.ellipse.semiMinorAxis.getValue(validTime)).toEqual(ellipsePacketInterval.ellipse.semiMinorAxis); - expect(entity.ellipse.rotation.getValue(validTime)).toEqual(ellipsePacketInterval.ellipse.rotation); - expect(entity.ellipse.shadows.getValue(validTime)).toEqual(ShadowMode.ENABLED); - - expect(entity.ellipse.semiMajorAxis.getValue(invalidTime)).toBeUndefined(); - expect(entity.ellipse.semiMinorAxis.getValue(invalidTime)).toBeUndefined(); - expect(entity.ellipse.rotation.getValue(invalidTime)).toBeUndefined(); - expect(entity.ellipse.shadows.getValue(invalidTime)).toBeUndefined(); + return dataSource.load(makePacket(ellipsePacketInterval)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + var validTime = TimeInterval.fromIso8601({ + iso8601: ellipsePacketInterval.ellipse.interval + }).start; + var invalidTime = JulianDate.addSeconds(validTime, -1, new JulianDate()); + + expect(entity.ellipse).toBeDefined(); + expect(entity.ellipse.semiMajorAxis.getValue(validTime)).toEqual(ellipsePacketInterval.ellipse.semiMajorAxis); + expect(entity.ellipse.semiMinorAxis.getValue(validTime)).toEqual(ellipsePacketInterval.ellipse.semiMinorAxis); + expect(entity.ellipse.rotation.getValue(validTime)).toEqual(ellipsePacketInterval.ellipse.rotation); + expect(entity.ellipse.shadows.getValue(validTime)).toEqual(ShadowMode.ENABLED); + + expect(entity.ellipse.semiMajorAxis.getValue(invalidTime)).toBeUndefined(); + expect(entity.ellipse.semiMinorAxis.getValue(invalidTime)).toBeUndefined(); + expect(entity.ellipse.rotation.getValue(invalidTime)).toBeUndefined(); + expect(entity.ellipse.shadows.getValue(invalidTime)).toBeUndefined(); + }); }); it('CZML adds data for infinite ellipsoid.', function() { @@ -1152,20 +1236,21 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(ellipsoidPacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.ellipsoid).toBeDefined(); - expect(entity.ellipsoid.radii.getValue(Iso8601.MINIMUM_VALUE)).toEqual(expectedRadii); - expect(entity.ellipsoid.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ellipsoidPacket.ellipsoid.show); - expect(entity.ellipsoid.material.getValue(Iso8601.MINIMUM_VALUE).color).toEqual(new Color(0.1, 0.1, 0.1, 0.1)); - expect(entity.ellipsoid.outline.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); - expect(entity.ellipsoid.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); - expect(entity.ellipsoid.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(6); - expect(entity.ellipsoid.stackPartitions.getValue(Iso8601.MINIMUM_VALUE)).toEqual(25); - expect(entity.ellipsoid.slicePartitions.getValue(Iso8601.MINIMUM_VALUE)).toEqual(26); - expect(entity.ellipsoid.subdivisions.getValue(Iso8601.MINIMUM_VALUE)).toEqual(27); - expect(entity.ellipsoid.shadows.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ShadowMode.ENABLED); + return dataSource.load(makePacket(ellipsoidPacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.ellipsoid).toBeDefined(); + expect(entity.ellipsoid.radii.getValue(Iso8601.MINIMUM_VALUE)).toEqual(expectedRadii); + expect(entity.ellipsoid.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ellipsoidPacket.ellipsoid.show); + expect(entity.ellipsoid.material.getValue(Iso8601.MINIMUM_VALUE).color).toEqual(new Color(0.1, 0.1, 0.1, 0.1)); + expect(entity.ellipsoid.outline.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); + expect(entity.ellipsoid.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); + expect(entity.ellipsoid.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(6); + expect(entity.ellipsoid.stackPartitions.getValue(Iso8601.MINIMUM_VALUE)).toEqual(25); + expect(entity.ellipsoid.slicePartitions.getValue(Iso8601.MINIMUM_VALUE)).toEqual(26); + expect(entity.ellipsoid.subdivisions.getValue(Iso8601.MINIMUM_VALUE)).toEqual(27); + expect(entity.ellipsoid.shadows.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ShadowMode.ENABLED); + }); }); it('CZML adds data for constrained ellipsoid.', function() { @@ -1190,24 +1275,25 @@ defineSuite([ }; var validTime = TimeInterval.fromIso8601({ - iso8601 : ellipsoidPacketInterval.ellipsoid.interval + iso8601: ellipsoidPacketInterval.ellipsoid.interval }).start; var invalidTime = JulianDate.addSeconds(validTime, -1, new JulianDate()); var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(ellipsoidPacketInterval)); - var entity = dataSource.entities.values[0]; - - expect(entity.ellipsoid).toBeDefined(); - expect(entity.ellipsoid.radii.getValue(validTime)).toEqual(expectedRadii); - expect(entity.ellipsoid.show.getValue(validTime)).toEqual(ellipsoidPacketInterval.ellipsoid.show); - expect(entity.ellipsoid.material.getValue(validTime).color).toEqual(new Color(0.1, 0.1, 0.1, 0.1)); - expect(entity.ellipsoid.shadows.getValue(validTime)).toEqual(ShadowMode.ENABLED); - - expect(entity.ellipsoid.radii.getValue(invalidTime)).toBeUndefined(); - expect(entity.ellipsoid.show.getValue(invalidTime)).toBeUndefined(); - expect(entity.ellipsoid.material.getValue(invalidTime)).toBeUndefined(); - expect(entity.ellipsoid.shadows.getValue(invalidTime)).toBeUndefined(); + return dataSource.load(makePacket(ellipsoidPacketInterval)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.ellipsoid).toBeDefined(); + expect(entity.ellipsoid.radii.getValue(validTime)).toEqual(expectedRadii); + expect(entity.ellipsoid.show.getValue(validTime)).toEqual(ellipsoidPacketInterval.ellipsoid.show); + expect(entity.ellipsoid.material.getValue(validTime).color).toEqual(new Color(0.1, 0.1, 0.1, 0.1)); + expect(entity.ellipsoid.shadows.getValue(validTime)).toEqual(ShadowMode.ENABLED); + + expect(entity.ellipsoid.radii.getValue(invalidTime)).toBeUndefined(); + expect(entity.ellipsoid.show.getValue(invalidTime)).toBeUndefined(); + expect(entity.ellipsoid.material.getValue(invalidTime)).toBeUndefined(); + expect(entity.ellipsoid.shadows.getValue(invalidTime)).toBeUndefined(); + }); }); it('CZML adds data for infinite label.', function() { @@ -1243,24 +1329,25 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(labelPacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.label).toBeDefined(); - expect(entity.label.text.getValue(Iso8601.MINIMUM_VALUE)).toEqual(labelPacket.label.text); - expect(entity.label.font.getValue(Iso8601.MINIMUM_VALUE)).toEqual(labelPacket.label.font); - expect(entity.label.style.getValue(Iso8601.MINIMUM_VALUE)).toEqual(LabelStyle.FILL); - expect(entity.label.fillColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.1, 0.1, 0.1, 0.1)); - expect(entity.label.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); - expect(entity.label.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(labelPacket.label.outlineWidth); - expect(entity.label.horizontalOrigin.getValue(Iso8601.MINIMUM_VALUE)).toEqual(HorizontalOrigin.LEFT); - expect(entity.label.verticalOrigin.getValue(Iso8601.MINIMUM_VALUE)).toEqual(VerticalOrigin.CENTER); - expect(entity.label.eyeOffset.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Cartesian3(1.0, 2.0, 3.0)); - expect(entity.label.pixelOffset.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Cartesian2(4.0, 5.0)); - expect(entity.label.scale.getValue(Iso8601.MINIMUM_VALUE)).toEqual(labelPacket.label.scale); - expect(entity.label.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(labelPacket.label.show); - expect(entity.label.translucencyByDistance.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new NearFarScalar(1.0, 1.0, 10000.0, 0.0)); - expect(entity.label.pixelOffsetScaleByDistance.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new NearFarScalar(1.0, 20.0, 10000.0, 30.0)); + return dataSource.load(makePacket(labelPacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.label).toBeDefined(); + expect(entity.label.text.getValue(Iso8601.MINIMUM_VALUE)).toEqual(labelPacket.label.text); + expect(entity.label.font.getValue(Iso8601.MINIMUM_VALUE)).toEqual(labelPacket.label.font); + expect(entity.label.style.getValue(Iso8601.MINIMUM_VALUE)).toEqual(LabelStyle.FILL); + expect(entity.label.fillColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.1, 0.1, 0.1, 0.1)); + expect(entity.label.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); + expect(entity.label.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(labelPacket.label.outlineWidth); + expect(entity.label.horizontalOrigin.getValue(Iso8601.MINIMUM_VALUE)).toEqual(HorizontalOrigin.LEFT); + expect(entity.label.verticalOrigin.getValue(Iso8601.MINIMUM_VALUE)).toEqual(VerticalOrigin.CENTER); + expect(entity.label.eyeOffset.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Cartesian3(1.0, 2.0, 3.0)); + expect(entity.label.pixelOffset.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Cartesian2(4.0, 5.0)); + expect(entity.label.scale.getValue(Iso8601.MINIMUM_VALUE)).toEqual(labelPacket.label.scale); + expect(entity.label.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(labelPacket.label.show); + expect(entity.label.translucencyByDistance.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new NearFarScalar(1.0, 1.0, 10000.0, 0.0)); + expect(entity.label.pixelOffsetScaleByDistance.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new NearFarScalar(1.0, 20.0, 10000.0, 30.0)); + }); }); it('CZML adds data for constrained label.', function() { @@ -1291,39 +1378,40 @@ defineSuite([ }; var validTime = TimeInterval.fromIso8601({ - iso8601 : labelPacket.label.interval + iso8601: labelPacket.label.interval }).start; var invalidTime = JulianDate.addSeconds(validTime, -1, new JulianDate()); var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(labelPacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.label).toBeDefined(); - expect(entity.label.text.getValue(validTime)).toEqual(labelPacket.label.text); - expect(entity.label.font.getValue(validTime)).toEqual(labelPacket.label.font); - expect(entity.label.style.getValue(validTime)).toEqual(LabelStyle.FILL); - expect(entity.label.fillColor.getValue(validTime)).toEqual(new Color(0.1, 0.1, 0.1, 0.1)); - expect(entity.label.outlineColor.getValue(validTime)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); - expect(entity.label.outlineWidth.getValue(validTime)).toEqual(labelPacket.label.outlineWidth); - expect(entity.label.horizontalOrigin.getValue(validTime)).toEqual(HorizontalOrigin.LEFT); - expect(entity.label.verticalOrigin.getValue(validTime)).toEqual(VerticalOrigin.CENTER); - expect(entity.label.eyeOffset.getValue(validTime)).toEqual(new Cartesian3(1.0, 2.0, 3.0)); - expect(entity.label.pixelOffset.getValue(validTime)).toEqual(new Cartesian2(4.0, 5.0)); - expect(entity.label.scale.getValue(validTime)).toEqual(labelPacket.label.scale); - expect(entity.label.show.getValue(validTime)).toEqual(labelPacket.label.show); - expect(entity.label.text.getValue(invalidTime)).toBeUndefined(); - expect(entity.label.font.getValue(invalidTime)).toBeUndefined(); - expect(entity.label.style.getValue(invalidTime)).toBeUndefined(); - expect(entity.label.fillColor.getValue(invalidTime)).toBeUndefined(); - expect(entity.label.outlineColor.getValue(invalidTime)).toBeUndefined(); - expect(entity.label.outlineWidth.getValue(invalidTime)).toBeUndefined(); - expect(entity.label.horizontalOrigin.getValue(invalidTime)).toBeUndefined(); - expect(entity.label.verticalOrigin.getValue(invalidTime)).toBeUndefined(); - expect(entity.label.eyeOffset.getValue(invalidTime)).toBeUndefined(); - expect(entity.label.pixelOffset.getValue(invalidTime)).toBeUndefined(); - expect(entity.label.scale.getValue(invalidTime)).toBeUndefined(); - expect(entity.label.show.getValue(invalidTime)).toBeUndefined(); + return dataSource.load(makePacket(labelPacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.label).toBeDefined(); + expect(entity.label.text.getValue(validTime)).toEqual(labelPacket.label.text); + expect(entity.label.font.getValue(validTime)).toEqual(labelPacket.label.font); + expect(entity.label.style.getValue(validTime)).toEqual(LabelStyle.FILL); + expect(entity.label.fillColor.getValue(validTime)).toEqual(new Color(0.1, 0.1, 0.1, 0.1)); + expect(entity.label.outlineColor.getValue(validTime)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); + expect(entity.label.outlineWidth.getValue(validTime)).toEqual(labelPacket.label.outlineWidth); + expect(entity.label.horizontalOrigin.getValue(validTime)).toEqual(HorizontalOrigin.LEFT); + expect(entity.label.verticalOrigin.getValue(validTime)).toEqual(VerticalOrigin.CENTER); + expect(entity.label.eyeOffset.getValue(validTime)).toEqual(new Cartesian3(1.0, 2.0, 3.0)); + expect(entity.label.pixelOffset.getValue(validTime)).toEqual(new Cartesian2(4.0, 5.0)); + expect(entity.label.scale.getValue(validTime)).toEqual(labelPacket.label.scale); + expect(entity.label.show.getValue(validTime)).toEqual(labelPacket.label.show); + expect(entity.label.text.getValue(invalidTime)).toBeUndefined(); + expect(entity.label.font.getValue(invalidTime)).toBeUndefined(); + expect(entity.label.style.getValue(invalidTime)).toBeUndefined(); + expect(entity.label.fillColor.getValue(invalidTime)).toBeUndefined(); + expect(entity.label.outlineColor.getValue(invalidTime)).toBeUndefined(); + expect(entity.label.outlineWidth.getValue(invalidTime)).toBeUndefined(); + expect(entity.label.horizontalOrigin.getValue(invalidTime)).toBeUndefined(); + expect(entity.label.verticalOrigin.getValue(invalidTime)).toBeUndefined(); + expect(entity.label.eyeOffset.getValue(invalidTime)).toBeUndefined(); + expect(entity.label.pixelOffset.getValue(invalidTime)).toBeUndefined(); + expect(entity.label.scale.getValue(invalidTime)).toBeUndefined(); + expect(entity.label.show.getValue(invalidTime)).toBeUndefined(); + }); }); it('can handle sampled label pixelOffset.', function() { @@ -1339,14 +1427,15 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(labelPacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.label).toBeDefined(); - var date1 = epoch; - var date2 = JulianDate.addSeconds(epoch, 1.0, new JulianDate()); - expect(entity.label.pixelOffset.getValue(date1)).toEqual(new Cartesian2(1.0, 2.0)); - expect(entity.label.pixelOffset.getValue(date2)).toEqual(new Cartesian2(3.0, 4.0)); + return dataSource.load(makePacket(labelPacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.label).toBeDefined(); + var date1 = epoch; + var date2 = JulianDate.addSeconds(epoch, 1.0, new JulianDate()); + expect(entity.label.pixelOffset.getValue(date1)).toEqual(new Cartesian2(1.0, 2.0)); + expect(entity.label.pixelOffset.getValue(date2)).toEqual(new Cartesian2(3.0, 4.0)); + }); }); it('CZML Position works.', function() { @@ -1357,9 +1446,10 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - var entity = dataSource.entities.values[0]; - expect(entity.position.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Cartesian3(1.0, 2.0, 3.0)); + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + expect(entity.position.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Cartesian3(1.0, 2.0, 3.0)); + }); }); it('CZML Orientation works.', function() { @@ -1370,9 +1460,10 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - var entity = dataSource.entities.values[0]; - expect(entity.orientation.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Quaternion(0.0, 0.0, 0.0, 1.0)); + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + expect(entity.orientation.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Quaternion(0.0, 0.0, 0.0, 1.0)); + }); }); it('CZML Orientation is normalized on load.', function() { @@ -1386,9 +1477,10 @@ defineSuite([ Quaternion.normalize(expected, expected); var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - var entity = dataSource.entities.values[0]; - expect(entity.orientation.getValue(Iso8601.MINIMUM_VALUE)).toEqual(expected); + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + expect(entity.orientation.getValue(Iso8601.MINIMUM_VALUE)).toEqual(expected); + }); }); it('CZML Orientation is normalized on load.', function() { @@ -1407,10 +1499,40 @@ defineSuite([ Quaternion.normalize(expected2, expected2); var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - var entity = dataSource.entities.values[0]; - expect(entity.orientation.getValue(JulianDate.fromIso8601(time1))).toEqual(expected1); - expect(entity.orientation.getValue(JulianDate.fromIso8601(time2))).toEqual(expected2); + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + expect(entity.orientation.getValue(JulianDate.fromIso8601(time1))).toEqual(expected1); + expect(entity.orientation.getValue(JulianDate.fromIso8601(time2))).toEqual(expected2); + }); + }); + + it('can handle orientation expressed as a velocity reference', function() { + var packet = { + "position" : { + "epoch" : "2016-06-17T12:00:00Z", + "cartesian" : [0, 1, 2, 3, + 60, 61, 122, 183] + }, + "orientation": { + "velocityReference": "#position" + } + }; + + var dataSource = new CzmlDataSource(); + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + var property = entity.orientation; + + var expectedVelocity = new Cartesian3(1.0, 2.0, 3.0); + var expectedVelocityDirection = Cartesian3.normalize(expectedVelocity, new Cartesian3()); + + var expectedPosition = new Cartesian3(1, 2, 3); + var expectedRotation = Transforms.rotationMatrixFromPositionVelocity(expectedPosition, expectedVelocityDirection); + var expectedOrientation = Quaternion.fromRotationMatrix(expectedRotation); + + expect(property.getValue(JulianDate.fromIso8601('2016-06-17T12:00:00Z'))).toEqualEpsilon(expectedOrientation, CesiumMath.EPSILON15); + expect(property.getValue(JulianDate.fromIso8601('2016-06-17T12:00:30Z'))).toEqualEpsilon(expectedOrientation, CesiumMath.EPSILON15); + }); }); it('positions work with cartesians.', function() { @@ -1425,9 +1547,10 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - var entity = dataSource.entities.values[0]; - expect(entity.polyline.positions.getValue(Iso8601.MINIMUM_VALUE)).toEqual(expectedResult); + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + expect(entity.polyline.positions.getValue(Iso8601.MINIMUM_VALUE)).toEqual(expectedResult); + }); }); it('positions work with cartographicRadians.', function() { @@ -1443,9 +1566,10 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - var entity = dataSource.entities.values[0]; - expect(entity.polyline.positions.getValue(Iso8601.MINIMUM_VALUE)).toEqual(expectedResult); + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + expect(entity.polyline.positions.getValue(Iso8601.MINIMUM_VALUE)).toEqual(expectedResult); + }); }); it('positions work with cartographicDegrees.', function() { @@ -1463,9 +1587,10 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - var entity = dataSource.entities.values[0]; - expect(entity.polyline.positions.getValue(Iso8601.MINIMUM_VALUE)).toEqual(expectedResult); + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + expect(entity.polyline.positions.getValue(Iso8601.MINIMUM_VALUE)).toEqual(expectedResult); + }); }); it('CZML ViewFrom works.', function() { @@ -1476,9 +1601,10 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - var entity = dataSource.entities.values[0]; - expect(entity.viewFrom.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Cartesian3(1.0, 2.0, 3.0)); + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + expect(entity.viewFrom.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Cartesian3(1.0, 2.0, 3.0)); + }); }); it('CZML description works.', function() { @@ -1487,9 +1613,10 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - var entity = dataSource.entities.values[0]; - expect(entity.description.getValue(Iso8601.MINIMUM_VALUE)).toEqual(packet.description); + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + expect(entity.description.getValue(Iso8601.MINIMUM_VALUE)).toEqual(packet.description); + }); }); it('works with properties that are constant.', function() { @@ -1514,12 +1641,13 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - var entity = dataSource.entities.values[0]; - expect(entity.properties.constant_name.getValue(Iso8601.MINIMUM_VALUE)).toEqual(packet.properties.constant_name); - expect(entity.properties.constant_height.getValue(Iso8601.MINIMUM_VALUE)).toEqual(packet.properties.constant_height); - expect(entity.properties.constant_object.getValue(Iso8601.MINIMUM_VALUE)).toEqual(testObject); - expect(entity.properties.constant_array.getValue(Iso8601.MINIMUM_VALUE)).toEqual(testArray); + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + expect(entity.properties.constant_name.getValue(Iso8601.MINIMUM_VALUE)).toEqual(packet.properties.constant_name); + expect(entity.properties.constant_height.getValue(Iso8601.MINIMUM_VALUE)).toEqual(packet.properties.constant_height); + expect(entity.properties.constant_object.getValue(Iso8601.MINIMUM_VALUE)).toEqual(testObject); + expect(entity.properties.constant_array.getValue(Iso8601.MINIMUM_VALUE)).toEqual(testArray); + }); }); it('works with properties which are constant with specified type.', function() { @@ -1548,12 +1676,13 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - var entity = dataSource.entities.values[0]; - expect(entity.properties.constant_name.getValue(Iso8601.MINIMUM_VALUE)).toEqual(packet.properties.constant_name.string); - expect(entity.properties.constant_height.getValue(Iso8601.MINIMUM_VALUE)).toEqual(packet.properties.constant_height.number); - expect(entity.properties.constant_object.getValue(Iso8601.MINIMUM_VALUE)).toEqual(testObject); - expect(entity.properties.constant_array.getValue(Iso8601.MINIMUM_VALUE)).toEqual(testArray); + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + expect(entity.properties.constant_name.getValue(Iso8601.MINIMUM_VALUE)).toEqual(packet.properties.constant_name.string); + expect(entity.properties.constant_height.getValue(Iso8601.MINIMUM_VALUE)).toEqual(packet.properties.constant_height.number); + expect(entity.properties.constant_object.getValue(Iso8601.MINIMUM_VALUE)).toEqual(testObject); + expect(entity.properties.constant_array.getValue(Iso8601.MINIMUM_VALUE)).toEqual(testArray); + }); }); it('works with properties with one interval.', function() { @@ -1567,14 +1696,15 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - var entity = dataSource.entities.values[0]; + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; - var time1 = JulianDate.fromIso8601('2013'); - var time2 = JulianDate.fromIso8601('2015'); + var time1 = JulianDate.fromIso8601('2013'); + var time2 = JulianDate.fromIso8601('2015'); - expect(entity.properties.changing_name.getValue(time1)).toEqual('ABC'); - expect(entity.properties.changing_name.getValue(time2)).toBeUndefined(); + expect(entity.properties.changing_name.getValue(time1)).toEqual('ABC'); + expect(entity.properties.changing_name.getValue(time2)).toBeUndefined(); + }); }); it('works with properties with one interval with specified type.', function() { @@ -1588,14 +1718,15 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - var entity = dataSource.entities.values[0]; + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; - var time1 = JulianDate.fromIso8601('2013'); - var time2 = JulianDate.fromIso8601('2015'); + var time1 = JulianDate.fromIso8601('2013'); + var time2 = JulianDate.fromIso8601('2015'); - expect(entity.properties.changing_name.getValue(time1)).toEqual('ABC'); - expect(entity.properties.changing_name.getValue(time2)).toBeUndefined(); + expect(entity.properties.changing_name.getValue(time1)).toEqual('ABC'); + expect(entity.properties.changing_name.getValue(time2)).toBeUndefined(); + }); }); it('works with properties with multiple intervals.', function() { @@ -1617,14 +1748,15 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - var entity = dataSource.entities.values[0]; + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; - var time1 = JulianDate.fromIso8601('2012-06-01'); - var time2 = JulianDate.fromIso8601('2013-06-01'); + var time1 = JulianDate.fromIso8601('2012-06-01'); + var time2 = JulianDate.fromIso8601('2013-06-01'); - expect(entity.properties.changing_array.getValue(time1)).toEqual(array1); - expect(entity.properties.changing_array.getValue(time2)).toEqual(array2); + expect(entity.properties.changing_array.getValue(time1)).toEqual(array1); + expect(entity.properties.changing_array.getValue(time2)).toEqual(array2); + }); }); it('handles boolean custom properties with intervals.', function() { @@ -1649,15 +1781,16 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - var entity = dataSource.entities.getById('MyID'); - expect(entity).toBeDefined(); - expect(entity.properties).toBeDefined(); - expect(entity.properties.custom_boolean).toBeDefined(); - - expect(entity.properties.custom_boolean.getValue(JulianDate.fromIso8601('2012-04-02T12:00:00Z'))).toEqual(true); - expect(entity.properties.custom_boolean.getValue(JulianDate.fromIso8601('2012-04-02T12:00:01Z'))).toEqual(false); - expect(entity.properties.custom_boolean.getValue(JulianDate.fromIso8601('2012-04-02T12:00:02Z'))).toEqual(true); + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.getById('MyID'); + expect(entity).toBeDefined(); + expect(entity.properties).toBeDefined(); + expect(entity.properties.custom_boolean).toBeDefined(); + + expect(entity.properties.custom_boolean.getValue(JulianDate.fromIso8601('2012-04-02T12:00:00Z'))).toEqual(true); + expect(entity.properties.custom_boolean.getValue(JulianDate.fromIso8601('2012-04-02T12:00:01Z'))).toEqual(false); + expect(entity.properties.custom_boolean.getValue(JulianDate.fromIso8601('2012-04-02T12:00:02Z'))).toEqual(true); + }); }); it('works with properties with multiple intervals with specified type.', function() { @@ -1679,14 +1812,15 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - var entity = dataSource.entities.values[0]; + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; - var time1 = JulianDate.fromIso8601('2012-06-01'); - var time2 = JulianDate.fromIso8601('2013-06-01'); + var time1 = JulianDate.fromIso8601('2012-06-01'); + var time2 = JulianDate.fromIso8601('2013-06-01'); - expect(entity.properties.changing_array.getValue(time1)).toEqual(array1); - expect(entity.properties.changing_array.getValue(time2)).toEqual(array2); + expect(entity.properties.changing_array.getValue(time1)).toEqual(array1); + expect(entity.properties.changing_array.getValue(time2)).toEqual(array2); + }); }); it('handles sampled custom properties.', function() { @@ -1705,18 +1839,19 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - var entity = dataSource.entities.getById('MyID'); - expect(entity).toBeDefined(); - expect(entity.properties).toBeDefined(); - expect(entity.properties.custom_cartesian).toBeDefined(); - - expect(entity.properties.custom_cartesian.getValue(JulianDate.fromIso8601('2012-04-02T12:00:00Z'))).toBeInstanceOf(Cartesian3); - expect(entity.properties.custom_cartesian.getValue(JulianDate.fromIso8601('2012-04-02T12:00:00Z'))).toEqual(new Cartesian3(1, 2, 3)); - // halfway between two samples, linearly interpolated - expect(entity.properties.custom_cartesian.getValue(JulianDate.fromIso8601('2012-04-02T12:00:30Z'))).toEqual(new Cartesian3((1 + 4) / 2, (2 + 5) / 2, (3 + 6) / 2)); - expect(entity.properties.custom_cartesian.getValue(JulianDate.fromIso8601('2012-04-02T12:01:00Z'))).toEqual(new Cartesian3(4, 5, 6)); - expect(entity.properties.custom_cartesian.getValue(JulianDate.fromIso8601('2012-04-02T12:02:00Z'))).toEqual(new Cartesian3(7, 8, 9)); + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.getById('MyID'); + expect(entity).toBeDefined(); + expect(entity.properties).toBeDefined(); + expect(entity.properties.custom_cartesian).toBeDefined(); + + expect(entity.properties.custom_cartesian.getValue(JulianDate.fromIso8601('2012-04-02T12:00:00Z'))).toBeInstanceOf(Cartesian3); + expect(entity.properties.custom_cartesian.getValue(JulianDate.fromIso8601('2012-04-02T12:00:00Z'))).toEqual(new Cartesian3(1, 2, 3)); + // halfway between two samples, linearly interpolated + expect(entity.properties.custom_cartesian.getValue(JulianDate.fromIso8601('2012-04-02T12:00:30Z'))).toEqual(new Cartesian3((1 + 4) / 2, (2 + 5) / 2, (3 + 6) / 2)); + expect(entity.properties.custom_cartesian.getValue(JulianDate.fromIso8601('2012-04-02T12:01:00Z'))).toEqual(new Cartesian3(4, 5, 6)); + expect(entity.properties.custom_cartesian.getValue(JulianDate.fromIso8601('2012-04-02T12:02:00Z'))).toEqual(new Cartesian3(7, 8, 9)); + }); }); it('handles various types of custom properties.', function() { @@ -1848,94 +1983,95 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - var entity = dataSource.entities.getById('MyID'); - expect(entity).toBeDefined(); - expect(entity.properties).toBeDefined(); - - var time1 = JulianDate.fromIso8601('2012-06-01'); - var time2 = JulianDate.fromIso8601('2013-06-01'); - - expect(entity.properties.custom_array_constant).toBeDefined(); - expect(entity.properties.custom_array_constant.getValue(time1)).toBeInstanceOf(Array); - expect(entity.properties.custom_array_constant.getValue(time1)).toEqual(packet.properties.custom_array_constant.array); - - expect(entity.properties.custom_array_interval).toBeDefined(); - expect(entity.properties.custom_array_interval.getValue(time1)).toBeInstanceOf(Array); - expect(entity.properties.custom_array_interval.getValue(time1)).toEqual(packet.properties.custom_array_interval[0].array); - expect(entity.properties.custom_array_interval.getValue(time2)).toEqual(packet.properties.custom_array_interval[1].array); - - expect(entity.properties.custom_boolean_constant).toBeDefined(); - expect(entity.properties.custom_boolean_constant.getValue(time1)).toEqual(packet.properties.custom_boolean_constant.boolean); - - expect(entity.properties.custom_boolean_interval).toBeDefined(); - expect(entity.properties.custom_boolean_interval.getValue(time1)).toEqual(packet.properties.custom_boolean_interval[0].boolean); - expect(entity.properties.custom_boolean_interval.getValue(time2)).toEqual(packet.properties.custom_boolean_interval[1].boolean); - - expect(entity.properties.custom_boundingRectangle_constant).toBeDefined(); - expect(entity.properties.custom_boundingRectangle_constant.getValue(time1)).toBeInstanceOf(BoundingRectangle); - expect(entity.properties.custom_boundingRectangle_constant.getValue(time1)).toEqual(BoundingRectangle.unpack(packet.properties.custom_boundingRectangle_constant.boundingRectangle)); - - expect(entity.properties.custom_boundingRectangle_interval).toBeDefined(); - expect(entity.properties.custom_boundingRectangle_interval.getValue(time1)).toBeInstanceOf(BoundingRectangle); - expect(entity.properties.custom_boundingRectangle_interval.getValue(time1)).toEqual(BoundingRectangle.unpack(packet.properties.custom_boundingRectangle_interval[0].boundingRectangle)); - expect(entity.properties.custom_boundingRectangle_interval.getValue(time2)).toEqual(BoundingRectangle.unpack(packet.properties.custom_boundingRectangle_interval[1].boundingRectangle)); - - expect(entity.properties.custom_boundingRectangle_sampled).toBeDefined(); - expect(entity.properties.custom_boundingRectangle_sampled.getValue(time1)).toBeInstanceOf(BoundingRectangle); - expect(entity.properties.custom_boundingRectangle_sampled.getValue(time1)).toEqual(BoundingRectangle.unpack(packet.properties.custom_boundingRectangle_sampled.boundingRectangle, 0 + 1)); - expect(entity.properties.custom_boundingRectangle_sampled.getValue(JulianDate.addSeconds(time1, 60, new JulianDate()))).toEqual(BoundingRectangle.unpack(packet.properties.custom_boundingRectangle_sampled.boundingRectangle, 4 + 2)); - - expect(entity.properties.custom_cartesian2_constant).toBeDefined(); - expect(entity.properties.custom_cartesian2_constant.getValue(time1)).toBeInstanceOf(Cartesian2); - expect(entity.properties.custom_cartesian2_constant.getValue(time1)).toEqual(Cartesian2.unpack(packet.properties.custom_cartesian2_constant.cartesian2)); - - expect(entity.properties.custom_cartesian2_interval).toBeDefined(); - expect(entity.properties.custom_cartesian2_interval.getValue(time1)).toBeInstanceOf(Cartesian2); - expect(entity.properties.custom_cartesian2_interval.getValue(time1)).toEqual(Cartesian2.unpack(packet.properties.custom_cartesian2_interval[0].cartesian2)); - expect(entity.properties.custom_cartesian2_interval.getValue(time2)).toEqual(Cartesian2.unpack(packet.properties.custom_cartesian2_interval[1].cartesian2)); - - expect(entity.properties.custom_cartesian2_sampled).toBeDefined(); - expect(entity.properties.custom_cartesian2_sampled.getValue(time1)).toBeInstanceOf(Cartesian2); - expect(entity.properties.custom_cartesian2_sampled.getValue(time1)).toEqual(Cartesian2.unpack(packet.properties.custom_cartesian2_sampled.cartesian2, 0 + 1)); - expect(entity.properties.custom_cartesian2_sampled.getValue(JulianDate.addSeconds(time1, 60, new JulianDate()))).toEqual(Cartesian2.unpack(packet.properties.custom_cartesian2_sampled.cartesian2, 2 + 2)); - - expect(entity.properties.custom_cartesian_constant).toBeDefined(); - expect(entity.properties.custom_cartesian_constant.getValue(time1)).toBeInstanceOf(Cartesian3); - expect(entity.properties.custom_cartesian_constant.getValue(time1)).toEqual(Cartesian3.unpack(packet.properties.custom_cartesian_constant.cartesian)); - - expect(entity.properties.custom_cartesian_interval).toBeDefined(); - expect(entity.properties.custom_cartesian_interval.getValue(time1)).toBeInstanceOf(Cartesian3); - expect(entity.properties.custom_cartesian_interval.getValue(time1)).toEqual(Cartesian3.unpack(packet.properties.custom_cartesian_interval[0].cartesian)); - expect(entity.properties.custom_cartesian_interval.getValue(time2)).toEqual(Cartesian3.unpack(packet.properties.custom_cartesian_interval[1].cartesian)); - - expect(entity.properties.custom_cartesian_sampled).toBeDefined(); - expect(entity.properties.custom_cartesian_sampled.getValue(time1)).toBeInstanceOf(Cartesian3); - expect(entity.properties.custom_cartesian_sampled.getValue(time1)).toEqual(Cartesian3.unpack(packet.properties.custom_cartesian_sampled.cartesian, 0 + 1)); - expect(entity.properties.custom_cartesian_sampled.getValue(JulianDate.addSeconds(time1, 60, new JulianDate()))).toEqual(Cartesian3.unpack(packet.properties.custom_cartesian_sampled.cartesian, 3 + 2)); - - expect(entity.properties.custom_color_constant).toBeDefined(); - expect(entity.properties.custom_color_constant.getValue(time1)).toBeInstanceOf(Color); - expect(entity.properties.custom_color_constant.getValue(time1)).toEqual(Color.unpack(packet.properties.custom_color_constant.rgbaf)); - - expect(entity.properties.custom_color_interval).toBeDefined(); - expect(entity.properties.custom_color_interval.getValue(time1)).toBeInstanceOf(Color); - expect(entity.properties.custom_color_interval.getValue(time1)).toEqual(Color.unpack(packet.properties.custom_color_interval[0].rgbaf)); - expect(entity.properties.custom_color_interval.getValue(time2)).toEqual(Color.unpack(packet.properties.custom_color_interval[1].rgbaf)); - - expect(entity.properties.custom_color_sampled).toBeDefined(); - expect(entity.properties.custom_color_sampled.getValue(time1)).toBeInstanceOf(Color); - expect(entity.properties.custom_color_sampled.getValue(time1)).toEqual(Color.unpack(packet.properties.custom_color_sampled.rgbaf, 0 + 1)); - expect(entity.properties.custom_color_sampled.getValue(JulianDate.addSeconds(time1, 60, new JulianDate()))).toEqual(Color.unpack(packet.properties.custom_color_sampled.rgbaf, 4 + 2)); - - expect(entity.properties.custom_date_constant).toBeDefined(); - expect(entity.properties.custom_date_constant.getValue(time1)).toBeInstanceOf(JulianDate); - expect(entity.properties.custom_date_constant.getValue(time1)).toEqual(JulianDate.fromIso8601(packet.properties.custom_date_constant.date)); - - expect(entity.properties.custom_date_interval).toBeDefined(); - expect(entity.properties.custom_date_interval.getValue(time1)).toBeInstanceOf(JulianDate); - expect(entity.properties.custom_date_interval.getValue(time1)).toEqual(JulianDate.fromIso8601(packet.properties.custom_date_interval[0].date)); - expect(entity.properties.custom_date_interval.getValue(time2)).toEqual(JulianDate.fromIso8601(packet.properties.custom_date_interval[1].date)); + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.getById('MyID'); + expect(entity).toBeDefined(); + expect(entity.properties).toBeDefined(); + + var time1 = JulianDate.fromIso8601('2012-06-01'); + var time2 = JulianDate.fromIso8601('2013-06-01'); + + expect(entity.properties.custom_array_constant).toBeDefined(); + expect(entity.properties.custom_array_constant.getValue(time1)).toBeInstanceOf(Array); + expect(entity.properties.custom_array_constant.getValue(time1)).toEqual(packet.properties.custom_array_constant.array); + + expect(entity.properties.custom_array_interval).toBeDefined(); + expect(entity.properties.custom_array_interval.getValue(time1)).toBeInstanceOf(Array); + expect(entity.properties.custom_array_interval.getValue(time1)).toEqual(packet.properties.custom_array_interval[0].array); + expect(entity.properties.custom_array_interval.getValue(time2)).toEqual(packet.properties.custom_array_interval[1].array); + + expect(entity.properties.custom_boolean_constant).toBeDefined(); + expect(entity.properties.custom_boolean_constant.getValue(time1)).toEqual(packet.properties.custom_boolean_constant.boolean); + + expect(entity.properties.custom_boolean_interval).toBeDefined(); + expect(entity.properties.custom_boolean_interval.getValue(time1)).toEqual(packet.properties.custom_boolean_interval[0].boolean); + expect(entity.properties.custom_boolean_interval.getValue(time2)).toEqual(packet.properties.custom_boolean_interval[1].boolean); + + expect(entity.properties.custom_boundingRectangle_constant).toBeDefined(); + expect(entity.properties.custom_boundingRectangle_constant.getValue(time1)).toBeInstanceOf(BoundingRectangle); + expect(entity.properties.custom_boundingRectangle_constant.getValue(time1)).toEqual(BoundingRectangle.unpack(packet.properties.custom_boundingRectangle_constant.boundingRectangle)); + + expect(entity.properties.custom_boundingRectangle_interval).toBeDefined(); + expect(entity.properties.custom_boundingRectangle_interval.getValue(time1)).toBeInstanceOf(BoundingRectangle); + expect(entity.properties.custom_boundingRectangle_interval.getValue(time1)).toEqual(BoundingRectangle.unpack(packet.properties.custom_boundingRectangle_interval[0].boundingRectangle)); + expect(entity.properties.custom_boundingRectangle_interval.getValue(time2)).toEqual(BoundingRectangle.unpack(packet.properties.custom_boundingRectangle_interval[1].boundingRectangle)); + + expect(entity.properties.custom_boundingRectangle_sampled).toBeDefined(); + expect(entity.properties.custom_boundingRectangle_sampled.getValue(time1)).toBeInstanceOf(BoundingRectangle); + expect(entity.properties.custom_boundingRectangle_sampled.getValue(time1)).toEqual(BoundingRectangle.unpack(packet.properties.custom_boundingRectangle_sampled.boundingRectangle, 0 + 1)); + expect(entity.properties.custom_boundingRectangle_sampled.getValue(JulianDate.addSeconds(time1, 60, new JulianDate()))).toEqual(BoundingRectangle.unpack(packet.properties.custom_boundingRectangle_sampled.boundingRectangle, 4 + 2)); + + expect(entity.properties.custom_cartesian2_constant).toBeDefined(); + expect(entity.properties.custom_cartesian2_constant.getValue(time1)).toBeInstanceOf(Cartesian2); + expect(entity.properties.custom_cartesian2_constant.getValue(time1)).toEqual(Cartesian2.unpack(packet.properties.custom_cartesian2_constant.cartesian2)); + + expect(entity.properties.custom_cartesian2_interval).toBeDefined(); + expect(entity.properties.custom_cartesian2_interval.getValue(time1)).toBeInstanceOf(Cartesian2); + expect(entity.properties.custom_cartesian2_interval.getValue(time1)).toEqual(Cartesian2.unpack(packet.properties.custom_cartesian2_interval[0].cartesian2)); + expect(entity.properties.custom_cartesian2_interval.getValue(time2)).toEqual(Cartesian2.unpack(packet.properties.custom_cartesian2_interval[1].cartesian2)); + + expect(entity.properties.custom_cartesian2_sampled).toBeDefined(); + expect(entity.properties.custom_cartesian2_sampled.getValue(time1)).toBeInstanceOf(Cartesian2); + expect(entity.properties.custom_cartesian2_sampled.getValue(time1)).toEqual(Cartesian2.unpack(packet.properties.custom_cartesian2_sampled.cartesian2, 0 + 1)); + expect(entity.properties.custom_cartesian2_sampled.getValue(JulianDate.addSeconds(time1, 60, new JulianDate()))).toEqual(Cartesian2.unpack(packet.properties.custom_cartesian2_sampled.cartesian2, 2 + 2)); + + expect(entity.properties.custom_cartesian_constant).toBeDefined(); + expect(entity.properties.custom_cartesian_constant.getValue(time1)).toBeInstanceOf(Cartesian3); + expect(entity.properties.custom_cartesian_constant.getValue(time1)).toEqual(Cartesian3.unpack(packet.properties.custom_cartesian_constant.cartesian)); + + expect(entity.properties.custom_cartesian_interval).toBeDefined(); + expect(entity.properties.custom_cartesian_interval.getValue(time1)).toBeInstanceOf(Cartesian3); + expect(entity.properties.custom_cartesian_interval.getValue(time1)).toEqual(Cartesian3.unpack(packet.properties.custom_cartesian_interval[0].cartesian)); + expect(entity.properties.custom_cartesian_interval.getValue(time2)).toEqual(Cartesian3.unpack(packet.properties.custom_cartesian_interval[1].cartesian)); + + expect(entity.properties.custom_cartesian_sampled).toBeDefined(); + expect(entity.properties.custom_cartesian_sampled.getValue(time1)).toBeInstanceOf(Cartesian3); + expect(entity.properties.custom_cartesian_sampled.getValue(time1)).toEqual(Cartesian3.unpack(packet.properties.custom_cartesian_sampled.cartesian, 0 + 1)); + expect(entity.properties.custom_cartesian_sampled.getValue(JulianDate.addSeconds(time1, 60, new JulianDate()))).toEqual(Cartesian3.unpack(packet.properties.custom_cartesian_sampled.cartesian, 3 + 2)); + + expect(entity.properties.custom_color_constant).toBeDefined(); + expect(entity.properties.custom_color_constant.getValue(time1)).toBeInstanceOf(Color); + expect(entity.properties.custom_color_constant.getValue(time1)).toEqual(Color.unpack(packet.properties.custom_color_constant.rgbaf)); + + expect(entity.properties.custom_color_interval).toBeDefined(); + expect(entity.properties.custom_color_interval.getValue(time1)).toBeInstanceOf(Color); + expect(entity.properties.custom_color_interval.getValue(time1)).toEqual(Color.unpack(packet.properties.custom_color_interval[0].rgbaf)); + expect(entity.properties.custom_color_interval.getValue(time2)).toEqual(Color.unpack(packet.properties.custom_color_interval[1].rgbaf)); + + expect(entity.properties.custom_color_sampled).toBeDefined(); + expect(entity.properties.custom_color_sampled.getValue(time1)).toBeInstanceOf(Color); + expect(entity.properties.custom_color_sampled.getValue(time1)).toEqual(Color.unpack(packet.properties.custom_color_sampled.rgbaf, 0 + 1)); + expect(entity.properties.custom_color_sampled.getValue(JulianDate.addSeconds(time1, 60, new JulianDate()))).toEqual(Color.unpack(packet.properties.custom_color_sampled.rgbaf, 4 + 2)); + + expect(entity.properties.custom_date_constant).toBeDefined(); + expect(entity.properties.custom_date_constant.getValue(time1)).toBeInstanceOf(JulianDate); + expect(entity.properties.custom_date_constant.getValue(time1)).toEqual(JulianDate.fromIso8601(packet.properties.custom_date_constant.date)); + + expect(entity.properties.custom_date_interval).toBeDefined(); + expect(entity.properties.custom_date_interval.getValue(time1)).toBeInstanceOf(JulianDate); + expect(entity.properties.custom_date_interval.getValue(time1)).toEqual(JulianDate.fromIso8601(packet.properties.custom_date_interval[0].date)); + expect(entity.properties.custom_date_interval.getValue(time2)).toEqual(JulianDate.fromIso8601(packet.properties.custom_date_interval[1].date)); + }); }); it('handles properties in a way that allows CompositeEntityCollection to work', function() { @@ -2022,27 +2158,29 @@ defineSuite([ availability : '2000-01-01/2001-01-01' }; - var dataSource = new CzmlDataSource(); - dataSource.process(makePacket(packet1)); - var entity = dataSource.entities.values[0]; - - var interval = TimeInterval.fromIso8601({ - iso8601 : packet1.availability - }); - expect(entity.availability.length).toEqual(1); - expect(entity.availability.get(0)).toEqual(interval); - var packet2 = { - id : 'testObject', - availability : '2000-02-02/2001-02-02' + id: 'testObject', + availability: '2000-02-02/2001-02-02' }; - dataSource.process(packet2); - interval = TimeInterval.fromIso8601({ - iso8601 : packet2.availability + var dataSource = new CzmlDataSource(); + return dataSource.process(makePacket(packet1)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + var interval = TimeInterval.fromIso8601({ + iso8601: packet1.availability + }); + expect(entity.availability.length).toEqual(1); + expect(entity.availability.get(0)).toEqual(interval); + + return dataSource.process(packet2); + }).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + var interval = TimeInterval.fromIso8601({ + iso8601: packet2.availability + }); + expect(entity.availability.length).toEqual(1); + expect(entity.availability.get(0)).toEqual(interval); }); - expect(entity.availability.length).toEqual(1); - expect(entity.availability.get(0)).toEqual(interval); }); it('CZML Availability works with multiple intervals.', function() { @@ -2050,36 +2188,38 @@ defineSuite([ id : 'testObject', availability : ['2000-01-01/2001-01-01', '2002-01-01/2003-01-01'] }; - - var dataSource = new CzmlDataSource(); - dataSource.process(makePacket(packet1)); - var entity = dataSource.entities.values[0]; - - var interval1 = TimeInterval.fromIso8601({ - iso8601 : packet1.availability[0] - }); - var interval2 = TimeInterval.fromIso8601({ - iso8601 : packet1.availability[1] - }); - expect(entity.availability.length).toEqual(2); - expect(entity.availability.get(0)).toEqual(interval1); - expect(entity.availability.get(1)).toEqual(interval2); - var packet2 = { id : 'testObject', availability : ['2003-01-01/2004-01-01', '2005-01-01/2006-01-01'] }; - dataSource.process(packet2); - interval1 = TimeInterval.fromIso8601({ - iso8601 : packet2.availability[0] - }); - interval2 = TimeInterval.fromIso8601({ - iso8601 : packet2.availability[1] + var dataSource = new CzmlDataSource(); + return dataSource.process(makePacket(packet1)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + var interval1 = TimeInterval.fromIso8601({ + iso8601: packet1.availability[0] + }); + var interval2 = TimeInterval.fromIso8601({ + iso8601: packet1.availability[1] + }); + expect(entity.availability.length).toEqual(2); + expect(entity.availability.get(0)).toEqual(interval1); + expect(entity.availability.get(1)).toEqual(interval2); + + return dataSource.process(packet2); + }).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + var interval1 = TimeInterval.fromIso8601({ + iso8601: packet2.availability[0] + }); + var interval2 = TimeInterval.fromIso8601({ + iso8601: packet2.availability[1] + }); + expect(entity.availability.length).toEqual(2); + expect(entity.availability.get(0)).toEqual(interval1); + expect(entity.availability.get(1)).toEqual(interval2); }); - expect(entity.availability.length).toEqual(2); - expect(entity.availability.get(0)).toEqual(interval1); - expect(entity.availability.get(1)).toEqual(interval2); }); it('CZML adds data for infinite path.', function() { @@ -2105,18 +2245,19 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(pathPacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.path).toBeDefined(); - expect(entity.path.material.color.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.1, 0.1, 0.1, 0.1)); - expect(entity.path.width.getValue(Iso8601.MINIMUM_VALUE)).toEqual(pathPacket.path.width); - expect(entity.path.resolution.getValue(Iso8601.MINIMUM_VALUE)).toEqual(pathPacket.path.resolution); - expect(entity.path.material.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); - expect(entity.path.material.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(1.0); - expect(entity.path.leadTime.getValue(Iso8601.MINIMUM_VALUE)).toEqual(pathPacket.path.leadTime); - expect(entity.path.trailTime.getValue(Iso8601.MINIMUM_VALUE)).toEqual(pathPacket.path.trailTime); - expect(entity.path.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); + return dataSource.load(makePacket(pathPacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.path).toBeDefined(); + expect(entity.path.material.color.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.1, 0.1, 0.1, 0.1)); + expect(entity.path.width.getValue(Iso8601.MINIMUM_VALUE)).toEqual(pathPacket.path.width); + expect(entity.path.resolution.getValue(Iso8601.MINIMUM_VALUE)).toEqual(pathPacket.path.resolution); + expect(entity.path.material.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); + expect(entity.path.material.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(1.0); + expect(entity.path.leadTime.getValue(Iso8601.MINIMUM_VALUE)).toEqual(pathPacket.path.leadTime); + expect(entity.path.trailTime.getValue(Iso8601.MINIMUM_VALUE)).toEqual(pathPacket.path.trailTime); + expect(entity.path.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); + }); }); it('CZML adds data for constrained path.', function() { @@ -2148,24 +2289,25 @@ defineSuite([ var invalidTime = JulianDate.addSeconds(validTime, -1, new JulianDate()); var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(pathPacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.path).toBeDefined(); - expect(entity.path.width.getValue(validTime)).toEqual(pathPacket.path.width); - expect(entity.path.resolution.getValue(validTime)).toEqual(pathPacket.path.resolution); - expect(entity.path.leadTime.getValue(validTime)).toEqual(pathPacket.path.leadTime); - expect(entity.path.trailTime.getValue(validTime)).toEqual(pathPacket.path.trailTime); - expect(entity.path.show.getValue(validTime)).toEqual(true); - expect(entity.path.material.getValue(validTime).color).toEqual(new Color(0.1, 0.1, 0.1, 0.1)); - expect(entity.path.material.getValue(validTime).outlineColor).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); - expect(entity.path.material.getValue(validTime).outlineWidth).toEqual(1.0); - - expect(entity.path.material.getValue(invalidTime)).toBeUndefined(); - expect(entity.path.width.getValue(invalidTime)).toBeUndefined(); - expect(entity.path.leadTime.getValue(invalidTime)).toBeUndefined(); - expect(entity.path.trailTime.getValue(invalidTime)).toBeUndefined(); - expect(entity.path.show.getValue(invalidTime)).toBeUndefined(); + return dataSource.load(makePacket(pathPacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.path).toBeDefined(); + expect(entity.path.width.getValue(validTime)).toEqual(pathPacket.path.width); + expect(entity.path.resolution.getValue(validTime)).toEqual(pathPacket.path.resolution); + expect(entity.path.leadTime.getValue(validTime)).toEqual(pathPacket.path.leadTime); + expect(entity.path.trailTime.getValue(validTime)).toEqual(pathPacket.path.trailTime); + expect(entity.path.show.getValue(validTime)).toEqual(true); + expect(entity.path.material.getValue(validTime).color).toEqual(new Color(0.1, 0.1, 0.1, 0.1)); + expect(entity.path.material.getValue(validTime).outlineColor).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); + expect(entity.path.material.getValue(validTime).outlineWidth).toEqual(1.0); + + expect(entity.path.material.getValue(invalidTime)).toBeUndefined(); + expect(entity.path.width.getValue(invalidTime)).toBeUndefined(); + expect(entity.path.leadTime.getValue(invalidTime)).toBeUndefined(); + expect(entity.path.trailTime.getValue(invalidTime)).toBeUndefined(); + expect(entity.path.show.getValue(invalidTime)).toBeUndefined(); + }); }); it('CZML adds data for infinite point.', function() { @@ -2191,18 +2333,19 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(pointPacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.point).toBeDefined(); - expect(entity.point.color.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.1, 0.1, 0.1, 0.1)); - expect(entity.point.pixelSize.getValue(Iso8601.MINIMUM_VALUE)).toEqual(pointPacket.point.pixelSize); - expect(entity.point.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); - expect(entity.point.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(pointPacket.point.outlineWidth); - expect(entity.point.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); - expect(entity.point.scaleByDistance.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new NearFarScalar(1.0, 2.0, 10000.0, 3.0)); - expect(entity.point.translucencyByDistance.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new NearFarScalar(1.0, 1.0, 10000.0, 0.0)); - expect(entity.point.heightReference.getValue(Iso8601.MINIMUM_VALUE)).toEqual(HeightReference.CLAMP_TO_GROUND); + return dataSource.load(makePacket(pointPacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.point).toBeDefined(); + expect(entity.point.color.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.1, 0.1, 0.1, 0.1)); + expect(entity.point.pixelSize.getValue(Iso8601.MINIMUM_VALUE)).toEqual(pointPacket.point.pixelSize); + expect(entity.point.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); + expect(entity.point.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(pointPacket.point.outlineWidth); + expect(entity.point.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); + expect(entity.point.scaleByDistance.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new NearFarScalar(1.0, 2.0, 10000.0, 3.0)); + expect(entity.point.translucencyByDistance.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new NearFarScalar(1.0, 1.0, 10000.0, 0.0)); + expect(entity.point.heightReference.getValue(Iso8601.MINIMUM_VALUE)).toEqual(HeightReference.CLAMP_TO_GROUND); + }); }); it('CZML adds data for constrained point.', function() { @@ -2227,21 +2370,22 @@ defineSuite([ var invalidTime = JulianDate.addSeconds(validTime, -1, new JulianDate()); var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(pointPacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.point).toBeDefined(); - expect(entity.point.color.getValue(validTime)).toEqual(new Color(0.1, 0.1, 0.1, 0.1)); - expect(entity.point.pixelSize.getValue(validTime)).toEqual(pointPacket.point.pixelSize); - expect(entity.point.outlineColor.getValue(validTime)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); - expect(entity.point.outlineWidth.getValue(validTime)).toEqual(pointPacket.point.outlineWidth); - expect(entity.point.show.getValue(validTime)).toEqual(true); - - expect(entity.point.color.getValue(invalidTime)).toBeUndefined(); - expect(entity.point.pixelSize.getValue(invalidTime)).toBeUndefined(); - expect(entity.point.outlineColor.getValue(invalidTime)).toBeUndefined(); - expect(entity.point.outlineWidth.getValue(invalidTime)).toBeUndefined(); - expect(entity.point.show.getValue(invalidTime)).toBeUndefined(); + return dataSource.load(makePacket(pointPacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.point).toBeDefined(); + expect(entity.point.color.getValue(validTime)).toEqual(new Color(0.1, 0.1, 0.1, 0.1)); + expect(entity.point.pixelSize.getValue(validTime)).toEqual(pointPacket.point.pixelSize); + expect(entity.point.outlineColor.getValue(validTime)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); + expect(entity.point.outlineWidth.getValue(validTime)).toEqual(pointPacket.point.outlineWidth); + expect(entity.point.show.getValue(validTime)).toEqual(true); + + expect(entity.point.color.getValue(invalidTime)).toBeUndefined(); + expect(entity.point.pixelSize.getValue(invalidTime)).toBeUndefined(); + expect(entity.point.outlineColor.getValue(invalidTime)).toBeUndefined(); + expect(entity.point.outlineWidth.getValue(invalidTime)).toBeUndefined(); + expect(entity.point.show.getValue(invalidTime)).toBeUndefined(); + }); }); it('CZML adds data for infinite polygon.', function() { @@ -2271,22 +2415,23 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(polygonPacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.polygon).toBeDefined(); - expect(entity.polygon.material.getValue(Iso8601.MINIMUM_VALUE).color).toEqual(new Color(0.1, 0.1, 0.1, 0.1)); - expect(entity.polygon.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); - expect(entity.polygon.height.getValue(Iso8601.MINIMUM_VALUE)).toEqual(1); - expect(entity.polygon.extrudedHeight.getValue(Iso8601.MINIMUM_VALUE)).toEqual(2); - expect(entity.polygon.granularity.getValue(Iso8601.MINIMUM_VALUE)).toEqual(3); - expect(entity.polygon.stRotation.getValue(Iso8601.MINIMUM_VALUE)).toEqual(4); - expect(entity.polygon.outline.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); - expect(entity.polygon.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); - expect(entity.polygon.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(6); - expect(entity.polygon.closeTop.getValue(Iso8601.MINIMUM_VALUE)).toEqual(false); - expect(entity.polygon.closeBottom.getValue(Iso8601.MINIMUM_VALUE)).toEqual(false); - expect(entity.polygon.shadows.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ShadowMode.ENABLED); + return dataSource.load(makePacket(polygonPacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.polygon).toBeDefined(); + expect(entity.polygon.material.getValue(Iso8601.MINIMUM_VALUE).color).toEqual(new Color(0.1, 0.1, 0.1, 0.1)); + expect(entity.polygon.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); + expect(entity.polygon.height.getValue(Iso8601.MINIMUM_VALUE)).toEqual(1); + expect(entity.polygon.extrudedHeight.getValue(Iso8601.MINIMUM_VALUE)).toEqual(2); + expect(entity.polygon.granularity.getValue(Iso8601.MINIMUM_VALUE)).toEqual(3); + expect(entity.polygon.stRotation.getValue(Iso8601.MINIMUM_VALUE)).toEqual(4); + expect(entity.polygon.outline.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); + expect(entity.polygon.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); + expect(entity.polygon.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(6); + expect(entity.polygon.closeTop.getValue(Iso8601.MINIMUM_VALUE)).toEqual(false); + expect(entity.polygon.closeBottom.getValue(Iso8601.MINIMUM_VALUE)).toEqual(false); + expect(entity.polygon.shadows.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ShadowMode.ENABLED); + }); }); it('CZML adds data for constrained polygon.', function() { @@ -2311,18 +2456,18 @@ defineSuite([ var invalidTime = JulianDate.addSeconds(validTime, -1, new JulianDate()); var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(polygonPacket)); - var entity = dataSource.entities.values[0]; + return dataSource.load(makePacket(polygonPacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; - expect(entity.polygon).toBeDefined(); - expect(entity.polygon.material.getValue(validTime).color).toEqual(new Color(0.1, 0.1, 0.1, 0.1)); - expect(entity.polygon.show.getValue(validTime)).toEqual(true); - expect(entity.polygon.shadows.getValue(validTime)).toEqual(ShadowMode.ENABLED); - - expect(entity.polygon.material.getValue(invalidTime)).toBeUndefined(); - expect(entity.polygon.show.getValue(invalidTime)).toBeUndefined(); - expect(entity.polygon.shadows.getValue(invalidTime)).toBeUndefined(); + expect(entity.polygon).toBeDefined(); + expect(entity.polygon.material.getValue(validTime).color).toEqual(new Color(0.1, 0.1, 0.1, 0.1)); + expect(entity.polygon.show.getValue(validTime)).toEqual(true); + expect(entity.polygon.shadows.getValue(validTime)).toEqual(ShadowMode.ENABLED); + expect(entity.polygon.material.getValue(invalidTime)).toBeUndefined(); + expect(entity.polygon.show.getValue(invalidTime)).toBeUndefined(); + expect(entity.polygon.shadows.getValue(invalidTime)).toBeUndefined(); + }); }); it('CZML adds data for infinite polyline.', function() { @@ -2346,16 +2491,17 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(polylinePacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.polyline).toBeDefined(); - expect(entity.polyline.material.color.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.1, 0.1, 0.1, 0.1)); - expect(entity.polyline.width.getValue(Iso8601.MINIMUM_VALUE)).toEqual(polylinePacket.polyline.width); - expect(entity.polyline.material.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); - expect(entity.polyline.material.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(1.0); - expect(entity.polyline.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); - expect(entity.polyline.shadows.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ShadowMode.ENABLED); + return dataSource.load(makePacket(polylinePacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.polyline).toBeDefined(); + expect(entity.polyline.material.color.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.1, 0.1, 0.1, 0.1)); + expect(entity.polyline.width.getValue(Iso8601.MINIMUM_VALUE)).toEqual(polylinePacket.polyline.width); + expect(entity.polyline.material.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); + expect(entity.polyline.material.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(1.0); + expect(entity.polyline.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); + expect(entity.polyline.shadows.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ShadowMode.ENABLED); + }); }); it('CZML adds data for constrained polyline.', function() { @@ -2385,21 +2531,22 @@ defineSuite([ var invalidTime = JulianDate.addSeconds(validTime, -1, new JulianDate()); var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(polylinePacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.polyline).toBeDefined(); - expect(entity.polyline.material.getValue(validTime).color).toEqual(new Color(0.1, 0.1, 0.1, 0.1)); - expect(entity.polyline.width.getValue(validTime)).toEqual(polylinePacket.polyline.width); - expect(entity.polyline.material.getValue(validTime).outlineColor).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); - expect(entity.polyline.material.getValue(validTime).outlineWidth).toEqual(1.0); - expect(entity.polyline.show.getValue(validTime)).toEqual(true); - expect(entity.polyline.shadows.getValue(validTime)).toEqual(ShadowMode.ENABLED); - - expect(entity.polyline.material.getValue(invalidTime)).toBeUndefined(); - expect(entity.polyline.width.getValue(invalidTime)).toBeUndefined(); - expect(entity.polyline.show.getValue(invalidTime)).toBeUndefined(); - expect(entity.polyline.shadows.getValue(invalidTime)).toBeUndefined(); + return dataSource.load(makePacket(polylinePacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.polyline).toBeDefined(); + expect(entity.polyline.material.getValue(validTime).color).toEqual(new Color(0.1, 0.1, 0.1, 0.1)); + expect(entity.polyline.width.getValue(validTime)).toEqual(polylinePacket.polyline.width); + expect(entity.polyline.material.getValue(validTime).outlineColor).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); + expect(entity.polyline.material.getValue(validTime).outlineWidth).toEqual(1.0); + expect(entity.polyline.show.getValue(validTime)).toEqual(true); + expect(entity.polyline.shadows.getValue(validTime)).toEqual(ShadowMode.ENABLED); + + expect(entity.polyline.material.getValue(invalidTime)).toBeUndefined(); + expect(entity.polyline.width.getValue(invalidTime)).toBeUndefined(); + expect(entity.polyline.show.getValue(invalidTime)).toBeUndefined(); + expect(entity.polyline.shadows.getValue(invalidTime)).toBeUndefined(); + }); }); it('CZML adds data for infinite model.', function() { @@ -2439,36 +2586,37 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(modelPacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.model).toBeDefined(); - expect(entity.model.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); - expect(entity.model.scale.getValue(Iso8601.MINIMUM_VALUE)).toEqual(3.0); - expect(entity.model.minimumPixelSize.getValue(Iso8601.MINIMUM_VALUE)).toEqual(5.0); - expect(entity.model.maximumScale.getValue(Iso8601.MINIMUM_VALUE)).toEqual(4.0); - expect(entity.model.uri.getValue(Iso8601.MINIMUM_VALUE)).toEqual('./Data/Models/Box/CesiumBoxTest.gltf'); - expect(entity.model.incrementallyLoadTextures.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); - expect(entity.model.shadows.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ShadowMode.ENABLED); - expect(entity.model.heightReference.getValue(Iso8601.MINIMUM_VALUE)).toEqual(HeightReference.CLAMP_TO_GROUND); - expect(entity.model.silhouetteColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(1.0, 0.0, 0.0, 1.0)); - expect(entity.model.silhouetteSize.getValue(Iso8601.MINIMUM_VALUE)).toEqual(2.0); - expect(entity.model.color.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.0, 1.0, 0.0, 0.2)); - expect(entity.model.colorBlendMode.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ColorBlendMode.HIGHLIGHT); - expect(entity.model.colorBlendAmount.getValue(Iso8601.MINIMUM_VALUE)).toEqual(0.5); - - var nodeTransform = entity.model.nodeTransformations.getValue(Iso8601.MINIMUM_VALUE).Mesh; - expect(nodeTransform).toBeDefined(); - expect(nodeTransform.scale).toEqual(new Cartesian3(1.0, 2.0, 3.0)); - expect(nodeTransform.translation).toEqual(new Cartesian3(4.0, 5.0, 6.0)); - - var expectedRotation = new Quaternion(0.0, 0.707, 0.0, 0.707); - Quaternion.normalize(expectedRotation, expectedRotation); - expect(nodeTransform.rotation).toEqual(expectedRotation); - - expect(entity.model.nodeTransformations.Mesh.scale.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Cartesian3(1.0, 2.0, 3.0)); - expect(entity.model.nodeTransformations.Mesh.translation.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Cartesian3(4.0, 5.0, 6.0)); - expect(entity.model.nodeTransformations.Mesh.rotation.getValue(Iso8601.MINIMUM_VALUE)).toEqual(expectedRotation); + return dataSource.load(makePacket(modelPacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.model).toBeDefined(); + expect(entity.model.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); + expect(entity.model.scale.getValue(Iso8601.MINIMUM_VALUE)).toEqual(3.0); + expect(entity.model.minimumPixelSize.getValue(Iso8601.MINIMUM_VALUE)).toEqual(5.0); + expect(entity.model.maximumScale.getValue(Iso8601.MINIMUM_VALUE)).toEqual(4.0); + expect(entity.model.uri.getValue(Iso8601.MINIMUM_VALUE)).toEqual('./Data/Models/Box/CesiumBoxTest.gltf'); + expect(entity.model.incrementallyLoadTextures.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); + expect(entity.model.shadows.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ShadowMode.ENABLED); + expect(entity.model.heightReference.getValue(Iso8601.MINIMUM_VALUE)).toEqual(HeightReference.CLAMP_TO_GROUND); + expect(entity.model.silhouetteColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(1.0, 0.0, 0.0, 1.0)); + expect(entity.model.silhouetteSize.getValue(Iso8601.MINIMUM_VALUE)).toEqual(2.0); + expect(entity.model.color.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.0, 1.0, 0.0, 0.2)); + expect(entity.model.colorBlendMode.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ColorBlendMode.HIGHLIGHT); + expect(entity.model.colorBlendAmount.getValue(Iso8601.MINIMUM_VALUE)).toEqual(0.5); + + var nodeTransform = entity.model.nodeTransformations.getValue(Iso8601.MINIMUM_VALUE).Mesh; + expect(nodeTransform).toBeDefined(); + expect(nodeTransform.scale).toEqual(new Cartesian3(1.0, 2.0, 3.0)); + expect(nodeTransform.translation).toEqual(new Cartesian3(4.0, 5.0, 6.0)); + + var expectedRotation = new Quaternion(0.0, 0.707, 0.0, 0.707); + Quaternion.normalize(expectedRotation, expectedRotation); + expect(nodeTransform.rotation).toEqual(expectedRotation); + + expect(entity.model.nodeTransformations.Mesh.scale.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Cartesian3(1.0, 2.0, 3.0)); + expect(entity.model.nodeTransformations.Mesh.translation.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Cartesian3(4.0, 5.0, 6.0)); + expect(entity.model.nodeTransformations.Mesh.rotation.getValue(Iso8601.MINIMUM_VALUE)).toEqual(expectedRotation); + }); }); it('CZML adds data for constrained model.', function() { @@ -2513,62 +2661,66 @@ defineSuite([ var invalidTime = JulianDate.addSeconds(validTime, -1, new JulianDate()); var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(modelPacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.model).toBeDefined(); - expect(entity.model.show.getValue(validTime)).toEqual(true); - expect(entity.model.scale.getValue(validTime)).toEqual(3.0); - expect(entity.model.minimumPixelSize.getValue(validTime)).toEqual(5.0); - expect(entity.model.uri.getValue(validTime)).toEqual('./Data/Models/Box/CesiumBoxTest.gltf'); - expect(entity.model.incrementallyLoadTextures.getValue(validTime)).toEqual(true); - expect(entity.model.shadows.getValue(validTime)).toEqual(ShadowMode.ENABLED); - expect(entity.model.heightReference.getValue(validTime)).toEqual(HeightReference.CLAMP_TO_GROUND); - expect(entity.model.silhouetteColor.getValue(validTime)).toEqual(new Color(1.0, 0.0, 0.0, 1.0)); - expect(entity.model.silhouetteSize.getValue(validTime)).toEqual(2.0); - expect(entity.model.color.getValue(validTime)).toEqual(new Color(0.0, 1.0, 0.0, 0.2)); - expect(entity.model.colorBlendMode.getValue(validTime)).toEqual(ColorBlendMode.HIGHLIGHT); - expect(entity.model.colorBlendAmount.getValue(validTime)).toEqual(0.5); - - var nodeTransform = entity.model.nodeTransformations.getValue(validTime).Mesh; - expect(nodeTransform).toBeDefined(); - expect(nodeTransform.scale).toEqual(new Cartesian3(1.0, 2.0, 3.0)); - expect(nodeTransform.translation).toEqual(new Cartesian3(4.0, 5.0, 6.0)); - - var expectedRotation = new Quaternion(0.0, 0.707, 0.0, 0.707); - Quaternion.normalize(expectedRotation, expectedRotation); - expect(nodeTransform.rotation).toEqual(expectedRotation); - - expect(entity.model.nodeTransformations.Mesh.scale.getValue(validTime)).toEqual(new Cartesian3(1.0, 2.0, 3.0)); - expect(entity.model.nodeTransformations.Mesh.translation.getValue(validTime)).toEqual(new Cartesian3(4.0, 5.0, 6.0)); - expect(entity.model.nodeTransformations.Mesh.rotation.getValue(validTime)).toEqual(expectedRotation); - - expect(entity.model.show.getValue(invalidTime)).toBeUndefined(); - expect(entity.model.scale.getValue(invalidTime)).toBeUndefined(); - expect(entity.model.minimumPixelSize.getValue(invalidTime)).toBeUndefined(); - expect(entity.model.uri.getValue(invalidTime)).toBeUndefined(); - expect(entity.model.incrementallyLoadTextures.getValue(invalidTime)).toBeUndefined(); - expect(entity.model.shadows.getValue(invalidTime)).toBeUndefined(); - expect(entity.model.heightReference.getValue(invalidTime)).toBeUndefined(); - expect(entity.model.color.getValue(invalidTime)).toBeUndefined(); - expect(entity.model.silhouetteColor.getValue(invalidTime)).toBeUndefined(); - expect(entity.model.silhouetteSize.getValue(invalidTime)).toBeUndefined(); - expect(entity.model.colorBlendMode.getValue(invalidTime)).toBeUndefined(); - expect(entity.model.colorBlendAmount.getValue(invalidTime)).toBeUndefined(); - - expect(entity.model.nodeTransformations.Mesh.getValue(invalidTime)).toEqual(new TranslationRotationScale()); - expect(entity.model.nodeTransformations.Mesh.scale.getValue(invalidTime)).toBeUndefined(); - expect(entity.model.nodeTransformations.Mesh.translation.getValue(invalidTime)).toBeUndefined(); - expect(entity.model.nodeTransformations.Mesh.rotation.getValue(invalidTime)).toBeUndefined(); + return dataSource.load(makePacket(modelPacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.model).toBeDefined(); + expect(entity.model.show.getValue(validTime)).toEqual(true); + expect(entity.model.scale.getValue(validTime)).toEqual(3.0); + expect(entity.model.minimumPixelSize.getValue(validTime)).toEqual(5.0); + expect(entity.model.uri.getValue(validTime)).toEqual('./Data/Models/Box/CesiumBoxTest.gltf'); + expect(entity.model.incrementallyLoadTextures.getValue(validTime)).toEqual(true); + expect(entity.model.shadows.getValue(validTime)).toEqual(ShadowMode.ENABLED); + expect(entity.model.heightReference.getValue(validTime)).toEqual(HeightReference.CLAMP_TO_GROUND); + expect(entity.model.silhouetteColor.getValue(validTime)).toEqual(new Color(1.0, 0.0, 0.0, 1.0)); + expect(entity.model.silhouetteSize.getValue(validTime)).toEqual(2.0); + expect(entity.model.color.getValue(validTime)).toEqual(new Color(0.0, 1.0, 0.0, 0.2)); + expect(entity.model.colorBlendMode.getValue(validTime)).toEqual(ColorBlendMode.HIGHLIGHT); + expect(entity.model.colorBlendAmount.getValue(validTime)).toEqual(0.5); + + var nodeTransform = entity.model.nodeTransformations.getValue(validTime).Mesh; + expect(nodeTransform).toBeDefined(); + expect(nodeTransform.scale).toEqual(new Cartesian3(1.0, 2.0, 3.0)); + expect(nodeTransform.translation).toEqual(new Cartesian3(4.0, 5.0, 6.0)); + + var expectedRotation = new Quaternion(0.0, 0.707, 0.0, 0.707); + Quaternion.normalize(expectedRotation, expectedRotation); + expect(nodeTransform.rotation).toEqual(expectedRotation); + + expect(entity.model.nodeTransformations.Mesh.scale.getValue(validTime)).toEqual(new Cartesian3(1.0, 2.0, 3.0)); + expect(entity.model.nodeTransformations.Mesh.translation.getValue(validTime)).toEqual(new Cartesian3(4.0, 5.0, 6.0)); + expect(entity.model.nodeTransformations.Mesh.rotation.getValue(validTime)).toEqual(expectedRotation); + + expect(entity.model.show.getValue(invalidTime)).toBeUndefined(); + expect(entity.model.scale.getValue(invalidTime)).toBeUndefined(); + expect(entity.model.minimumPixelSize.getValue(invalidTime)).toBeUndefined(); + expect(entity.model.uri.getValue(invalidTime)).toBeUndefined(); + expect(entity.model.incrementallyLoadTextures.getValue(invalidTime)).toBeUndefined(); + expect(entity.model.shadows.getValue(invalidTime)).toBeUndefined(); + expect(entity.model.heightReference.getValue(invalidTime)).toBeUndefined(); + expect(entity.model.color.getValue(invalidTime)).toBeUndefined(); + expect(entity.model.silhouetteColor.getValue(invalidTime)).toBeUndefined(); + expect(entity.model.silhouetteSize.getValue(invalidTime)).toBeUndefined(); + expect(entity.model.colorBlendMode.getValue(invalidTime)).toBeUndefined(); + expect(entity.model.colorBlendAmount.getValue(invalidTime)).toBeUndefined(); + + expect(entity.model.nodeTransformations.Mesh.getValue(invalidTime)).toEqual(new TranslationRotationScale()); + expect(entity.model.nodeTransformations.Mesh.scale.getValue(invalidTime)).toBeUndefined(); + expect(entity.model.nodeTransformations.Mesh.translation.getValue(invalidTime)).toBeUndefined(); + expect(entity.model.nodeTransformations.Mesh.rotation.getValue(invalidTime)).toBeUndefined(); + }); }); it('processCzml deletes an existing object.', function() { var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(staticCzml)); - var objects = dataSource.entities.values; - expect(objects.length).toEqual(1); - dataSource.load(makePacket(czmlDelete)); - expect(objects.length).toEqual(0); + return dataSource.load(makePacket(staticCzml)).then(function(dataSource) { + var objects = dataSource.entities.values; + expect(objects.length).toEqual(1); + return dataSource.load(makePacket(czmlDelete)); + }).then(function(dataSource) { + var objects = dataSource.entities.values; + expect(objects.length).toEqual(0); + }); }); it('Processes parent property.', function() { @@ -2583,14 +2735,15 @@ defineSuite([ }]; var dataSource = new CzmlDataSource(); - dataSource.load(parentChildCzml); - var objects = dataSource.entities; + return dataSource.load(parentChildCzml).then(function(dataSource) { + var objects = dataSource.entities; - var parent = objects.getById('parent'); - expect(parent.parent).toBeUndefined(); + var parent = objects.getById('parent'); + expect(parent.parent).toBeUndefined(); - var child = objects.getById('child'); - expect(child.parent).toBe(parent); + var child = objects.getById('child'); + expect(child.parent).toBe(parent); + }); }); it('Processes parent property out of order.', function() { @@ -2616,26 +2769,27 @@ defineSuite([ }]; var dataSource = new CzmlDataSource(); - dataSource.load(parentChildCzml); - var objects = dataSource.entities; + return dataSource.load(parentChildCzml).then(function(dataSource) { + var objects = dataSource.entities; - var grandparent = objects.getById('grandparent'); - expect(grandparent.parent).toBeUndefined(); + var grandparent = objects.getById('grandparent'); + expect(grandparent.parent).toBeUndefined(); - var grandparent2 = objects.getById('grandparent'); - expect(grandparent2.parent).toBeUndefined(); + var grandparent2 = objects.getById('grandparent'); + expect(grandparent2.parent).toBeUndefined(); - var parent = objects.getById('parent'); - expect(parent.parent).toBe(grandparent); + var parent = objects.getById('parent'); + expect(parent.parent).toBe(grandparent); - var parent2 = objects.getById('parent2'); - expect(parent2.parent).toBe(grandparent); + var parent2 = objects.getById('parent2'); + expect(parent2.parent).toBe(grandparent); - var child = objects.getById('child'); - expect(child.parent).toBe(parent); + var child = objects.getById('child'); + expect(child.parent).toBe(parent); - var child2 = objects.getById('child2'); - expect(child2.parent).toBe(parent); + var child2 = objects.getById('child2'); + expect(child2.parent).toBe(parent); + }); }); it('Processes JulianDate packets.', function() { @@ -2691,9 +2845,9 @@ defineSuite([ var dataSource = new CzmlDataSource(); dataSource.entities.collectionChanged.addEventListener(spy); - dataSource.load(packets); - - expect(spy.calls.count()).toEqual(1); + return dataSource.load(packets).then(function(dataSource) { + expect(spy.calls.count()).toEqual(1); + }); }); it('CZML materials work with composite interval', function() { @@ -2740,13 +2894,14 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - var entity = dataSource.entities.values[0]; - expect(entity.polygon.material.getType(solid)).toBe('Color'); - expect(entity.polygon.material.getType(grid1)).toBe('Grid'); - expect(entity.polygon.material.getType(grid2)).toBe('Grid'); - expect(entity.polygon.material.getType(before)).toBeUndefined(); - expect(entity.polygon.material.getType(after)).toBeUndefined(); + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + expect(entity.polygon.material.getType(solid)).toBe('Color'); + expect(entity.polygon.material.getType(grid1)).toBe('Grid'); + expect(entity.polygon.material.getType(grid2)).toBe('Grid'); + expect(entity.polygon.material.getType(before)).toBeUndefined(); + expect(entity.polygon.material.getType(after)).toBeUndefined(); + }); }); it('CZML adds data for rectangle.', function() { @@ -2782,24 +2937,25 @@ defineSuite([ var czmlRectangle = rectanglePacket.rectangle; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(rectanglePacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.rectangle).toBeDefined(); - expect(entity.rectangle.coordinates.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Rectangle(0, 1, 2, 3)); - expect(entity.rectangle.material.getValue(Iso8601.MINIMUM_VALUE).color).toEqual(new Color(0.1, 0.2, 0.3, 0.4)); - expect(entity.rectangle.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlRectangle.show); - expect(entity.rectangle.height.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlRectangle.height); - expect(entity.rectangle.extrudedHeight.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlRectangle.extrudedHeight); - expect(entity.rectangle.granularity.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlRectangle.granularity); - expect(entity.rectangle.rotation.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlRectangle.rotation); - expect(entity.rectangle.stRotation.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlRectangle.stRotation); - expect(entity.rectangle.closeBottom.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlRectangle.closeBottom); - expect(entity.rectangle.closeTop.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlRectangle.closeTop); - expect(entity.rectangle.outline.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); - expect(entity.rectangle.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); - expect(entity.rectangle.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(6); - expect(entity.rectangle.shadows.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ShadowMode.ENABLED); + return dataSource.load(makePacket(rectanglePacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.rectangle).toBeDefined(); + expect(entity.rectangle.coordinates.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Rectangle(0, 1, 2, 3)); + expect(entity.rectangle.material.getValue(Iso8601.MINIMUM_VALUE).color).toEqual(new Color(0.1, 0.2, 0.3, 0.4)); + expect(entity.rectangle.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlRectangle.show); + expect(entity.rectangle.height.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlRectangle.height); + expect(entity.rectangle.extrudedHeight.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlRectangle.extrudedHeight); + expect(entity.rectangle.granularity.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlRectangle.granularity); + expect(entity.rectangle.rotation.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlRectangle.rotation); + expect(entity.rectangle.stRotation.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlRectangle.stRotation); + expect(entity.rectangle.closeBottom.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlRectangle.closeBottom); + expect(entity.rectangle.closeTop.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlRectangle.closeTop); + expect(entity.rectangle.outline.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); + expect(entity.rectangle.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); + expect(entity.rectangle.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(6); + expect(entity.rectangle.shadows.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ShadowMode.ENABLED); + }); }); it('can handle constant rectangle coordinates in degrees.', function() { @@ -2812,9 +2968,10 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(rectanglePacket)); - var entity = dataSource.entities.values[0]; - expect(entity.rectangle.coordinates.getValue(Iso8601.MINIMUM_VALUE)).toEqual(Rectangle.fromDegrees(0, 1, 2, 3)); + return dataSource.load(makePacket(rectanglePacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + expect(entity.rectangle.coordinates.getValue(Iso8601.MINIMUM_VALUE)).toEqual(Rectangle.fromDegrees(0, 1, 2, 3)); + }); }); it('can handle sampled rectangle coordinates.', function() { @@ -2831,16 +2988,17 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(rectanglePacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.rectangle).toBeDefined(); - var date1 = epoch; - var date2 = JulianDate.addSeconds(epoch, 0.5, new JulianDate()); - var date3 = JulianDate.addSeconds(epoch, 1.0, new JulianDate()); - expect(entity.rectangle.coordinates.getValue(date1)).toEqual(new Rectangle(1.0, 2.0, 3.0, 4.0)); - expect(entity.rectangle.coordinates.getValue(date2)).toEqual(new Rectangle(2.0, 3.0, 4.0, 5.0)); - expect(entity.rectangle.coordinates.getValue(date3)).toEqual(new Rectangle(3.0, 4.0, 5.0, 6.0)); + return dataSource.load(makePacket(rectanglePacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.rectangle).toBeDefined(); + var date1 = epoch; + var date2 = JulianDate.addSeconds(epoch, 0.5, new JulianDate()); + var date3 = JulianDate.addSeconds(epoch, 1.0, new JulianDate()); + expect(entity.rectangle.coordinates.getValue(date1)).toEqual(new Rectangle(1.0, 2.0, 3.0, 4.0)); + expect(entity.rectangle.coordinates.getValue(date2)).toEqual(new Rectangle(2.0, 3.0, 4.0, 5.0)); + expect(entity.rectangle.coordinates.getValue(date3)).toEqual(new Rectangle(3.0, 4.0, 5.0, 6.0)); + }); }); it('can handle sampled rectangle coordinates in degrees.', function() { @@ -2857,16 +3015,17 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(rectanglePacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.rectangle).toBeDefined(); - var date1 = epoch; - var date2 = JulianDate.addSeconds(epoch, 0.5, new JulianDate()); - var date3 = JulianDate.addSeconds(epoch, 1.0, new JulianDate()); - expect(entity.rectangle.coordinates.getValue(date1)).toEqual(Rectangle.fromDegrees(1.0, 2.0, 3.0, 4.0)); - expect(entity.rectangle.coordinates.getValue(date2)).toEqualEpsilon(Rectangle.fromDegrees(2.0, 3.0, 4.0, 5.0), CesiumMath.EPSILON15); - expect(entity.rectangle.coordinates.getValue(date3)).toEqual(Rectangle.fromDegrees(3.0, 4.0, 5.0, 6.0)); + return dataSource.load(makePacket(rectanglePacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.rectangle).toBeDefined(); + var date1 = epoch; + var date2 = JulianDate.addSeconds(epoch, 0.5, new JulianDate()); + var date3 = JulianDate.addSeconds(epoch, 1.0, new JulianDate()); + expect(entity.rectangle.coordinates.getValue(date1)).toEqual(Rectangle.fromDegrees(1.0, 2.0, 3.0, 4.0)); + expect(entity.rectangle.coordinates.getValue(date2)).toEqualEpsilon(Rectangle.fromDegrees(2.0, 3.0, 4.0, 5.0), CesiumMath.EPSILON15); + expect(entity.rectangle.coordinates.getValue(date3)).toEqual(Rectangle.fromDegrees(3.0, 4.0, 5.0, 6.0)); + }); }); it('CZML adds data for wall.', function() { @@ -2899,19 +3058,20 @@ defineSuite([ var czmlRectangle = wallPacket.wall; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(wallPacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.wall).toBeDefined(); - expect(entity.wall.material.getValue(Iso8601.MINIMUM_VALUE).color).toEqual(new Color(0.1, 0.2, 0.3, 0.4)); - expect(entity.wall.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlRectangle.show); - expect(entity.wall.granularity.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlRectangle.granularity); - expect(entity.wall.minimumHeights.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlRectangle.minimumHeights.array); - expect(entity.wall.maximumHeights.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlRectangle.maximumHeights.array); - expect(entity.wall.outline.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); - expect(entity.wall.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); - expect(entity.wall.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(6); - expect(entity.wall.shadows.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ShadowMode.ENABLED); + return dataSource.load(makePacket(wallPacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.wall).toBeDefined(); + expect(entity.wall.material.getValue(Iso8601.MINIMUM_VALUE).color).toEqual(new Color(0.1, 0.2, 0.3, 0.4)); + expect(entity.wall.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlRectangle.show); + expect(entity.wall.granularity.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlRectangle.granularity); + expect(entity.wall.minimumHeights.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlRectangle.minimumHeights.array); + expect(entity.wall.maximumHeights.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlRectangle.maximumHeights.array); + expect(entity.wall.outline.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); + expect(entity.wall.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); + expect(entity.wall.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(6); + expect(entity.wall.shadows.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ShadowMode.ENABLED); + }); }); it('CZML adds data for wall with minimumHeights as references.', function() { @@ -2941,12 +3101,13 @@ defineSuite([ }]; var dataSource = new CzmlDataSource(); - dataSource.load(packets); - var entity = dataSource.entities.getById('wall'); + return dataSource.load(packets).then(function(dataSource) { + var entity = dataSource.entities.getById('wall'); - expect(entity.wall).toBeDefined(); - expect(entity.wall.minimumHeights.getValue(Iso8601.MINIMUM_VALUE)).toEqual([packets[1].billboard.scale, packets[2].billboard.scale]); - expect(entity.wall.maximumHeights.getValue(Iso8601.MINIMUM_VALUE)).toEqual([packets[2].billboard.scale, packets[1].billboard.scale]); + expect(entity.wall).toBeDefined(); + expect(entity.wall.minimumHeights.getValue(Iso8601.MINIMUM_VALUE)).toEqual([packets[1].billboard.scale, packets[2].billboard.scale]); + expect(entity.wall.maximumHeights.getValue(Iso8601.MINIMUM_VALUE)).toEqual([packets[2].billboard.scale, packets[1].billboard.scale]); + }); }); it('CZML adds data for box.', function() { @@ -2973,17 +3134,18 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(boxPacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.box).toBeDefined(); - expect(entity.box.dimensions.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Cartesian3(1, 2, 3)); - expect(entity.box.material.getValue(Iso8601.MINIMUM_VALUE).color).toEqual(new Color(0.1, 0.2, 0.3, 0.4)); - expect(entity.box.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); - expect(entity.box.outline.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); - expect(entity.box.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); - expect(entity.box.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(6); - expect(entity.box.shadows.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ShadowMode.ENABLED); + return dataSource.load(makePacket(boxPacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.box).toBeDefined(); + expect(entity.box.dimensions.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Cartesian3(1, 2, 3)); + expect(entity.box.material.getValue(Iso8601.MINIMUM_VALUE).color).toEqual(new Color(0.1, 0.2, 0.3, 0.4)); + expect(entity.box.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); + expect(entity.box.outline.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); + expect(entity.box.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); + expect(entity.box.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(6); + expect(entity.box.shadows.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ShadowMode.ENABLED); + }); }); it('CZML adds data for cylinder.', function() { @@ -3012,21 +3174,22 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(cylinderPacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.cylinder).toBeDefined(); - expect(entity.cylinder.length.getValue(Iso8601.MINIMUM_VALUE)).toEqual(5); - expect(entity.cylinder.topRadius.getValue(Iso8601.MINIMUM_VALUE)).toEqual(6); - expect(entity.cylinder.bottomRadius.getValue(Iso8601.MINIMUM_VALUE)).toEqual(7); - expect(entity.cylinder.material.getValue(Iso8601.MINIMUM_VALUE).color).toEqual(new Color(0.1, 0.2, 0.3, 0.4)); - expect(entity.cylinder.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); - expect(entity.cylinder.outline.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); - expect(entity.cylinder.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); - expect(entity.cylinder.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(6); - expect(entity.cylinder.numberOfVerticalLines.getValue(Iso8601.MINIMUM_VALUE)).toEqual(15); - expect(entity.cylinder.slices.getValue(Iso8601.MINIMUM_VALUE)).toEqual(100); - expect(entity.cylinder.shadows.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ShadowMode.ENABLED); + return dataSource.load(makePacket(cylinderPacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.cylinder).toBeDefined(); + expect(entity.cylinder.length.getValue(Iso8601.MINIMUM_VALUE)).toEqual(5); + expect(entity.cylinder.topRadius.getValue(Iso8601.MINIMUM_VALUE)).toEqual(6); + expect(entity.cylinder.bottomRadius.getValue(Iso8601.MINIMUM_VALUE)).toEqual(7); + expect(entity.cylinder.material.getValue(Iso8601.MINIMUM_VALUE).color).toEqual(new Color(0.1, 0.2, 0.3, 0.4)); + expect(entity.cylinder.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); + expect(entity.cylinder.outline.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); + expect(entity.cylinder.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); + expect(entity.cylinder.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(6); + expect(entity.cylinder.numberOfVerticalLines.getValue(Iso8601.MINIMUM_VALUE)).toEqual(15); + expect(entity.cylinder.slices.getValue(Iso8601.MINIMUM_VALUE)).toEqual(100); + expect(entity.cylinder.shadows.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ShadowMode.ENABLED); + }); }); it('CZML adds data for corridor.', function() { @@ -3062,37 +3225,40 @@ defineSuite([ var czmlCorridor = corridorPacket.corridor; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(corridorPacket)); - var entity = dataSource.entities.values[0]; - - expect(entity.corridor).toBeDefined(); - expect(entity.corridor.positions.getValue(Iso8601.MINIMUM_VALUE)).toEqual(expectedResult); - expect(entity.corridor.material.getValue(Iso8601.MINIMUM_VALUE).color).toEqual(new Color(0.1, 0.2, 0.3, 0.4)); - expect(entity.corridor.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlCorridor.show); - expect(entity.corridor.height.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlCorridor.height); - expect(entity.corridor.width.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlCorridor.width); - expect(entity.corridor.cornerType.getValue(Iso8601.MINIMUM_VALUE)).toEqual(CornerType.MITERED); - expect(entity.corridor.extrudedHeight.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlCorridor.extrudedHeight); - expect(entity.corridor.granularity.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlCorridor.granularity); - expect(entity.corridor.outline.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); - expect(entity.corridor.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); - expect(entity.corridor.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(6); - expect(entity.corridor.shadows.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ShadowMode.ENABLED); + return dataSource.load(makePacket(corridorPacket)).then(function(dataSource) { + var entity = dataSource.entities.values[0]; + + expect(entity.corridor).toBeDefined(); + expect(entity.corridor.positions.getValue(Iso8601.MINIMUM_VALUE)).toEqual(expectedResult); + expect(entity.corridor.material.getValue(Iso8601.MINIMUM_VALUE).color).toEqual(new Color(0.1, 0.2, 0.3, 0.4)); + expect(entity.corridor.show.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlCorridor.show); + expect(entity.corridor.height.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlCorridor.height); + expect(entity.corridor.width.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlCorridor.width); + expect(entity.corridor.cornerType.getValue(Iso8601.MINIMUM_VALUE)).toEqual(CornerType.MITERED); + expect(entity.corridor.extrudedHeight.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlCorridor.extrudedHeight); + expect(entity.corridor.granularity.getValue(Iso8601.MINIMUM_VALUE)).toEqual(czmlCorridor.granularity); + expect(entity.corridor.outline.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); + expect(entity.corridor.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); + expect(entity.corridor.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(6); + expect(entity.corridor.shadows.getValue(Iso8601.MINIMUM_VALUE)).toEqual(ShadowMode.ENABLED); + }); }); it('Has entity collection with link to data source', function() { var dataSource = new CzmlDataSource(); - dataSource.load(nameCzml); - var entityCollection = dataSource.entities; - expect(entityCollection.owner).toEqual(dataSource); + return dataSource.load(nameCzml).then(function(dataSource) { + var entityCollection = dataSource.entities; + expect(entityCollection.owner).toEqual(dataSource); + }); }); it('Has entity with link to entity collection', function() { var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(staticCzml)); - var entityCollection = dataSource.entities; - var entity = entityCollection.values[0]; - expect(entity.entityCollection).toEqual(entityCollection); + return dataSource.load(makePacket(staticCzml)).then(function(dataSource) { + var entityCollection = dataSource.entities; + var entity = entityCollection.values[0]; + expect(entity.entityCollection).toEqual(entityCollection); + }); }); it('Can use constant reference properties', function() { @@ -3115,13 +3281,13 @@ defineSuite([ }]; var dataSource = new CzmlDataSource(); - dataSource.load(packets); + return dataSource.load(packets).then(function(dataSource) { + var targetEntity = dataSource.entities.getById('targetId'); + var referenceObject = dataSource.entities.getById('referenceId'); - var targetEntity = dataSource.entities.getById('targetId'); - var referenceObject = dataSource.entities.getById('referenceId'); - - expect(referenceObject.point.pixelSize instanceof ReferenceProperty).toBe(true); - expect(targetEntity.point.pixelSize.getValue(time)).toEqual(referenceObject.point.pixelSize.getValue(time)); + expect(referenceObject.point.pixelSize instanceof ReferenceProperty).toBe(true); + expect(targetEntity.point.pixelSize.getValue(time)).toEqual(referenceObject.point.pixelSize.getValue(time)); + }); }); it('Can use interval reference properties', function() { @@ -3155,14 +3321,14 @@ defineSuite([ var time2 = JulianDate.fromIso8601('2014'); var dataSource = new CzmlDataSource(); - dataSource.load(packets); - - var targetEntity = dataSource.entities.getById('targetId'); - var targetEntity2 = dataSource.entities.getById('targetId2'); - var referenceObject = dataSource.entities.getById('referenceId'); + return dataSource.load(packets).then(function(dataSource) { + var targetEntity = dataSource.entities.getById('targetId'); + var targetEntity2 = dataSource.entities.getById('targetId2'); + var referenceObject = dataSource.entities.getById('referenceId'); - expect(targetEntity.point.pixelSize.getValue(time1)).toEqual(referenceObject.point.pixelSize.getValue(time1)); - expect(targetEntity2.point.pixelSize.getValue(time2)).toEqual(referenceObject.point.pixelSize.getValue(time2)); + expect(targetEntity.point.pixelSize.getValue(time1)).toEqual(referenceObject.point.pixelSize.getValue(time1)); + expect(targetEntity2.point.pixelSize.getValue(time2)).toEqual(referenceObject.point.pixelSize.getValue(time2)); + }); }); it('Can use constant reference properties for position', function() { @@ -3184,13 +3350,13 @@ defineSuite([ }]; var dataSource = new CzmlDataSource(); - dataSource.load(packets); - - var targetEntity = dataSource.entities.getById('targetId'); - var referenceObject = dataSource.entities.getById('referenceId'); + return dataSource.load(packets).then(function(dataSource) { + var targetEntity = dataSource.entities.getById('targetId'); + var referenceObject = dataSource.entities.getById('referenceId'); - expect(referenceObject.position instanceof ReferenceProperty).toBe(true); - expect(targetEntity.position.getValue(time)).toEqual(referenceObject.position.getValue(time)); + expect(referenceObject.position instanceof ReferenceProperty).toBe(true); + expect(targetEntity.position.getValue(time)).toEqual(referenceObject.position.getValue(time)); + }); }); it('Can use interval reference properties for positions', function() { @@ -3222,14 +3388,14 @@ defineSuite([ var time2 = JulianDate.fromIso8601('2014'); var dataSource = new CzmlDataSource(); - dataSource.load(packets); + return dataSource.load(packets).then(function(dataSource) { + var targetEntity = dataSource.entities.getById('targetId'); + var targetEntity2 = dataSource.entities.getById('targetId2'); + var referenceObject = dataSource.entities.getById('referenceId'); - var targetEntity = dataSource.entities.getById('targetId'); - var targetEntity2 = dataSource.entities.getById('targetId2'); - var referenceObject = dataSource.entities.getById('referenceId'); - - expect(targetEntity.position.getValue(time1)).toEqual(referenceObject.position.getValue(time1)); - expect(targetEntity2.position.getValue(time2)).toEqual(referenceObject.position.getValue(time2)); + expect(targetEntity.position.getValue(time1)).toEqual(referenceObject.position.getValue(time1)); + expect(targetEntity2.position.getValue(time2)).toEqual(referenceObject.position.getValue(time2)); + }); }); it('Can reference properties before they exist.', function() { @@ -3252,13 +3418,13 @@ defineSuite([ }]; var dataSource = new CzmlDataSource(); - dataSource.load(packets); + return dataSource.load(packets).then(function(dataSource) { + var targetEntity = dataSource.entities.getById('targetId'); + var referenceObject = dataSource.entities.getById('referenceId'); - var targetEntity = dataSource.entities.getById('targetId'); - var referenceObject = dataSource.entities.getById('referenceId'); - - expect(referenceObject.point.pixelSize instanceof ReferenceProperty).toBe(true); - expect(targetEntity.point.pixelSize.getValue(time)).toEqual(referenceObject.point.pixelSize.getValue(time)); + expect(referenceObject.point.pixelSize instanceof ReferenceProperty).toBe(true); + expect(targetEntity.point.pixelSize.getValue(time)).toEqual(referenceObject.point.pixelSize.getValue(time)); + }); }); it('Can reference local properties.', function() { @@ -3274,11 +3440,11 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - - var targetEntity = dataSource.entities.getById('testObject'); - expect(targetEntity.point.outlineWidth instanceof ReferenceProperty).toBe(true); - expect(targetEntity.point.outlineWidth.getValue(time)).toEqual(targetEntity.point.pixelSize.getValue(time)); + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var targetEntity = dataSource.entities.getById('testObject'); + expect(targetEntity.point.outlineWidth instanceof ReferenceProperty).toBe(true); + expect(targetEntity.point.outlineWidth.getValue(time)).toEqual(targetEntity.point.pixelSize.getValue(time)); + }); }); it('Polyline glow.', function() { @@ -3297,11 +3463,11 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - - var entity = dataSource.entities.getById('polylineGlow'); - expect(entity.polyline.material.color.getValue()).toEqual(new Color(0.1, 0.2, 0.3, 0.4)); - expect(entity.polyline.material.glowPower.getValue()).toEqual(0.75); + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.getById('polylineGlow'); + expect(entity.polyline.material.color.getValue()).toEqual(new Color(0.1, 0.2, 0.3, 0.4)); + expect(entity.polyline.material.glowPower.getValue()).toEqual(0.75); + }); }); it('Polyline arrow.', function() { @@ -3319,10 +3485,10 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - - var entity = dataSource.entities.getById('polylineArrow'); - expect(entity.polyline.material.color.getValue()).toEqual(new Color(0.1, 0.2, 0.3, 0.4)); + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.getById('polylineArrow'); + expect(entity.polyline.material.color.getValue()).toEqual(new Color(0.1, 0.2, 0.3, 0.4)); + }); }); it('Polyline dash.', function() { @@ -3342,12 +3508,12 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - - var entity = dataSource.entities.getById('polylineDash'); - expect(entity.polyline.material.color.getValue()).toEqual(new Color(0.1, 0.2, 0.3, 0.4)); - expect(entity.polyline.material.dashLength.getValue()).toEqual(16.0); - expect(entity.polyline.material.dashPattern.getValue()).toEqual(7.0); + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.getById('polylineDash'); + expect(entity.polyline.material.color.getValue()).toEqual(new Color(0.1, 0.2, 0.3, 0.4)); + expect(entity.polyline.material.dashLength.getValue()).toEqual(16.0); + expect(entity.polyline.material.dashPattern.getValue()).toEqual(7.0); + }); }); it('Processes extrapolation options', function() { @@ -3372,20 +3538,20 @@ defineSuite([ }; var dataSource = new CzmlDataSource(); - dataSource.load(makePacket(packet)); - - var entity = dataSource.entities.getById('point'); - var color = entity.point.color; - expect(color.forwardExtrapolationType).toEqual(ExtrapolationType.NONE); - expect(color.forwardExtrapolationDuration).toEqual(1.0); - expect(color.backwardExtrapolationType).toEqual(ExtrapolationType.HOLD); - expect(color.backwardExtrapolationDuration).toEqual(2.0); - - var position = entity.position; - expect(position.forwardExtrapolationType).toEqual(ExtrapolationType.HOLD); - expect(position.forwardExtrapolationDuration).toEqual(2.0); - expect(position.backwardExtrapolationType).toEqual(ExtrapolationType.NONE); - expect(position.backwardExtrapolationDuration).toEqual(1.0); + return dataSource.load(makePacket(packet)).then(function(dataSource) { + var entity = dataSource.entities.getById('point'); + var color = entity.point.color; + expect(color.forwardExtrapolationType).toEqual(ExtrapolationType.NONE); + expect(color.forwardExtrapolationDuration).toEqual(1.0); + expect(color.backwardExtrapolationType).toEqual(ExtrapolationType.HOLD); + expect(color.backwardExtrapolationDuration).toEqual(2.0); + + var position = entity.position; + expect(position.forwardExtrapolationType).toEqual(ExtrapolationType.HOLD); + expect(position.forwardExtrapolationDuration).toEqual(2.0); + expect(position.backwardExtrapolationType).toEqual(ExtrapolationType.NONE); + expect(position.backwardExtrapolationDuration).toEqual(1.0); + }); }); it('rejects if first document packet lacks version information', function() { diff --git a/Specs/DataSources/KmlDataSourceSpec.js b/Specs/DataSources/KmlDataSourceSpec.js index 985284667945..acaacb86430c 100644 --- a/Specs/DataSources/KmlDataSourceSpec.js +++ b/Specs/DataSources/KmlDataSourceSpec.js @@ -244,6 +244,14 @@ defineSuite([ }); }); + it('load inserts missing namespace declaration', function() { + var dataSource = new KmlDataSource(options); + return dataSource.load('Data/KML/undeclaredNamespaces.kml').then(function(source) { + expect(source).toBe(dataSource); + expect(source.entities.values.length).toEqual(1); + }); + }); + it('load rejects nonexistent URL', function() { return KmlDataSource.load('test.invalid', options).otherwise(function(e) { expect(e).toBeInstanceOf(RequestErrorEvent); @@ -808,6 +816,7 @@ defineSuite([ expect(entity.polygon).toBeUndefined(); expect(entity.rectangle.coordinates.getValue()).toEqualEpsilon(Rectangle.fromDegrees(3, 1, 4, 2), CesiumMath.EPSILON14); expect(entity.rectangle.rotation.getValue()).toEqual(Math.PI / 4); + expect(entity.rectangle.stRotation.getValue()).toEqual(Math.PI / 4); }); }); diff --git a/Specs/DataSources/KmlTourFlyToSpec.js b/Specs/DataSources/KmlTourFlyToSpec.js index 71ee413aeb8e..49d61154f1ca 100644 --- a/Specs/DataSources/KmlTourFlyToSpec.js +++ b/Specs/DataSources/KmlTourFlyToSpec.js @@ -1,4 +1,3 @@ -/*global defineSuite*/ defineSuite([ 'DataSources/KmlTourFlyTo', 'DataSources/KmlCamera', diff --git a/Specs/DataSources/KmlTourSpec.js b/Specs/DataSources/KmlTourSpec.js index aca9c72fc898..98014337bb5a 100644 --- a/Specs/DataSources/KmlTourSpec.js +++ b/Specs/DataSources/KmlTourSpec.js @@ -1,4 +1,3 @@ -/*global defineSuite*/ defineSuite([ 'DataSources/KmlTour', 'DataSources/KmlTourFlyTo', 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..a65c20d60914 100644 --- a/Specs/Renderer/RenderStateSpec.js +++ b/Specs/Renderer/RenderStateSpec.js @@ -1,14 +1,16 @@ defineSuite([ + 'Renderer/RenderState', + 'Core/defined', 'Core/WebGLConstants', 'Core/WindingOrder', 'Renderer/ContextLimits', - 'Renderer/RenderState', 'Specs/createContext' ], function( + RenderState, + defined, WebGLConstants, WindingOrder, ContextLimits, - RenderState, createContext) { 'use strict'; @@ -407,6 +409,11 @@ defineSuite([ expect(cache[fullKey]).not.toBeDefined(); }); + it('freezes render states', function() { + var rs = RenderState.fromCache(); + expect(Object.isFrozen(rs)).toBe(!window.specsUsingRelease); + }); + 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..c12030f324c9 --- /dev/null +++ b/Specs/Renderer/freezeRenderStateSpec.js @@ -0,0 +1,23 @@ +defineSuite([ + 'Renderer/freezeRenderState' + ], function( + freezeRenderState) { + 'use strict'; + + it('works as expected', function() { + var fresh = { + a: 1, + b: { + c: 'c' + }, + _applyFunctions: [function() { }] + }; + + var frozen = freezeRenderState(fresh); + expect(Object.isFrozen(frozen)).toBe(true); + expect(Object.isFrozen(frozen.a)).toBe(true); + expect(Object.isFrozen(frozen.b)).toBe(true); + expect(Object.isFrozen(frozen.c)).toBe(true); + expect(Object.isFrozen(frozen._applyFunctions)).toBe(false); + }); +}); diff --git a/Specs/Scene/Cesium3DTilesetSpec.js b/Specs/Scene/Cesium3DTilesetSpec.js index a8352aee1dd0..c6f802b8f315 100644 --- a/Specs/Scene/Cesium3DTilesetSpec.js +++ b/Specs/Scene/Cesium3DTilesetSpec.js @@ -720,6 +720,14 @@ defineSuite([ }); }); + it('does not load additive tiles that are out of view', function() { + viewBottomLeft(); + return Cesium3DTilesTester.loadTileset(scene, tilesetUrl).then(function(tileset) { + var statistics = tileset._statistics; + expect(statistics.numberOfTilesWithContentReady).toEqual(2); + }); + }); + it('culls with content box', function() { // Root tile has a content box that is half the extents of its box // Expect to cull root tile and three child tiles diff --git a/Specs/Scene/ClassificationPrimitiveSpec.js b/Specs/Scene/ClassificationPrimitiveSpec.js index 0bbbba8058ad..641c8d48eaa6 100644 --- a/Specs/Scene/ClassificationPrimitiveSpec.js +++ b/Specs/Scene/ClassificationPrimitiveSpec.js @@ -17,6 +17,7 @@ defineSuite([ 'Core/ShowGeometryInstanceAttribute', 'Core/Transforms', 'Renderer/Pass', + 'Scene/InvertClassification', 'Scene/PerInstanceColorAppearance', 'Scene/Primitive', 'Specs/createScene', @@ -40,6 +41,7 @@ defineSuite([ ShowGeometryInstanceAttribute, Transforms, Pass, + InvertClassification, PerInstanceColorAppearance, Primitive, createScene, @@ -71,6 +73,7 @@ defineSuite([ function MockGlobePrimitive(primitive) { this._primitive = primitive; + this.pass = Pass.GLOBE; } MockGlobePrimitive.prototype.update = function(frameState) { var commandList = frameState.commandList; @@ -79,7 +82,7 @@ defineSuite([ for (var i = startLength; i < commandList.length; ++i) { var command = commandList[i]; - command.pass = Pass.GLOBE; + command.pass = this.pass; } }; @@ -416,6 +419,82 @@ defineSuite([ verifyClassificationPrimitiveRender(primitive, boxColorAttribute.value); }); + it('renders with invert classification and an opaque color', function() { + if (!ClassificationPrimitive.isSupported(scene)) { + return; + } + + scene.invertClassification = true; + scene.invertClassificationColor = new Color(0.25, 0.25, 0.25, 1.0); + + depthPrimitive.pass = Pass.CESIUM_3D_TILE; + boxInstance.attributes.show = new ShowGeometryInstanceAttribute(true); + + primitive = new ClassificationPrimitive({ + geometryInstances : boxInstance, + asynchronous : false + }); + + scene.camera.setView({ destination : rectangle }); + + var invertedColor = new Array(4); + invertedColor[0] = Color.floatToByte(Color.byteToFloat(depthColor[0]) * scene.invertClassificationColor.red); + invertedColor[1] = Color.floatToByte(Color.byteToFloat(depthColor[1]) * scene.invertClassificationColor.green); + invertedColor[2] = Color.floatToByte(Color.byteToFloat(depthColor[2]) * scene.invertClassificationColor.blue); + invertedColor[3] = 255; + + scene.groundPrimitives.add(depthPrimitive); + expect(scene).toRender(invertedColor); + + scene.groundPrimitives.add(primitive); + expect(scene).toRender(boxColor); + + primitive.getGeometryInstanceAttributes('box').show = [0]; + expect(scene).toRender(depthColor); + + scene.invertClassification = false; + }); + + it('renders with invert classification and a translucent color', function() { + if (!ClassificationPrimitive.isSupported(scene)) { + return; + } + + if (!InvertClassification.isTranslucencySupported(scene.context)) { + return; + } + + scene.invertClassification = true; + scene.invertClassificationColor = new Color(0.25, 0.25, 0.25, 0.25); + + depthPrimitive.pass = Pass.CESIUM_3D_TILE; + boxInstance.attributes.show = new ShowGeometryInstanceAttribute(true); + + primitive = new ClassificationPrimitive({ + geometryInstances : boxInstance, + asynchronous : false + }); + + scene.camera.setView({ destination : rectangle }); + + var invertedColor = new Array(4); + invertedColor[0] = Color.floatToByte(Color.byteToFloat(depthColor[0]) * scene.invertClassificationColor.red * scene.invertClassificationColor.alpha); + invertedColor[1] = Color.floatToByte(Color.byteToFloat(depthColor[1]) * scene.invertClassificationColor.green * scene.invertClassificationColor.alpha); + invertedColor[2] = Color.floatToByte(Color.byteToFloat(depthColor[2]) * scene.invertClassificationColor.blue * scene.invertClassificationColor.alpha); + invertedColor[3] = 255; + + scene.groundPrimitives.add(depthPrimitive); + expect(scene).toRender(invertedColor); + + scene.groundPrimitives.add(primitive); + expect(scene).toRender(boxColor); + + primitive.getGeometryInstanceAttributes('box').show = [0]; + expect(scene).toRender(depthColor); + + scene.invertClassification = false; + }); + it('renders bounding volume with debugShowBoundingVolume', function() { if (!ClassificationPrimitive.isSupported(scene)) { return; diff --git a/Specs/Scene/CullingVolumeSpec.js b/Specs/Scene/CullingVolumeSpec.js deleted file mode 100644 index d48eb0dbf9b0..000000000000 --- a/Specs/Scene/CullingVolumeSpec.js +++ /dev/null @@ -1,405 +0,0 @@ -defineSuite([ - 'Scene/CullingVolume', - 'Core/AxisAlignedBoundingBox', - 'Core/BoundingSphere', - 'Core/Cartesian3', - 'Core/Intersect', - 'Core/PerspectiveFrustum' - ], function( - CullingVolume, - AxisAlignedBoundingBox, - BoundingSphere, - Cartesian3, - Intersect, - PerspectiveFrustum) { - 'use strict'; - - var cullingVolume; - - beforeEach(function() { - var frustum = new PerspectiveFrustum(); - frustum.near = 1.0; - frustum.far = 2.0; - frustum.fov = (Math.PI) / 3; - frustum.aspectRatio = 1.0; - cullingVolume = frustum.computeCullingVolume(new Cartesian3(), Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3()), Cartesian3.UNIT_Y); - }); - - it('computeVisibility throws without a bounding volume', function() { - expect(function() { - return new CullingVolume().computeVisibility(); - }).toThrowDeveloperError(); - }); - - it('computeVisibilityWithPlaneMask throws without a bounding volume', function() { - expect(function() { - return new CullingVolume().computeVisibilityWithPlaneMask(undefined, CullingVolume.MASK_INDETERMINATE); - }).toThrowDeveloperError(); - }); - - it('computeVisibilityWithPlaneMask throws without a parent plane mask', function() { - expect(function() { - return new CullingVolume().computeVisibilityWithPlaneMask(new BoundingSphere(), undefined); - }).toThrowDeveloperError(); - }); - - function testWithAndWithoutPlaneMask(culling, bound, intersect) { - expect(culling.computeVisibility(bound)).toEqual(intersect); - - var mask = culling.computeVisibilityWithPlaneMask(bound, CullingVolume.MASK_INDETERMINATE); - if (intersect === Intersect.INSIDE) { - expect(mask).toEqual(CullingVolume.MASK_INSIDE); - } else if (intersect === Intersect.OUTSIDE) { - expect(mask).toEqual(CullingVolume.MASK_OUTSIDE); - } else { - expect(mask).not.toEqual(CullingVolume.MASK_INSIDE); - expect(mask).not.toEqual(CullingVolume.MASK_OUTSIDE); - } - expect(culling.computeVisibilityWithPlaneMask(bound, mask)).toEqual(mask); - } - - describe('box intersections', function() { - - it('can contain an axis aligned bounding box', function() { - var box1 = AxisAlignedBoundingBox.fromPoints([ - new Cartesian3(-0.5, 0, -1.25), - new Cartesian3(0.5, 0, -1.25), - new Cartesian3(-0.5, 0, -1.75), - new Cartesian3(0.5, 0, -1.75) - ]); - testWithAndWithoutPlaneMask(cullingVolume, box1, Intersect.INSIDE); - }); - - describe('can partially contain an axis aligned bounding box', function() { - - it('on the far plane', function() { - var box2 = AxisAlignedBoundingBox.fromPoints([ - new Cartesian3(-0.5, 0, -1.5), - new Cartesian3(0.5, 0, -1.5), - new Cartesian3(-0.5, 0, -2.5), - new Cartesian3(0.5, 0, -2.5) - ]); - testWithAndWithoutPlaneMask(cullingVolume, box2, Intersect.INTERSECTING); - }); - - it('on the near plane', function() { - var box3 = AxisAlignedBoundingBox.fromPoints([ - new Cartesian3(-0.5, 0, -0.5), - new Cartesian3(0.5, 0, -0.5), - new Cartesian3(-0.5, 0, -1.5), - new Cartesian3(0.5, 0, -1.5) - ]); - testWithAndWithoutPlaneMask(cullingVolume, box3, Intersect.INTERSECTING); - }); - - it('on the left plane', function() { - var box4 = AxisAlignedBoundingBox.fromPoints([ - new Cartesian3(-1.5, 0, -1.25), - new Cartesian3(0, 0, -1.25), - new Cartesian3(-1.5, 0, -1.5), - new Cartesian3(0, 0, -1.5) - ]); - testWithAndWithoutPlaneMask(cullingVolume, box4, Intersect.INTERSECTING); - }); - - it('on the right plane', function() { - var box5 = AxisAlignedBoundingBox.fromPoints([ - new Cartesian3(0, 0, -1.25), - new Cartesian3(1.5, 0, -1.25), - new Cartesian3(0, 0, -1.5), - new Cartesian3(1.5, 0, -1.5) - ]); - testWithAndWithoutPlaneMask(cullingVolume, box5, Intersect.INTERSECTING); - }); - - it('on the top plane', function() { - var box6 = AxisAlignedBoundingBox.fromPoints([ - new Cartesian3(-0.5, 0, -1.25), - new Cartesian3(0.5, 0, -1.25), - new Cartesian3(-0.5, 2.0, -1.75), - new Cartesian3(0.5, 2.0, -1.75) - ]); - testWithAndWithoutPlaneMask(cullingVolume, box6, Intersect.INTERSECTING); - }); - - it('on the bottom plane', function() { - var box7 = AxisAlignedBoundingBox.fromPoints([ - new Cartesian3(-0.5, -2.0, -1.25), - new Cartesian3(0.5, 0, -1.25), - new Cartesian3(-0.5, -2.0, -1.5), - new Cartesian3(0.5, 0, -1.5) - ]); - testWithAndWithoutPlaneMask(cullingVolume, box7, Intersect.INTERSECTING); - }); - }); - - describe('can not contain an axis aligned bounding box', function() { - - it('past the far plane', function() { - var box8 = AxisAlignedBoundingBox.fromPoints([ - new Cartesian3(-0.5, 0, -2.25), - new Cartesian3(0.5, 0, -2.25), - new Cartesian3(-0.5, 0, -2.75), - new Cartesian3(0.5, 0, -2.75) - ]); - testWithAndWithoutPlaneMask(cullingVolume, box8, Intersect.OUTSIDE); - }); - - it('before the near plane', function() { - var box9 = AxisAlignedBoundingBox.fromPoints([ - new Cartesian3(-0.5, 0, -0.25), - new Cartesian3(0.5, 0, -0.25), - new Cartesian3(-0.5, 0, -0.75), - new Cartesian3(0.5, 0, -0.75) - ]); - testWithAndWithoutPlaneMask(cullingVolume, box9, Intersect.OUTSIDE); - }); - - it('past the left plane', function() { - var box10 = AxisAlignedBoundingBox.fromPoints([ - new Cartesian3(-5, 0, -1.25), - new Cartesian3(-3, 0, -1.25), - new Cartesian3(-5, 0, -1.75), - new Cartesian3(-3, 0, -1.75) - ]); - testWithAndWithoutPlaneMask(cullingVolume, box10, Intersect.OUTSIDE); - }); - - it('past the right plane', function() { - var box11 = AxisAlignedBoundingBox.fromPoints([ - new Cartesian3(3, 0, -1.25), - new Cartesian3(5, 0, -1.25), - new Cartesian3(3, 0, -1.75), - new Cartesian3(5, 0, -1.75) - ]); - testWithAndWithoutPlaneMask(cullingVolume, box11, Intersect.OUTSIDE); - }); - - it('past the top plane', function() { - var box12 = AxisAlignedBoundingBox.fromPoints([ - new Cartesian3(-0.5, 3, -1.25), - new Cartesian3(0.5, 3, -1.25), - new Cartesian3(-0.5, 5, -1.75), - new Cartesian3(0.5, 5, -1.75) - ]); - testWithAndWithoutPlaneMask(cullingVolume, box12, Intersect.OUTSIDE); - }); - - it('past the bottom plane', function() { - var box13 = AxisAlignedBoundingBox.fromPoints([ - new Cartesian3(-0.5, -3, -1.25), - new Cartesian3(0.5, -3, -1.25), - new Cartesian3(-0.5, -5, -1.75), - new Cartesian3(0.5, -5, -1.75) - ]); - testWithAndWithoutPlaneMask(cullingVolume, box13, Intersect.OUTSIDE); - }); - - }); - }); - - describe('sphere intersection', function() { - - it('can contain a sphere', function() { - var sphere1 = BoundingSphere.fromPoints([new Cartesian3(0, 0, -1.25), new Cartesian3(0, 0, -1.75)]); - testWithAndWithoutPlaneMask(cullingVolume, sphere1, Intersect.INSIDE); - }); - - describe('can partially contain a sphere', function() { - - it('on the far plane', function() { - var sphere2 = BoundingSphere.fromPoints([new Cartesian3(0, 0, -1.5), new Cartesian3(0, 0, -2.5)]); - testWithAndWithoutPlaneMask(cullingVolume, sphere2, Intersect.INTERSECTING); - }); - - it('on the near plane', function() { - var sphere3 = BoundingSphere.fromPoints([new Cartesian3(0, 0, -0.5), new Cartesian3(0, 0, -1.5)]); - testWithAndWithoutPlaneMask(cullingVolume, sphere3, Intersect.INTERSECTING); - }); - - it('on the left plane', function() { - var sphere4 = BoundingSphere.fromPoints([new Cartesian3(-1.0, 0, -1.5), new Cartesian3(0, 0, -1.5)]); - testWithAndWithoutPlaneMask(cullingVolume, sphere4, Intersect.INTERSECTING); - }); - - it('on the right plane', function() { - var sphere5 = BoundingSphere.fromPoints([new Cartesian3(0, 0, -1.5), new Cartesian3(1.0, 0, -1.5)]); - testWithAndWithoutPlaneMask(cullingVolume, sphere5, Intersect.INTERSECTING); - }); - - it('on the top plane', function() { - var sphere6 = BoundingSphere.fromPoints([new Cartesian3(0, 0, -1.5), new Cartesian3(0, 2.0, -1.5)]); - testWithAndWithoutPlaneMask(cullingVolume, sphere6, Intersect.INTERSECTING); - }); - - it('on the bottom plane', function() { - var sphere7 = BoundingSphere.fromPoints([new Cartesian3(0, -2.0, -1.5), new Cartesian3(0, 0, -1.5)]); - testWithAndWithoutPlaneMask(cullingVolume, sphere7, Intersect.INTERSECTING); - }); - }); - - describe('can not contain a sphere', function() { - - it('past the far plane', function() { - var sphere8 = BoundingSphere.fromPoints([new Cartesian3(0, 0, -2.25), new Cartesian3(0, 0, -2.75)]); - testWithAndWithoutPlaneMask(cullingVolume, sphere8, Intersect.OUTSIDE); - }); - - it('before the near plane', function() { - var sphere9 = BoundingSphere.fromPoints([new Cartesian3(0, 0, -0.25), new Cartesian3(0, 0, -0.5)]); - testWithAndWithoutPlaneMask(cullingVolume, sphere9, Intersect.OUTSIDE); - }); - - it('past the left plane', function() { - var sphere10 = BoundingSphere.fromPoints([new Cartesian3(-5, 0, -1.25), new Cartesian3(-4.5, 0, -1.75)]); - testWithAndWithoutPlaneMask(cullingVolume, sphere10, Intersect.OUTSIDE); - }); - - it('past the right plane', function() { - var sphere11 = BoundingSphere.fromPoints([new Cartesian3(4.5, 0, -1.25), new Cartesian3(5, 0, -1.75)]); - testWithAndWithoutPlaneMask(cullingVolume, sphere11, Intersect.OUTSIDE); - }); - - it('past the top plane', function() { - var sphere12 = BoundingSphere.fromPoints([new Cartesian3(-0.5, 4.5, -1.25), new Cartesian3(-0.5, 5, -1.25)]); - testWithAndWithoutPlaneMask(cullingVolume, sphere12, Intersect.OUTSIDE); - }); - - it('past the bottom plane', function() { - var sphere13 = BoundingSphere.fromPoints([new Cartesian3(-0.5, -4.5, -1.25), new Cartesian3(-0.5, -5, -1.25)]); - testWithAndWithoutPlaneMask(cullingVolume, sphere13, Intersect.OUTSIDE); - }); - }); - }); - - describe('construct from bounding sphere', function() { - var boundingSphereCullingVolume = new BoundingSphere(new Cartesian3(1000.0, 2000.0, 3000.0), 100.0); - var cullingVolume = CullingVolume.fromBoundingSphere(boundingSphereCullingVolume); - - it('throws without a boundingSphere', function() { - expect(function() { - CullingVolume.fromBoundingSphere(undefined); - }).toThrowDeveloperError(); - }); - - it('can contain a volume', function() { - var sphere1 = BoundingSphere.clone(boundingSphereCullingVolume); - sphere1.radius *= 0.5; - testWithAndWithoutPlaneMask(cullingVolume, sphere1, Intersect.INSIDE); - }); - - describe('can partially contain a volume', function() { - - it('on the far plane', function() { - var offset = new Cartesian3(0.0, 0.0, boundingSphereCullingVolume.radius * 1.5); - var center = Cartesian3.add(boundingSphereCullingVolume.center, offset, new Cartesian3()); - var radius = boundingSphereCullingVolume.radius * 0.5; - var sphere2 = new BoundingSphere(center, radius); - - testWithAndWithoutPlaneMask(cullingVolume, sphere2, Intersect.INTERSECTING); - }); - - it('on the near plane', function() { - var offset = new Cartesian3(0.0, 0.0, -boundingSphereCullingVolume.radius * 1.5); - var center = Cartesian3.add(boundingSphereCullingVolume.center, offset, new Cartesian3()); - var radius = boundingSphereCullingVolume.radius * 0.5; - var sphere3 = new BoundingSphere(center, radius); - - testWithAndWithoutPlaneMask(cullingVolume, sphere3, Intersect.INTERSECTING); - }); - - it('on the left plane', function() { - var offset = new Cartesian3(-boundingSphereCullingVolume.radius * 1.5, 0.0, 0.0); - var center = Cartesian3.add(boundingSphereCullingVolume.center, offset, new Cartesian3()); - var radius = boundingSphereCullingVolume.radius * 0.5; - var sphere4 = new BoundingSphere(center, radius); - - testWithAndWithoutPlaneMask(cullingVolume, sphere4, Intersect.INTERSECTING); - }); - - it('on the right plane', function() { - var offset = new Cartesian3(boundingSphereCullingVolume.radius * 1.5, 0.0, 0.0); - var center = Cartesian3.add(boundingSphereCullingVolume.center, offset, new Cartesian3()); - var radius = boundingSphereCullingVolume.radius * 0.5; - var sphere5 = new BoundingSphere(center, radius); - - testWithAndWithoutPlaneMask(cullingVolume, sphere5, Intersect.INTERSECTING); - }); - - it('on the top plane', function() { - var offset = new Cartesian3(0.0, boundingSphereCullingVolume.radius * 1.5, 0.0); - var center = Cartesian3.add(boundingSphereCullingVolume.center, offset, new Cartesian3()); - var radius = boundingSphereCullingVolume.radius * 0.5; - var sphere6 = new BoundingSphere(center, radius); - - testWithAndWithoutPlaneMask(cullingVolume, sphere6, Intersect.INTERSECTING); - }); - - it('on the bottom plane', function() { - var offset = new Cartesian3(0.0, -boundingSphereCullingVolume.radius * 1.5, 0.0); - var center = Cartesian3.add(boundingSphereCullingVolume.center, offset, new Cartesian3()); - var radius = boundingSphereCullingVolume.radius * 0.5; - var sphere7 = new BoundingSphere(center, radius); - - testWithAndWithoutPlaneMask(cullingVolume, sphere7, Intersect.INTERSECTING); - }); - }); - - describe('can not contain a volume', function() { - - it('past the far plane', function() { - var offset = new Cartesian3(0.0, 0.0, boundingSphereCullingVolume.radius * 2.0); - var center = Cartesian3.add(boundingSphereCullingVolume.center, offset, new Cartesian3()); - var radius = boundingSphereCullingVolume.radius * 0.5; - var sphere8 = new BoundingSphere(center, radius); - - testWithAndWithoutPlaneMask(cullingVolume, sphere8, Intersect.OUTSIDE); - }); - - it('before the near plane', function() { - var offset = new Cartesian3(0.0, 0.0, -boundingSphereCullingVolume.radius * 2.0); - var center = Cartesian3.add(boundingSphereCullingVolume.center, offset, new Cartesian3()); - var radius = boundingSphereCullingVolume.radius * 0.5; - var sphere9 = new BoundingSphere(center, radius); - - testWithAndWithoutPlaneMask(cullingVolume, sphere9, Intersect.OUTSIDE); - }); - - it('past the left plane', function() { - var offset = new Cartesian3(-boundingSphereCullingVolume.radius * 2.0, 0.0, 0.0); - var center = Cartesian3.add(boundingSphereCullingVolume.center, offset, new Cartesian3()); - var radius = boundingSphereCullingVolume.radius * 0.5; - var sphere10 = new BoundingSphere(center, radius); - - testWithAndWithoutPlaneMask(cullingVolume, sphere10, Intersect.OUTSIDE); - }); - - it('past the right plane', function() { - var offset = new Cartesian3(boundingSphereCullingVolume.radius * 2.0, 0.0, 0.0); - var center = Cartesian3.add(boundingSphereCullingVolume.center, offset, new Cartesian3()); - var radius = boundingSphereCullingVolume.radius * 0.5; - var sphere11 = new BoundingSphere(center, radius); - - testWithAndWithoutPlaneMask(cullingVolume, sphere11, Intersect.OUTSIDE); - }); - - it('past the top plane', function() { - var offset = new Cartesian3(0.0, boundingSphereCullingVolume.radius * 2.0, 0.0); - var center = Cartesian3.add(boundingSphereCullingVolume.center, offset, new Cartesian3()); - var radius = boundingSphereCullingVolume.radius * 0.5; - var sphere12 = new BoundingSphere(center, radius); - - testWithAndWithoutPlaneMask(cullingVolume, sphere12, Intersect.OUTSIDE); - }); - - it('past the bottom plane', function() { - var offset = new Cartesian3(0.0, -boundingSphereCullingVolume.radius * 2.0, 0.0); - var center = Cartesian3.add(boundingSphereCullingVolume.center, offset, new Cartesian3()); - var radius = boundingSphereCullingVolume.radius * 0.5; - var sphere13 = new BoundingSphere(center, radius); - - testWithAndWithoutPlaneMask(cullingVolume, sphere13, Intersect.OUTSIDE); - }); - }); - }); -}); diff --git a/Specs/Scene/GroundPrimitiveSpec.js b/Specs/Scene/GroundPrimitiveSpec.js index f80c0fcdb7fa..d329bf66028b 100644 --- a/Specs/Scene/GroundPrimitiveSpec.js +++ b/Specs/Scene/GroundPrimitiveSpec.js @@ -13,6 +13,7 @@ defineSuite([ 'Core/RectangleGeometry', 'Core/ShowGeometryInstanceAttribute', 'Renderer/Pass', + 'Scene/InvertClassification', 'Scene/PerInstanceColorAppearance', 'Scene/Primitive', 'Specs/createScene', @@ -32,6 +33,7 @@ defineSuite([ RectangleGeometry, ShowGeometryInstanceAttribute, Pass, + InvertClassification, PerInstanceColorAppearance, Primitive, createScene, @@ -72,7 +74,9 @@ defineSuite([ function MockGlobePrimitive(primitive) { this._primitive = primitive; + this.pass = Pass.GLOBE; } + MockGlobePrimitive.prototype.update = function(frameState) { var commandList = frameState.commandList; var startLength = commandList.length; @@ -80,7 +84,7 @@ defineSuite([ for (var i = startLength; i < commandList.length; ++i) { var command = commandList[i]; - command.pass = Pass.GLOBE; + command.pass = this.pass; } }; @@ -387,6 +391,82 @@ defineSuite([ verifyGroundPrimitiveRender(primitive, rectColorAttribute.value); }); + it('renders with invert classification and an opaque color', function() { + if (!GroundPrimitive.isSupported(scene)) { + return; + } + + scene.invertClassification = true; + scene.invertClassificationColor = new Color(0.25, 0.25, 0.25, 1.0); + + depthPrimitive.pass = Pass.CESIUM_3D_TILE; + rectangleInstance.attributes.show = new ShowGeometryInstanceAttribute(true); + + primitive = new GroundPrimitive({ + geometryInstances : rectangleInstance, + asynchronous : false + }); + + scene.camera.setView({ destination : rectangle }); + + var invertedColor = new Array(4); + invertedColor[0] = Color.floatToByte(Color.byteToFloat(depthColor[0]) * scene.invertClassificationColor.red); + invertedColor[1] = Color.floatToByte(Color.byteToFloat(depthColor[1]) * scene.invertClassificationColor.green); + invertedColor[2] = Color.floatToByte(Color.byteToFloat(depthColor[2]) * scene.invertClassificationColor.blue); + invertedColor[3] = 255; + + scene.groundPrimitives.add(depthPrimitive); + expect(scene).toRender(invertedColor); + + scene.groundPrimitives.add(primitive); + expect(scene).toRender(rectColor); + + primitive.getGeometryInstanceAttributes('rectangle').show = [0]; + expect(scene).toRender(depthColor); + + scene.invertClassification = false; + }); + + it('renders with invert classification and a translucent color', function() { + if (!GroundPrimitive.isSupported(scene)) { + return; + } + + if (!InvertClassification.isTranslucencySupported(scene.context)) { + return; + } + + scene.invertClassification = true; + scene.invertClassificationColor = new Color(0.25, 0.25, 0.25, 0.25); + + depthPrimitive.pass = Pass.CESIUM_3D_TILE; + rectangleInstance.attributes.show = new ShowGeometryInstanceAttribute(true); + + primitive = new GroundPrimitive({ + geometryInstances : rectangleInstance, + asynchronous : false + }); + + scene.camera.setView({ destination : rectangle }); + + var invertedColor = new Array(4); + invertedColor[0] = Color.floatToByte(Color.byteToFloat(depthColor[0]) * scene.invertClassificationColor.red * scene.invertClassificationColor.alpha); + invertedColor[1] = Color.floatToByte(Color.byteToFloat(depthColor[1]) * scene.invertClassificationColor.green * scene.invertClassificationColor.alpha); + invertedColor[2] = Color.floatToByte(Color.byteToFloat(depthColor[2]) * scene.invertClassificationColor.blue * scene.invertClassificationColor.alpha); + invertedColor[3] = 255; + + scene.groundPrimitives.add(depthPrimitive); + expect(scene).toRender(invertedColor); + + scene.groundPrimitives.add(primitive); + expect(scene).toRender(rectColor); + + primitive.getGeometryInstanceAttributes('rectangle').show = [0]; + expect(scene).toRender(depthColor); + + scene.invertClassification = false; + }); + it('renders bounding volume with debugShowBoundingVolume', function() { if (!GroundPrimitive.isSupported(scene)) { return; diff --git a/Specs/Scene/ImageryLayerSpec.js b/Specs/Scene/ImageryLayerSpec.js index fbb3211d453e..22fe1c728999 100644 --- a/Specs/Scene/ImageryLayerSpec.js +++ b/Specs/Scene/ImageryLayerSpec.js @@ -7,6 +7,8 @@ defineSuite([ 'Core/Rectangle', 'Core/RequestScheduler', 'Renderer/ComputeEngine', + 'Renderer/TextureMagnificationFilter', + 'Renderer/TextureMinificationFilter', 'Scene/ArcGisMapServerImageryProvider', 'Scene/BingMapsImageryProvider', 'Scene/createTileMapServiceImageryProvider', @@ -30,6 +32,8 @@ defineSuite([ Rectangle, RequestScheduler, ComputeEngine, + TextureMagnificationFilter, + TextureMinificationFilter, ArcGisMapServerImageryProvider, BingMapsImageryProvider, createTileMapServiceImageryProvider, @@ -187,6 +191,9 @@ defineSuite([ return imagery.state === ImageryState.READY; }).then(function() { expect(imagery.texture).toBeDefined(); + expect(imagery.texture.sampler).toBeDefined(); + expect(imagery.texture.sampler.minificationFilter).toEqual(TextureMinificationFilter.LINEAR_MIPMAP_LINEAR); + expect(imagery.texture.sampler.magnificationFilter).toEqual(TextureMinificationFilter.LINEAR); expect(textureBeforeReprojection).not.toEqual(imagery.texture); imagery.releaseReference(); }); @@ -269,6 +276,9 @@ defineSuite([ return imagery.state === ImageryState.READY; }).then(function() { expect(imagery.texture).toBeDefined(); + expect(imagery.texture.sampler).toBeDefined(); + expect(imagery.texture.sampler.minificationFilter).toEqual(TextureMinificationFilter.LINEAR_MIPMAP_LINEAR); + expect(imagery.texture.sampler.magnificationFilter).toEqual(TextureMinificationFilter.LINEAR); expect(textureBeforeReprojection).not.toEqual(imagery.texture); imagery.releaseReference(); }); @@ -315,6 +325,9 @@ defineSuite([ return imagery.state === ImageryState.READY; }).then(function() { expect(imagery.texture).toBeDefined(); + expect(imagery.texture.sampler).toBeDefined(); + expect(imagery.texture.sampler.minificationFilter).toEqual(TextureMinificationFilter.LINEAR_MIPMAP_LINEAR); + expect(imagery.texture.sampler.magnificationFilter).toEqual(TextureMinificationFilter.LINEAR); expect(imagery.texture).toBe(imagery.textureWebMercator); imagery.releaseReference(); }); @@ -367,6 +380,41 @@ defineSuite([ expect(layer.isDestroyed()).toEqual(true); }); + it('allows setting texture filter properties', function() { + var provider = new SingleTileImageryProvider({ + url : 'Data/Images/Red16x16.png' + }); + + // expect default LINEAR + var layer = new ImageryLayer(provider); + expect(layer.minificationFilter).toEqual(TextureMinificationFilter.LINEAR); + expect(layer.magnificationFilter).toEqual(TextureMagnificationFilter.LINEAR); + layer.destroy(); + + // change to NEAREST + layer = new ImageryLayer(provider, { + minificationFilter: TextureMinificationFilter.NEAREST, + magnificationFilter: TextureMagnificationFilter.NEAREST + }); + expect(layer.minificationFilter).toEqual(TextureMinificationFilter.NEAREST); + expect(layer.magnificationFilter).toEqual(TextureMagnificationFilter.NEAREST); + layer.destroy(); + }); + + it('uses default texture filter properties of ImageryProvider', function() { + var provider = new SingleTileImageryProvider({ + url : 'Data/Images/Red16x16.png' + }); + + provider.defaultMinificationFilter = TextureMinificationFilter.NEAREST; + provider.defaultMagnificationFilter = TextureMinificationFilter.NEAREST; + + var layer = new ImageryLayer(provider); + expect(layer.minificationFilter).toEqual(TextureMinificationFilter.NEAREST); + expect(layer.magnificationFilter).toEqual(TextureMagnificationFilter.NEAREST); + layer.destroy(); + }); + it('returns HTTP status code information in TileProviderError', function() { // Web browsers unfortunately provide very little information about what went wrong when an Image fails // to load. But when an imagery provider is configured to use a TileDiscardPolicy, Cesium downloads the image diff --git a/Specs/Scene/OrthographicFrustumSpec.js b/Specs/Scene/OrthographicFrustumSpec.js deleted file mode 100644 index 1c86468ada21..000000000000 --- a/Specs/Scene/OrthographicFrustumSpec.js +++ /dev/null @@ -1,170 +0,0 @@ -defineSuite([ - 'Scene/OrthographicFrustum', - 'Core/Cartesian2', - 'Core/Cartesian3', - 'Core/Cartesian4', - 'Core/Math', - 'Core/Matrix4' - ], function( - OrthographicFrustum, - Cartesian2, - Cartesian3, - Cartesian4, - CesiumMath, - Matrix4) { - 'use strict'; - - var frustum, planes; - - beforeEach(function() { - frustum = new OrthographicFrustum(); - frustum.near = 1.0; - frustum.far = 3.0; - frustum.width = 2.0; - frustum.aspectRatio = 1.0; - planes = frustum.computeCullingVolume(new Cartesian3(), Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3()), Cartesian3.UNIT_Y).planes; - }); - - it('undefined width causes an exception', function() { - frustum.width = undefined; - expect(function() { - return frustum.projectionMatrix; - }).toThrowDeveloperError(); - }); - - it('undefined aspectRatio throws an exception', function() { - frustum.aspectRatio = undefined; - expect(function() { - return frustum.projectionMatrix; - }).toThrowDeveloperError(); - }); - - it('out of range near plane throws an exception', function() { - frustum.near = -1.0; - expect(function() { - return frustum.projectionMatrix; - }).toThrowDeveloperError(); - - frustum.far = 3.0; - expect(function() { - return frustum.projectionMatrix; - }).toThrowDeveloperError(); - }); - - it('negative far plane throws an exception', function() { - frustum.far = -1.0; - expect(function() { - return frustum.projectionMatrix; - }).toThrowDeveloperError(); - }); - - it('computeCullingVolume with no position throws an exception', function() { - expect(function() { - return frustum.computeCullingVolume(); - }).toThrowDeveloperError(); - }); - - it('computeCullingVolume with no direction throws an exception', function() { - expect(function() { - return frustum.computeCullingVolume(new Cartesian3()); - }).toThrowDeveloperError(); - }); - - it('computeCullingVolume with no up throws an exception', function() { - expect(function() { - return frustum.computeCullingVolume(new Cartesian3(), new Cartesian3()); - }).toThrowDeveloperError(); - }); - - it('get frustum left plane', function() { - var leftPlane = planes[0]; - var expectedResult = new Cartesian4(1.0, 0.0, 0.0, 1.0); - expect(leftPlane).toEqualEpsilon(expectedResult, CesiumMath.EPSILON4); - }); - - it('get frustum right plane', function() { - var rightPlane = planes[1]; - var expectedResult = new Cartesian4(-1.0, 0.0, 0.0, 1.0); - expect(rightPlane).toEqualEpsilon(expectedResult, CesiumMath.EPSILON4); - }); - - it('get frustum bottom plane', function() { - var bottomPlane = planes[2]; - var expectedResult = new Cartesian4(0.0, 1.0, 0.0, 1.0); - expect(bottomPlane).toEqualEpsilon(expectedResult, CesiumMath.EPSILON4); - }); - - it('get frustum top plane', function() { - var topPlane = planes[3]; - var expectedResult = new Cartesian4(0.0, -1.0, 0.0, 1.0); - expect(topPlane).toEqual(expectedResult, CesiumMath.EPSILON4); - }); - - it('get frustum near plane', function() { - var nearPlane = planes[4]; - var expectedResult = new Cartesian4(0.0, 0.0, -1.0, -1.0); - expect(nearPlane).toEqualEpsilon(expectedResult, CesiumMath.EPSILON4); - }); - - it('get frustum far plane', function() { - var farPlane = planes[5]; - var expectedResult = new Cartesian4(0.0, 0.0, 1.0, 3.0); - expect(farPlane).toEqualEpsilon(expectedResult, CesiumMath.EPSILON4); - }); - - it('get orthographic projection matrix', function() { - var projectionMatrix = frustum.projectionMatrix; - frustum = frustum._offCenterFrustum; - var expected = Matrix4.computeOrthographicOffCenter(frustum.left, frustum.right, frustum.bottom, frustum.top, frustum.near, frustum.far, new Matrix4()); - expect(projectionMatrix).toEqualEpsilon(expected, CesiumMath.EPSILON6); - }); - - it('get pixel dimensions throws without canvas height', function() { - expect(function() { - return frustum.getPixelDimensions(1.0, undefined, 0.0, new Cartesian2()); - }).toThrowDeveloperError(); - }); - - it('get pixel dimensions throws without canvas width', function() { - expect(function() { - return frustum.getPixelDimensions(undefined, 1.0, 0.0, new Cartesian2()); - }).toThrowDeveloperError(); - }); - - it('get pixel dimensions throws with canvas width less than or equal to zero', function() { - expect(function() { - return frustum.getPixelDimensions(0.0, 1.0, 0.0, new Cartesian2()); - }).toThrowDeveloperError(); - }); - - it('get pixel dimensions throws with canvas height less than or equal to zero', function() { - expect(function() { - return frustum.getPixelDimensions(1.0, 0.0, 0.0, new Cartesian2()); - }).toThrowDeveloperError(); - }); - - it('get pixel dimensions', function() { - var pixelSize = frustum.getPixelDimensions(1.0, 1.0, 0.0, new Cartesian2()); - expect(pixelSize.x).toEqual(2.0); - expect(pixelSize.y).toEqual(2.0); - }); - - it('throws with undefined frustum parameters', function() { - var frustum = new OrthographicFrustum(); - expect(function() { - return frustum.projectionMatrix; - }).toThrowDeveloperError(); - }); - - it('clone', function() { - var frustum2 = frustum.clone(); - expect(frustum).toEqual(frustum2); - }); - - it('clone with result parameter', function() { - var result = new OrthographicFrustum(); - var frustum2 = frustum.clone(result); - expect(frustum2).toBe(result); - expect(frustum).toEqual(frustum2); - }); -}); diff --git a/Specs/Scene/OrthographicOffCenterFrustumSpec.js b/Specs/Scene/OrthographicOffCenterFrustumSpec.js deleted file mode 100644 index 4f907e8c44a8..000000000000 --- a/Specs/Scene/OrthographicOffCenterFrustumSpec.js +++ /dev/null @@ -1,171 +0,0 @@ -defineSuite([ - 'Scene/OrthographicOffCenterFrustum', - 'Core/Cartesian2', - 'Core/Cartesian3', - 'Core/Cartesian4', - 'Core/Math', - 'Core/Matrix4' - ], function( - OrthographicOffCenterFrustum, - Cartesian2, - Cartesian3, - Cartesian4, - CesiumMath, - Matrix4) { - 'use strict'; - - var frustum, planes; - - beforeEach(function() { - frustum = new OrthographicOffCenterFrustum(); - frustum.near = 1.0; - frustum.far = 3.0; - frustum.right = 1.0; - frustum.left = -1.0; - frustum.top = 1.0; - frustum.bottom = -1.0; - planes = frustum.computeCullingVolume(new Cartesian3(), Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3()), Cartesian3.UNIT_Y).planes; - }); - - it('left greater than right causes an exception', function() { - frustum.left = frustum.right + 1.0; - expect(function() { - return frustum.projectionMatrix; - }).toThrowDeveloperError(); - }); - - it('bottom greater than top throws an exception', function() { - frustum.bottom = frustum.top + 1.0; - expect(function() { - return frustum.projectionMatrix; - }).toThrowDeveloperError(); - }); - - it('out of range near plane throws an exception', function() { - frustum.near = -1.0; - expect(function() { - return frustum.projectionMatrix; - }).toThrowDeveloperError(); - - frustum.far = 3.0; - expect(function() { - return frustum.projectionMatrix; - }).toThrowDeveloperError(); - }); - - it('negative far plane throws an exception', function() { - frustum.far = -1.0; - expect(function() { - return frustum.projectionMatrix; - }).toThrowDeveloperError(); - }); - - it('computeCullingVolume with no position throws an exception', function() { - expect(function() { - return frustum.computeCullingVolume(); - }).toThrowDeveloperError(); - }); - - it('computeCullingVolume with no direction throws an exception', function() { - expect(function() { - return frustum.computeCullingVolume(new Cartesian3()); - }).toThrowDeveloperError(); - }); - - it('computeCullingVolume with no up throws an exception', function() { - expect(function() { - return frustum.computeCullingVolume(new Cartesian3(), new Cartesian3()); - }).toThrowDeveloperError(); - }); - - it('get frustum left plane', function() { - var leftPlane = planes[0]; - var expectedResult = new Cartesian4(1.0, 0.0, 0.0, 1.0); - expect(leftPlane).toEqualEpsilon(expectedResult, CesiumMath.EPSILON4); - }); - - it('get frustum right plane', function() { - var rightPlane = planes[1]; - var expectedResult = new Cartesian4(-1.0, 0.0, 0.0, 1.0); - expect(rightPlane).toEqualEpsilon(expectedResult, CesiumMath.EPSILON4); - }); - - it('get frustum bottom plane', function() { - var bottomPlane = planes[2]; - var expectedResult = new Cartesian4(0.0, 1.0, 0.0, 1.0); - expect(bottomPlane).toEqualEpsilon(expectedResult, CesiumMath.EPSILON4); - }); - - it('get frustum top plane', function() { - var topPlane = planes[3]; - var expectedResult = new Cartesian4(0.0, -1.0, 0.0, 1.0); - expect(topPlane).toEqual(expectedResult, CesiumMath.EPSILON4); - }); - - it('get frustum near plane', function() { - var nearPlane = planes[4]; - var expectedResult = new Cartesian4(0.0, 0.0, -1.0, -1.0); - expect(nearPlane).toEqualEpsilon(expectedResult, CesiumMath.EPSILON4); - }); - - it('get frustum far plane', function() { - var farPlane = planes[5]; - var expectedResult = new Cartesian4(0.0, 0.0, 1.0, 3.0); - expect(farPlane).toEqualEpsilon(expectedResult, CesiumMath.EPSILON4); - }); - - it('get orthographic projection matrix', function() { - var projectionMatrix = frustum.projectionMatrix; - var expected = Matrix4.computeOrthographicOffCenter(frustum.left, frustum.right, frustum.bottom, frustum.top, frustum.near, frustum.far, new Matrix4()); - expect(projectionMatrix).toEqualEpsilon(expected, CesiumMath.EPSILON6); - }); - - it('get pixel dimensions throws without canvas height', function() { - expect(function() { - return frustum.getPixelDimensions(1.0, undefined, 0.0, new Cartesian2()); - }).toThrowDeveloperError(); - }); - - it('get pixel dimensions throws without canvas width', function() { - expect(function() { - return frustum.getPixelDimensions(undefined, 1.0, 0.0, new Cartesian2()); - }).toThrowDeveloperError(); - }); - - it('get pixel dimensions throws with canvas width less than or equal to zero', function() { - expect(function() { - return frustum.getPixelDimensions(0.0, 1.0, 0.0, new Cartesian2()); - }).toThrowDeveloperError(); - }); - - it('get pixel dimensions throws with canvas height less than or equal to zero', function() { - expect(function() { - return frustum.getPixelDimensions(1.0, 0.0, 0.0, new Cartesian2()); - }).toThrowDeveloperError(); - }); - - it('get pixel dimensions', function() { - var pixelSize = frustum.getPixelDimensions(1.0, 1.0, 0.0, new Cartesian2()); - expect(pixelSize.x).toEqual(2.0); - expect(pixelSize.y).toEqual(2.0); - }); - - it('throws with undefined frustum parameters', function() { - var frustum = new OrthographicOffCenterFrustum(); - expect(function() { - return frustum.projectionMatrix; - }).toThrowDeveloperError(); - }); - - it('clone', function() { - var frustum2 = frustum.clone(); - expect(frustum).toEqual(frustum2); - }); - - it('clone with result parameter', function() { - var result = new OrthographicOffCenterFrustum(); - var frustum2 = frustum.clone(result); - expect(frustum2).toBe(result); - expect(frustum).toEqual(frustum2); - }); -}); diff --git a/Specs/Scene/PerspectiveFrustumSpec.js b/Specs/Scene/PerspectiveFrustumSpec.js deleted file mode 100644 index 91805a77ee43..000000000000 --- a/Specs/Scene/PerspectiveFrustumSpec.js +++ /dev/null @@ -1,175 +0,0 @@ -defineSuite([ - 'Scene/PerspectiveFrustum', - 'Core/Cartesian2', - 'Core/Cartesian3', - 'Core/Cartesian4', - 'Core/Math', - 'Core/Matrix4' - ], function( - PerspectiveFrustum, - Cartesian2, - Cartesian3, - Cartesian4, - CesiumMath, - Matrix4) { - 'use strict'; - - var frustum, planes; - - beforeEach(function() { - frustum = new PerspectiveFrustum(); - frustum.near = 1.0; - frustum.far = 2.0; - frustum.aspectRatio = 1.0; - frustum.fov = (Math.PI) / 3; - planes = frustum.computeCullingVolume(new Cartesian3(), Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3()), Cartesian3.UNIT_Y).planes; - }); - - it('out of range fov causes an exception', function() { - frustum.fov = -1.0; - expect(function() { - return frustum.projectionMatrix; - }).toThrowDeveloperError(); - - frustum.fov = CesiumMath.TWO_PI; - expect(function() { - return frustum.projectionMatrix; - }).toThrowDeveloperError(); - }); - - it('negative aspect ratio throws an exception', function() { - frustum.aspectRatio = -1.0; - expect(function() { - return frustum.projectionMatrix; - }).toThrowDeveloperError(); - }); - - it('out of range near plane throws an exception', function() { - frustum.near = -1.0; - expect(function() { - return frustum.projectionMatrix; - }).toThrowDeveloperError(); - }); - - it('negative far plane throws an exception', function() { - frustum.far = -1.0; - expect(function() { - return frustum.projectionMatrix; - }).toThrowDeveloperError(); - }); - - it('computeCullingVolume with no position throws an exception', function() { - expect(function() { - return frustum.computeCullingVolume(); - }).toThrowDeveloperError(); - }); - - it('computeCullingVolume with no direction throws an exception', function() { - expect(function() { - return frustum.computeCullingVolume(new Cartesian3()); - }).toThrowDeveloperError(); - }); - - it('computeCullingVolume with no up throws an exception', function() { - expect(function() { - return frustum.computeCullingVolume(new Cartesian3(), new Cartesian3()); - }).toThrowDeveloperError(); - }); - - it('get frustum left plane', function() { - var leftPlane = planes[0]; - var expectedResult = new Cartesian4(Math.sqrt(3.0) / 2.0, 0.0, -0.5, 0.0); - expect(leftPlane).toEqualEpsilon(expectedResult, CesiumMath.EPSILON14); - }); - - it('get frustum right plane', function() { - var rightPlane = planes[1]; - var expectedResult = new Cartesian4(-Math.sqrt(3.0) / 2.0, 0.0, -0.5, 0.0); - expect(rightPlane).toEqualEpsilon(expectedResult, CesiumMath.EPSILON14); - }); - - it('get frustum bottom plane', function() { - var bottomPlane = planes[2]; - var expectedResult = new Cartesian4(0.0, Math.sqrt(3.0) / 2.0, -0.5, 0.0); - expect(bottomPlane).toEqualEpsilon(expectedResult, CesiumMath.EPSILON14); - }); - - it('get frustum top plane', function() { - var topPlane = planes[3]; - var expectedResult = new Cartesian4(0.0, -Math.sqrt(3.0) / 2.0, -0.5, 0.0); - expect(topPlane).toEqualEpsilon(expectedResult, CesiumMath.EPSILON14); - }); - - it('get frustum near plane', function() { - var nearPlane = planes[4]; - var expectedResult = new Cartesian4(0.0, 0.0, -1.0, -1.0); - expect(nearPlane).toEqual(expectedResult); - }); - - it('get frustum far plane', function() { - var farPlane = planes[5]; - var expectedResult = new Cartesian4(0.0, 0.0, 1.0, 2.0); - expect(farPlane).toEqual(expectedResult); - }); - - it('get sseDenominator', function() { - expect(frustum.sseDenominator).toEqualEpsilon(1.1547, CesiumMath.EPSILON5); - }); - - it('get perspective projection matrix', function() { - var projectionMatrix = frustum.projectionMatrix; - var expected = Matrix4.computePerspectiveFieldOfView(frustum.fovy, frustum.aspectRatio, frustum.near, frustum.far, new Matrix4()); - expect(projectionMatrix).toEqualEpsilon(expected, CesiumMath.EPSILON6); - }); - - it('get infinite perspective matrix', function() { - var top = frustum.near * Math.tan(0.5 * frustum.fovy); - var bottom = -top; - var right = frustum.aspectRatio * top; - var left = -right; - var near = frustum.near; - - var expected = Matrix4.computeInfinitePerspectiveOffCenter(left, right, bottom, top, near, new Matrix4()); - expect(frustum.infiniteProjectionMatrix).toEqual(expected); - }); - - it('get pixel dimensions', function() { - var dimensions = new Cartesian2(1.0, 1.0); - var pixelSize = frustum.getPixelDimensions(dimensions.x, dimensions.y, 1.0, new Cartesian2()); - var expected = frustum._offCenterFrustum.getPixelDimensions(dimensions.x, dimensions.y, 1.0, new Cartesian2()); - expect(pixelSize.x).toEqual(expected.x); - expect(pixelSize.y).toEqual(expected.y); - }); - - it('equals', function() { - var frustum2 = new PerspectiveFrustum(); - frustum2.near = 1.0; - frustum2.far = 2.0; - frustum2.fov = (Math.PI) / 3.0; - frustum2.aspectRatio = 1.0; - expect(frustum.equals(frustum2)).toEqual(true); - }); - - it('equals undefined', function() { - expect(frustum.equals()).toEqual(false); - }); - - it('throws with undefined frustum parameters', function() { - var frustum = new PerspectiveFrustum(); - expect(function() { - return frustum.infiniteProjectionMatrix; - }).toThrowDeveloperError(); - }); - - it('clone', function() { - var frustum2 = frustum.clone(); - expect(frustum).toEqual(frustum2); - }); - - it('clone with result parameter', function() { - var result = new PerspectiveFrustum(); - var frustum2 = frustum.clone(result); - expect(frustum2).toBe(result); - expect(frustum).toEqual(frustum2); - }); -}); diff --git a/Specs/Scene/PerspectiveOffCenterFrustumSpec.js b/Specs/Scene/PerspectiveOffCenterFrustumSpec.js deleted file mode 100644 index 67289e1cb889..000000000000 --- a/Specs/Scene/PerspectiveOffCenterFrustumSpec.js +++ /dev/null @@ -1,190 +0,0 @@ -defineSuite([ - 'Scene/PerspectiveOffCenterFrustum', - 'Core/Cartesian2', - 'Core/Cartesian3', - 'Core/Cartesian4', - 'Core/Math', - 'Core/Matrix4' - ], function( - PerspectiveOffCenterFrustum, - Cartesian2, - Cartesian3, - Cartesian4, - CesiumMath, - Matrix4) { - 'use strict'; - - var frustum, planes; - - beforeEach(function() { - frustum = new PerspectiveOffCenterFrustum(); - frustum.right = 1.0; - frustum.left = -frustum.right; - frustum.top = 1.0; - frustum.bottom = -frustum.top; - frustum.near = 1.0; - frustum.far = 2.0; - planes = frustum.computeCullingVolume(new Cartesian3(), Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3()), Cartesian3.UNIT_Y).planes; - }); - - it('out of range near plane throws an exception', function() { - frustum.near = -1.0; - expect(function() { - return frustum.projectionMatrix; - }).toThrowDeveloperError(); - }); - - it('negative far plane throws an exception', function() { - frustum.far = -1.0; - expect(function() { - return frustum.projectionMatrix; - }).toThrowDeveloperError(); - }); - - it('computeCullingVolume with no position throws an exception', function() { - expect(function() { - return frustum.computeCullingVolume(); - }).toThrowDeveloperError(); - }); - - it('computeCullingVolume with no direction throws an exception', function() { - expect(function() { - return frustum.computeCullingVolume(new Cartesian3()); - }).toThrowDeveloperError(); - }); - - it('computeCullingVolume with no up throws an exception', function() { - expect(function() { - return frustum.computeCullingVolume(new Cartesian3(), new Cartesian3()); - }).toThrowDeveloperError(); - }); - - it('get frustum left plane', function() { - var leftPlane = planes[0]; - var x = 1.0 / Math.sqrt(2.0); - var expectedResult = new Cartesian4(x, 0.0, -x, 0.0); - expect(leftPlane).toEqualEpsilon(expectedResult, CesiumMath.EPSILON15); - }); - - it('get frustum right plane', function() { - var rightPlane = planes[1]; - var x = 1.0 / Math.sqrt(2.0); - var expectedResult = new Cartesian4(-x, 0.0, -x, 0.0); - expect(rightPlane).toEqualEpsilon(expectedResult, CesiumMath.EPSILON15); - }); - - it('get frustum bottom plane', function() { - var bottomPlane = planes[2]; - var x = 1.0 / Math.sqrt(2.0); - var expectedResult = new Cartesian4(0.0, x, -x, 0.0); - expect(bottomPlane).toEqualEpsilon(expectedResult, CesiumMath.EPSILON15); - }); - - it('get frustum top plane', function() { - var topPlane = planes[3]; - var x = 1.0 / Math.sqrt(2.0); - var expectedResult = new Cartesian4(0.0, -x, -x, 0.0); - expect(topPlane).toEqualEpsilon(expectedResult, CesiumMath.EPSILON15); - }); - - it('get frustum near plane', function() { - var nearPlane = planes[4]; - var expectedResult = new Cartesian4(0.0, 0.0, -1.0, -1.0); - expect(nearPlane).toEqualEpsilon(expectedResult, CesiumMath.EPSILON15); - }); - - it('get frustum far plane', function() { - var farPlane = planes[5]; - var expectedResult = new Cartesian4(0.0, 0.0, 1.0, 2.0); - expect(farPlane).toEqualEpsilon(expectedResult, CesiumMath.EPSILON15); - }); - - it('get perspective projection matrix', function() { - var projectionMatrix = frustum.projectionMatrix; - - var top = frustum.top; - var bottom = frustum.bottom; - var right = frustum.right; - var left = frustum.left; - var near = frustum.near; - var far = frustum.far; - var expected = Matrix4.computePerspectiveOffCenter(left, right, bottom, top, near, far, new Matrix4()); - - expect(projectionMatrix).toEqualEpsilon(expected, CesiumMath.EPSILON6); - }); - - it('get infinite perspective matrix', function() { - var top = frustum.top; - var bottom = frustum.bottom; - var right = frustum.right; - var left = frustum.left; - var near = frustum.near; - - var expected = Matrix4.computeInfinitePerspectiveOffCenter(left, right, bottom, top, near, new Matrix4()); - expect(expected).toEqual(frustum.infiniteProjectionMatrix); - }); - - it('get pixel dimensions throws without canvas height', function() { - expect(function() { - return frustum.getPixelDimensions(1.0, undefined, 1.0, new Cartesian2()); - }).toThrowDeveloperError(); - }); - - it('get pixel dimensions throws without canvas width', function() { - expect(function() { - return frustum.getPixelDimensions(undefined, 1.0, 1.0, new Cartesian2()); - }).toThrowDeveloperError(); - }); - - it('get pixel dimensions throws with canvas width less than or equal to zero', function() { - expect(function() { - return frustum.getPixelDimensions(0.0, 1.0, 1.0, new Cartesian2()); - }).toThrowDeveloperError(); - }); - - it('get pixel dimensions throws with canvas height less than or equal to zero', function() { - expect(function() { - return frustum.getPixelDimensions(1.0, 0.0, 1.0, new Cartesian2()); - }).toThrowDeveloperError(); - }); - - it('get pixel dimensions', function() { - var pixelSize = frustum.getPixelDimensions(1.0, 1.0, 1.0, new Cartesian2()); - expect(pixelSize.x).toEqual(2.0); - expect(pixelSize.y).toEqual(2.0); - }); - - it('equals', function() { - var frustum2 = new PerspectiveOffCenterFrustum(); - frustum2.right = 1.0; - frustum2.left = -frustum.right; - frustum2.top = 1.0; - frustum2.bottom = -frustum.top; - frustum2.near = 1.0; - frustum2.far = 2.0; - frustum2.position = new Cartesian3(); - frustum2.direction = Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3()); - frustum2.up = Cartesian3.UNIT_Y; - - expect(frustum).toEqual(frustum2); - }); - - it('throws with undefined frustum parameters', function() { - var frustum = new PerspectiveOffCenterFrustum(); - expect(function() { - return frustum.infiniteProjectionMatrix; - }).toThrowDeveloperError(); - }); - - it('clone', function() { - var frustum2 = frustum.clone(); - expect(frustum).toEqual(frustum2); - }); - - it('clone with result parameter', function() { - var result = new PerspectiveOffCenterFrustum(); - var frustum2 = frustum.clone(result); - expect(frustum2).toBe(result); - expect(frustum).toEqual(frustum2); - }); -}); diff --git a/Specs/Scene/TimeDynamicImagerySpec.js b/Specs/Scene/TimeDynamicImagerySpec.js index 4e26c96f545a..c0af7ab448b8 100644 --- a/Specs/Scene/TimeDynamicImagerySpec.js +++ b/Specs/Scene/TimeDynamicImagerySpec.js @@ -1,4 +1,3 @@ -/*global defineSuite*/ defineSuite([ 'Scene/TimeDynamicImagery', 'Core/Clock', 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/Scene/createTileMapServiceImageryProviderSpec.js b/Specs/Scene/createTileMapServiceImageryProviderSpec.js index 0483b97b277e..6f40f347abad 100644 --- a/Specs/Scene/createTileMapServiceImageryProviderSpec.js +++ b/Specs/Scene/createTileMapServiceImageryProviderSpec.js @@ -105,6 +105,41 @@ defineSuite([ }); }); + it('rejects readyPromise on invalid xml', function() { + loadWithXhr.load = function(url, responseType, method, data, headers, deferred, overrideMimeType) { + // We can't resolve the promise immediately, because then the error would be raised + // before we could subscribe to it. This a problem particular to tests. + setTimeout(function() { + var parser = new DOMParser(); + var xmlString = + '' + + ' ' + + ' <Abstract/>' + + ' <SRS>EPSG:4326</SRS>' + + ' <Origin x="-90.0" y="-180.0"/>' + + ' <TileFormat width="256" height="256" mime-type="image/png" extension="png"/>' + + ' <TileSets profile="foobar">' + + ' <TileSet href="2" units-per-pixel="39135.75848201024200" order="2"/>' + + ' <TileSet href="3" units-per-pixel="19567.87924100512100" order="3"/>' + + ' </TileSets>' + + '</TileMap>'; + var xml = parser.parseFromString(xmlString, "text/xml"); + deferred.resolve(xml); + }, 1); + }; + + var provider = createTileMapServiceImageryProvider({ + url : 'made/up/tms/server' + }); + + return provider.readyPromise.then(function() { + fail('should not resolve'); + }).otherwise(function (e) { + expect(provider.ready).toBe(false); + expect(e.message).toContain('expected tilesets or bbox attributes'); + }); + }); + it('requires the url to be specified', function() { function createWithoutUrl() { return createTileMapServiceImageryProvider({}); diff --git a/Specs/customizeJasmine.js b/Specs/customizeJasmine.js index 21dbdce268f3..4528777b094d 100644 --- a/Specs/customizeJasmine.js +++ b/Specs/customizeJasmine.js @@ -42,6 +42,8 @@ define([ }); } + window.specsUsingRelease = release; + window.fdefineSuite = function(deps, name, suite, categories) { defineSuite(deps, name, suite, categories, true); }; 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 }); } diff --git a/Specs/spec-main.js b/Specs/spec-main.js index 9ba3c174eeea..78342be219ad 100644 --- a/Specs/spec-main.js +++ b/Specs/spec-main.js @@ -21,6 +21,7 @@ } var built = getQueryParameter('built'); + var release = getQueryParameter('release'); var toRequire = ['Cesium']; @@ -73,6 +74,8 @@ */ window.jasmine = jasmineRequire.core(jasmineRequire); + window.specsUsingRelease = release; + window.defineSuite = function(deps, name, suite, categories) { /*global define,describe*/ if (typeof suite === 'object' || typeof suite === 'string') { diff --git a/gulpfile.js b/gulpfile.js index 6be3722bd14b..9146b78c595d 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -113,7 +113,10 @@ gulp.task('build-watch', function() { }); gulp.task('buildApps', function() { - return buildCesiumViewer(); + return Promise.join( + buildCesiumViewer(), + buildSandcastle() + ); }); gulp.task('clean', function(done) { @@ -516,7 +519,7 @@ function getMimeType(filename) { return {type : 'application/font-woff', compress : false, isCompressed : false}; } - var mimeType = mime.lookup(filename); + var mimeType = mime.getType(filename); var compress = compressible(mimeType); return {type : mimeType, compress : compress, isCompressed : false}; } @@ -1046,11 +1049,6 @@ function createCesiumJs() { file = path.relative('Source', file); var moduleId = file; moduleId = filePathToModuleId(moduleId); - if (moduleId === 'Scene/OrthographicFrustum' || moduleId === 'Scene/OrthographicOffCenterFrustum' || - moduleId === 'Scene/PerspectiveFrustum' || moduleId === 'Scene/PerspectiveOffCenterFrustum' || - moduleId === 'Scene/CullingVolume') { - return; - } var assignmentName = "['" + path.basename(file, path.extname(file)) + "']"; if (moduleId.indexOf('Shaders/') === 0) { @@ -1158,6 +1156,35 @@ var sandcastleJsHintOptions = ' + JSON.stringify(primary, null, 4) + ';'; fs.writeFileSync(path.join('Apps', 'Sandcastle', 'jsHintOptions.js'), contents); } +function buildSandcastle() { + var appStream = gulp.src([ + 'Apps/Sandcastle/**', + '!Apps/Sandcastle/images/**', + '!Apps/Sandcastle/gallery/**.jpg' + ]) + // Replace require Source with pre-built Cesium + .pipe(gulpReplace('../../../ThirdParty/requirejs-2.1.20/require.js', '../../../CesiumUnminified/Cesium.js')) + // Use unminified cesium instead of source + .pipe(gulpReplace('Source/Cesium', 'CesiumUnminified')) + // Fix relative paths for new location + .pipe(gulpReplace('../../Source', '../../../Source')) + .pipe(gulpReplace('../../ThirdParty', '../../../ThirdParty')) + .pipe(gulpReplace('../../SampleData', '../../../../Apps/SampleData')) + .pipe(gulpReplace('Build/Documentation', 'Documentation')) + .pipe(gulp.dest('Build/Apps/Sandcastle')); + + var imageStream = gulp.src([ + 'Apps/Sandcastle/gallery/**.jpg', + 'Apps/Sandcastle/images/**' + ], { + base: 'Apps/Sandcastle', + buffer: false + }) + .pipe(gulp.dest('Build/Apps/Sandcastle')); + + return eventStream.merge(appStream, imageStream); +} + function buildCesiumViewer() { var cesiumViewerOutputDirectory = 'Build/Apps/CesiumViewer'; var cesiumViewerStartup = path.join(cesiumViewerOutputDirectory, 'CesiumViewerStartup.js'); diff --git a/index.html b/index.html index f4e700456904..bf40eef356d3 100644 --- a/index.html +++ b/index.html @@ -27,6 +27,7 @@ </li> <li> <a href="Apps/Sandcastle/index.html">Sandcastle</a> + (<a href="Build/Apps/Sandcastle/index.html">built version</a>) </li> <li> <a href="Apps/CesiumViewer/index.html?inspector=true">Cesium Inspector</a> diff --git a/package.json b/package.json index 0ccb1271f579..f2b438836387 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cesium", - "version": "1.37.0", + "version": "1.38.0", "description": "Cesium is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.", "homepage": "http://cesiumjs.org", "license": "Apache-2.0", @@ -48,7 +48,7 @@ "gulp": "^3.9.1", "gulp-insert": "^0.5.0", "gulp-rename": "^1.2.2", - "gulp-replace": "^0.5.4", + "gulp-replace": "^0.6.1", "gulp-tap": "^1.0.1", "gulp-zip": "^4.0.0", "jasmine-core": "^2.5.2", @@ -56,7 +56,7 @@ "karma": "^1.3.0", "karma-chrome-launcher": "^2.0.0", "karma-detect-browsers": "^2.2.3", - "karma-edge-launcher": "^0.2.0", + "karma-edge-launcher": "^0.4.2", "karma-electron": "^5.1.1", "karma-firefox-launcher": "^1.0.0", "karma-ie-launcher": "^1.0.0", @@ -64,11 +64,11 @@ "karma-requirejs": "^1.1.0", "karma-safari-launcher": "^1.0.0", "karma-spec-reporter": "^0.0.31", - "mime": "^1.3.4", + "mime": "^2.0.3", "mkdirp": "^0.5.1", "request": "^2.79.0", "rimraf": "^2.6.1", - "yargs": "^8.0.1" + "yargs": "^9.0.1" }, "scripts": { "start": "node server.js", diff --git a/server.js b/server.js index 31b98cb4875a..22e1a0d2c508 100644 --- a/server.js +++ b/server.js @@ -48,7 +48,7 @@ 'model/gltf-binary' : ['bgltf', 'glb'], 'application/octet-stream' : ['b3dm', 'pnts', 'i3dm', 'cmpt'], 'text/plain' : ['glsl'] - }); + }, true); var app = express(); app.use(compression());