diff --git a/Source/Scene/Batched3DModel3DTileContent.js b/Source/Scene/Batched3DModel3DTileContent.js index 11bf088f2f2f..532c152b618d 100644 --- a/Source/Scene/Batched3DModel3DTileContent.js +++ b/Source/Scene/Batched3DModel3DTileContent.js @@ -10,15 +10,10 @@ define([ '../Core/DeveloperError', '../Core/getAbsoluteUri', '../Core/getBaseUri', - '../Core/getMagic', '../Core/getStringFromTypedArray', - '../Core/loadArrayBuffer', - '../Core/Request', - '../Core/RequestScheduler', '../Core/RequestType', '../ThirdParty/when', './Cesium3DTileBatchTable', - './Cesium3DTileContentState', './Cesium3DTileFeature', './Cesium3DTileFeatureTable', './getAttributeOrUniformBySemantic', @@ -34,15 +29,10 @@ define([ DeveloperError, getAbsoluteUri, getBaseUri, - getMagic, getStringFromTypedArray, - loadArrayBuffer, - Request, - RequestScheduler, RequestType, when, Cesium3DTileBatchTable, - Cesium3DTileContentState, Cesium3DTileFeature, Cesium3DTileFeatureTable, getAttributeOrUniformBySemantic, @@ -59,7 +49,7 @@ define([ * * @private */ - function Batched3DModel3DTileContent(tileset, tile, url) { + function Batched3DModel3DTileContent(tileset, tile, url, arrayBuffer, byteOffset) { this._model = undefined; this._url = url; this._tileset = tileset; @@ -68,14 +58,12 @@ define([ /** * The following properties are part of the {@link Cesium3DTileContent} interface. */ - this.state = Cesium3DTileContentState.UNLOADED; this.batchTable = undefined; this.featurePropertiesDirty = false; - this._contentReadyToProcessPromise = when.defer(); - this._readyPromise = when.defer(); - this._featuresLength = 0; this._features = undefined; + + initialize(this, arrayBuffer, byteOffset); } // This can be overridden for testing purposes @@ -87,7 +75,7 @@ define([ */ featuresLength : { get : function() { - return this._featuresLength; + return this.batchTable.featuresLength; } }, @@ -105,10 +93,7 @@ define([ */ trianglesLength : { get : function() { - if (defined(this._model)) { - return this._model.trianglesLength; - } - return 0; + return this._model.trianglesLength; } }, @@ -117,10 +102,7 @@ define([ */ vertexMemorySizeInBytes : { get : function() { - if (defined(this._model)) { - return this._model.vertexMemorySizeInBytes; - } - return 0; + return this._model.vertexMemorySizeInBytes; } }, @@ -129,10 +111,7 @@ define([ */ textureMemorySizeInBytes : { get : function() { - if (defined(this._model)) { - return this._model.textureMemorySizeInBytes; - } - return 0; + return this._model.textureMemorySizeInBytes; } }, @@ -141,10 +120,7 @@ define([ */ batchTableMemorySizeInBytes : { get : function() { - if (defined(this.batchTable)) { - return this.batchTable.memorySizeInBytes; - } - return 0; + return this.batchTable.memorySizeInBytes; } }, @@ -157,28 +133,19 @@ define([ } }, - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - contentReadyToProcessPromise : { - get : function() { - return this._contentReadyToProcessPromise.promise; - } - }, - /** * Part of the {@link Cesium3DTileContent} interface. */ readyPromise : { get : function() { - return this._readyPromise.promise; + return this._model.readyPromise; } } }); function createFeatures(content) { var tileset = content._tileset; - var featuresLength = content._featuresLength; + var featuresLength = content.featuresLength; if (!defined(content._features) && (featuresLength > 0)) { var features = new Array(featuresLength); for (var i = 0; i < featuresLength; ++i) { @@ -199,7 +166,7 @@ define([ * Part of the {@link Cesium3DTileContent} interface. */ Batched3DModel3DTileContent.prototype.getFeature = function(batchId) { - var featuresLength = this._featuresLength; + var featuresLength = this.featuresLength; //>>includeStart('debug', pragmas.debug); if (!defined(batchId) || (batchId < 0) || (batchId >= featuresLength)) { throw new DeveloperError('batchId is required and between zero and featuresLength - 1 (' + (featuresLength - 1) + ').'); @@ -212,38 +179,6 @@ define([ var sizeOfUint32 = Uint32Array.BYTES_PER_ELEMENT; - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - Batched3DModel3DTileContent.prototype.request = function() { - var that = this; - - var distance = this._tile.distanceToCamera; - var promise = RequestScheduler.schedule(new Request({ - url : this._url, - server : this._tile.requestServer, - requestFunction : loadArrayBuffer, - type : RequestType.TILES3D, - distance : distance - })); - - if (!defined(promise)) { - return false; - } - - this.state = Cesium3DTileContentState.LOADING; - promise.then(function(arrayBuffer) { - if (that.isDestroyed()) { - return when.reject('tileset is destroyed'); - } - that.initialize(arrayBuffer); - }).otherwise(function(error) { - that.state = Cesium3DTileContentState.FAILED; - that._readyPromise.reject(error); - }); - return true; - }; - function getBatchIdAttributeName(gltf) { var batchIdAttributeName = getAttributeOrUniformBySemantic(gltf, '_BATCHID'); if (!defined(batchIdAttributeName)) { @@ -285,21 +220,17 @@ define([ }; } - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - Batched3DModel3DTileContent.prototype.initialize = function(arrayBuffer, byteOffset) { + function initialize(content, arrayBuffer, byteOffset) { + var tileset = content._tileset; + var tile = content._tile; + var basePath = getAbsoluteUri(getBaseUri(content._url, true)); + var byteStart = defaultValue(byteOffset, 0); byteOffset = byteStart; var uint8Array = new Uint8Array(arrayBuffer); - var magic = getMagic(uint8Array, byteOffset); - if (magic !== 'b3dm') { - throw new DeveloperError('Invalid Batched 3D Model. Expected magic=b3dm. Read magic=' + magic); - } - var view = new DataView(arrayBuffer); - byteOffset += sizeOfUint32; // Skip magic number + byteOffset += sizeOfUint32; // Skip magic //>>includeStart('debug', pragmas.debug); var version = view.getUint32(byteOffset, true); @@ -371,7 +302,6 @@ define([ batchLength = featureTable.getGlobalProperty('BATCH_LENGTH', ComponentDatatype.UNSIGNED_INT); featureTable.featuresLength = batchLength; - this._featuresLength = batchLength; var batchTableJson; var batchTableBinary; @@ -394,48 +324,35 @@ define([ } } - var batchTable = new Cesium3DTileBatchTable(this, batchLength, batchTableJson, batchTableBinary); - this.batchTable = batchTable; + var batchTable = new Cesium3DTileBatchTable(content, batchLength, batchTableJson, batchTableBinary); + content.batchTable = batchTable; var gltfByteLength = byteStart + byteLength - byteOffset; var gltfView = new Uint8Array(arrayBuffer, byteOffset, gltfByteLength); // PERFORMANCE_IDEA: patch the shader on demand, e.g., the first time show/color changes. // The pick shader still needs to be patched. - var model = new Model({ + content._model = new Model({ gltf : gltfView, cull : false, // The model is already culled by the 3D tiles releaseGltfJson : true, // Models are unique and will not benefit from caching so save memory - basePath : getAbsoluteUri(getBaseUri(this._url, true)), - modelMatrix : this._tile.computedTransform, - upAxis : this._tileset._gltfUpAxis, - shadows: this._tileset.shadows, - debugWireframe: this._tileset.debugWireframe, + basePath : basePath, + requestType : RequestType.TILES3D, + modelMatrix : tile.computedTransform, + upAxis : tileset._gltfUpAxis, + shadows: tileset.shadows, + debugWireframe: tileset.debugWireframe, incrementallyLoadTextures : false, - pickPrimitive : this._tileset, - vertexShaderLoaded : getVertexShaderCallback(this), - fragmentShaderLoaded : getFragmentShaderCallback(this), + pickPrimitive : tileset, + vertexShaderLoaded : getVertexShaderCallback(content), + fragmentShaderLoaded : getFragmentShaderCallback(content), uniformMapLoaded : batchTable.getUniformMapCallback(), - pickVertexShaderLoaded : getPickVertexShaderCallback(this), + pickVertexShaderLoaded : getPickVertexShaderCallback(content), pickFragmentShaderLoaded : batchTable.getPickFragmentShaderCallback(), pickUniformMapLoaded : batchTable.getPickUniformMapCallback(), addBatchIdToGeneratedShaders : (batchLength > 0) // If the batch table has values in it, generated shaders will need a batchId attribute }); - - this._model = model; - this.state = Cesium3DTileContentState.PROCESSING; - this._contentReadyToProcessPromise.resolve(this); - - var that = this; - - model.readyPromise.then(function(model) { - that.state = Cesium3DTileContentState.READY; - that._readyPromise.resolve(that); - }).otherwise(function(error) { - that.state = Cesium3DTileContentState.FAILED; - that._readyPromise.reject(error); - }); - }; + } /** * Part of the {@link Cesium3DTileContent} interface. diff --git a/Source/Scene/Cesium3DTile.js b/Source/Scene/Cesium3DTile.js index ae1a1c0787e6..cbe21565819a 100644 --- a/Source/Scene/Cesium3DTile.js +++ b/Source/Scene/Cesium3DTile.js @@ -13,16 +13,22 @@ define([ '../Core/DeveloperError', '../Core/GeometryInstance', '../Core/getExtensionFromUri', + '../Core/getMagic', + '../Core/getStringFromTypedArray', '../Core/Intersect', '../Core/joinUrls', + '../Core/loadArrayBuffer', '../Core/Matrix3', '../Core/Matrix4', '../Core/OrientedBoundingBox', '../Core/Rectangle', '../Core/RectangleOutlineGeometry', + '../Core/Request', '../Core/RequestScheduler', + '../Core/RequestType', '../Core/SphereOutlineGeometry', '../ThirdParty/Uri', + '../ThirdParty/when', './Cesium3DTileChildrenVisibility', './Cesium3DTileContentFactory', './Cesium3DTileContentState', @@ -50,16 +56,22 @@ define([ DeveloperError, GeometryInstance, getExtensionFromUri, + getMagic, + getStringFromTypedArray, Intersect, joinUrls, + loadArrayBuffer, Matrix3, Matrix4, OrientedBoundingBox, Rectangle, RectangleOutlineGeometry, + Request, RequestScheduler, + RequestType, SphereOutlineGeometry, Uri, + when, Cesium3DTileChildrenVisibility, Cesium3DTileContentFactory, Cesium3DTileContentState, @@ -163,17 +175,6 @@ define([ */ this.children = []; - /** - * Descendant tiles that need to be visible before this tile can refine. For example, if - * a child is empty (such as for accelerating culling), its descendants with content would - * be added here. This array is generated during runtime in {@link Cesium3DTileset#loadTileset}. - * If a tiles's children all have content, this is left undefined. - * - * @type {Array} - * @readonly - */ - this.descendantsWithContent = undefined; - /** * This tile's parent or undefined if this tile is the root. *

@@ -187,72 +188,75 @@ define([ */ this.parent = parent; - var hasContent; - var hasTilesetContent; + var content; + var hasEmptyContent; + var contentState; + var contentUrl; var requestServer; - var createContent; if (defined(contentHeader)) { - var contentUrl = contentHeader.url; - var url = joinUrls(baseUrl, contentUrl); - requestServer = RequestScheduler.getRequestServer(url); - var type = getExtensionFromUri(url); - var contentFactory = Cesium3DTileContentFactory[type]; - - if (type === 'json') { - hasContent = false; - hasTilesetContent = true; - } else { - hasContent = true; - hasTilesetContent = false; - } - - //>>includeStart('debug', pragmas.debug); - if (!defined(contentFactory)) { - throw new DeveloperError('Unknown tile content type, ' + type + ', for ' + url); - } - //>>includeEnd('debug'); - - var that = this; - createContent = function() { - return contentFactory(tileset, that, url); - }; + hasEmptyContent = false; + contentState = Cesium3DTileContentState.UNLOADED; + contentUrl = joinUrls(baseUrl, contentHeader.url); + requestServer = RequestScheduler.getRequestServer(contentUrl); } else { - hasContent = false; - hasTilesetContent = false; - - createContent = function() { - return new Empty3DTileContent(); - }; + content = new Empty3DTileContent(); + hasEmptyContent = true; + contentState = Cesium3DTileContentState.READY; } - this._createContent = createContent; - this._content = createContent(); + this._content = content; + this._contentUrl = contentUrl; + this._contentState = contentState; + this._contentReadyToProcessPromise = undefined; + this._contentReadyPromise = undefined; this._requestServer = requestServer; /** - * When true, the tile has content. This does not imply that the content is loaded. + * When true, the tile has no content. + * + * @type {Boolean} + * @readonly + * + * @see Empty3DTileContent + * + * @private + */ + this.hasEmptyContent = hasEmptyContent; + + /** + * When true, the tile's content is renderable. *

- * When a tile's content points to a external tileset, the tile is not considered to have content. + * This is false until the tile's content is loaded. *

* * @type {Boolean} * @readonly * + * @see Batched3DModel3DTileContent + * @see Instanced3DModel3DTileContent + * @see PointCloud3DTileContent + * @see Composite3DTileContent + * * @private */ - this.hasContent = hasContent; + this.hasRenderableContent = false; /** * When true, the tile's content points to an external tileset. + *

+ * This is false until the tile's content is loaded. + *

* * @type {Boolean} * @readonly * + * @see Tileset3DTileContent + * * @private */ - this.hasTilesetContent = hasTilesetContent; + this.hasTilesetContent = false; /** * The corresponding node in the cache replacement list. @@ -426,7 +430,7 @@ define([ */ contentReady : { get : function() { - return this._content.state === Cesium3DTileContentState.READY; + return this._contentState === Cesium3DTileContentState.READY; } }, @@ -441,7 +445,47 @@ define([ */ contentUnloaded : { get : function() { - return this._content.state === Cesium3DTileContentState.UNLOADED; + return this._contentState === Cesium3DTileContentState.UNLOADED; + } + }, + + /** + * Gets the promise that will be resolved when the tile's content is ready to process. + * This happens after the content is downloaded but before the content is ready + * to render. + *

+ * The promise remains undefined until the tile's content is requested. + *

+ * + * @type {Promise.} + * @readonly + * + * @private + */ + contentReadyToProcessPromise : { + get : function() { + if (defined(this._contentReadyToProcessPromise)) { + return this._contentReadyToProcessPromise.promise; + } + } + }, + + /** + * Gets the promise that will be resolved when the tile's content is ready to render. + *

+ * The promise remains undefined until the tile's content is requested. + *

+ * + * @type {Promise.} + * @readonly + * + * @private + */ + contentReadyPromise : { + get : function() { + if (defined(this._contentReadyPromise)) { + return this._contentReadyPromise.promise; + } } } }); @@ -455,7 +499,69 @@ define([ * @private */ Cesium3DTile.prototype.requestContent = function() { - this._content.request(); + var that = this; + + if (this.hasEmptyContent) { + return false; + } + + if (!this.canRequestContent()) { + return false; + } + + var distance = this.distanceToCamera; + var promise = RequestScheduler.schedule(new Request({ + url : this._contentUrl, + server : this._requestServer, + requestFunction : loadArrayBuffer, + type : RequestType.TILES3D, + distance : distance + })); + + if (!defined(promise)) { + return false; + } + + this._contentState = Cesium3DTileContentState.LOADING; + this._contentReadyToProcessPromise = when.defer(); + this._contentReadyPromise = when.defer(); + + promise.then(function(arrayBuffer) { + if (that.isDestroyed()) { + return when.reject('tileset is destroyed'); + } + var uint8Array = new Uint8Array(arrayBuffer); + var magic = getMagic(uint8Array); + var contentFactory = Cesium3DTileContentFactory[magic]; + var content; + + if (defined(contentFactory)) { + content = contentFactory(that._tileset, that, that._contentUrl, arrayBuffer, 0); + that.hasRenderableContent = true; + } else { + // The content may be json instead + content = Cesium3DTileContentFactory.json(that._tileset, that, that._contentUrl, arrayBuffer, 0); + that.hasTilesetContent = true; + } + + that._content = content; + that._contentState = Cesium3DTileContentState.PROCESSING; + that._contentReadyToProcessPromise.resolve(content); + + content.readyPromise.then(function(content) { + that._contentState = Cesium3DTileContentState.READY; + that._contentReadyPromise.resolve(content); + }).otherwise(function(error) { + that._contentState = Cesium3DTileContentState.FAILED; + that._contentReadyPromise.reject(error); + }); + }).otherwise(function(error) { + that._contentState = Cesium3DTileContentState.FAILED; + that._contentReadyPromise.reject(error); + that._contentReadyToProcessPromise.reject(error); + }); + + return true; }; /** @@ -481,8 +587,14 @@ define([ * @private */ Cesium3DTile.prototype.unloadContent = function() { + if (!this.hasRenderableContent) { + return; + } + this._content = this._content && this._content.destroy(); - this._content = this._createContent(); + this._contentState = Cesium3DTileContentState.UNLOADED; + this._contentReadyToProcessPromise = undefined; + this._contentReadyPromise = undefined; this.replacementNode = undefined; @@ -534,7 +646,7 @@ define([ * * @private */ - Cesium3DTile.prototype.contentsVisibility = function(frameState) { + Cesium3DTile.prototype.contentVisibility = function(frameState) { // Assumes the tile's bounding volume intersects the culling volume already, so // just return Intersect.INSIDE if there is no content bounding volume. if (!defined(this._contentBoundingVolume)) { diff --git a/Source/Scene/Cesium3DTileContent.js b/Source/Scene/Cesium3DTileContent.js index d5fe0bbdefc7..082040937664 100644 --- a/Source/Scene/Cesium3DTileContent.js +++ b/Source/Scene/Cesium3DTileContent.js @@ -26,22 +26,12 @@ define([ * @see Tileset3DTileContent * @see Empty3DTileContent */ - function Cesium3DTileContent(tileset, tile, url) { + function Cesium3DTileContent(tileset, tile, url, arrayBuffer, byteOffset) { // Private members are not exposed in the public Cesium API, but derived classes // need to implement them. The scope should be treated like C#'s internal. When // we're ready, we'll add these members to the public API so users can implement // new tile formats. - /** - * The current state of the tile's content. - * - * @type {Cesium3DTileContentState} - * @readonly - * - * @private - */ - this.state = undefined; - /** * Gets the batch table texture for this tile. * @@ -163,22 +153,6 @@ define([ } }, - /** - * Gets the promise that will be resolved when the tile's content is ready to process. - * This happens after the content is downloaded but before the content is ready - * to render. - * - * @type {Promise.} - * @readonly - * - * @private - */ - contentReadyToProcessPromise : { - get : function() { - DeveloperError.throwInstantiationError(); - } - }, - /** * Gets the promise that will be resolved when the tile's content is ready to render. * @@ -220,42 +194,6 @@ define([ DeveloperError.throwInstantiationError(); }; - /** - * Requests the tile's content. - *

- * The request may not be made if the Cesium Request Scheduler can't prioritize it. - *

- *

- * This is used to implement the Cesium3DTileContent interface, but is - * not part of the public Cesium API. - *

- * - * @returns {Boolean} Whether the request was initiated. May be false if the RequestScheduler is full. - * - * @private - */ - Cesium3DTileContent.prototype.request = function() { - DeveloperError.throwInstantiationError(); - }; - - /** - * Parses the tile's content's array buffer and initializes the content. This does not - * necessarily move the state to READY since WebGL resource creation may be - * amortized over several frames. - *

- * This is used to implement the Cesium3DTileContent interface, but is - * not part of the public Cesium API. - *

- * - * @param {Object} arrayBuffer The array buffer containing the contents payload. - * @param {Number} byteOffset The zero-based offset, in bytes, into the array buffer. - * - * @private - */ - Cesium3DTileContent.prototype.initialize = function(arrayBuffer, byteOffset) { - DeveloperError.throwInstantiationError(); - }; - /** * Called when {@link Cesium3DTileset#debugColorizeTiles} changes. *

diff --git a/Source/Scene/Cesium3DTileContentFactory.js b/Source/Scene/Cesium3DTileContentFactory.js index 4a1b14fad74e..b4e9471511e2 100644 --- a/Source/Scene/Cesium3DTileContentFactory.js +++ b/Source/Scene/Cesium3DTileContentFactory.js @@ -20,23 +20,23 @@ define([ * @private */ var Cesium3DTileContentFactory = { - b3dm : function(tileset, tile, url) { - return new Batched3DModel3DTileContent(tileset, tile, url); + b3dm : function(tileset, tile, url, arrayBuffer, byteOffset) { + return new Batched3DModel3DTileContent(tileset, tile, url, arrayBuffer, byteOffset); }, - pnts : function(tileset, tile, url) { - return new PointCloud3DTileContent(tileset, tile, url); + pnts : function(tileset, tile, url, arrayBuffer, byteOffset) { + return new PointCloud3DTileContent(tileset, tile, url, arrayBuffer, byteOffset); }, - i3dm : function(tileset, tile, url) { - return new Instanced3DModel3DTileContent(tileset, tile, url); + i3dm : function(tileset, tile, url, arrayBuffer, byteOffset) { + return new Instanced3DModel3DTileContent(tileset, tile, url, arrayBuffer, byteOffset); }, - cmpt : function(tileset, tile, url) { + cmpt : function(tileset, tile, url, arrayBuffer, byteOffset) { // Send in the factory in order to avoid a cyclical dependency - return new Composite3DTileContent(tileset, tile, url, Cesium3DTileContentFactory); + return new Composite3DTileContent(tileset, tile, url, arrayBuffer, byteOffset, Cesium3DTileContentFactory); }, - json : function(tileset, tile, url) { - return new Tileset3DTileContent(tileset, tile, url); + json : function(tileset, tile, url, arrayBuffer, byteOffset) { + return new Tileset3DTileContent(tileset, tile, url, arrayBuffer, byteOffset); } }; return Cesium3DTileContentFactory; -}); \ No newline at end of file +}); diff --git a/Source/Scene/Cesium3DTileset.js b/Source/Scene/Cesium3DTileset.js index 323d14d9145a..60e65fbfc3c7 100644 --- a/Source/Scene/Cesium3DTileset.js +++ b/Source/Scene/Cesium3DTileset.js @@ -500,14 +500,19 @@ define([ this._readyPromise = when.defer(); var that = this; - this.loadTileset(tilesetUrl).then(function(data) { - var tilesetJson = data.tilesetJson; + + // We don't know the distance of the tileset until tileset.json is loaded, so use the default distance for now + RequestScheduler.request(tilesetUrl, loadJson, undefined, RequestType.TILES3D).then(function(tilesetJson) { + if (that.isDestroyed()) { + return when.reject('tileset is destroyed'); + } + that._root = that.loadTileset(tilesetUrl, tilesetJson); + var gltfUpAxis = defined(tilesetJson.asset.gltfUpAxis) ? Axis.fromName(tilesetJson.asset.gltfUpAxis) : Axis.Y; that._asset = tilesetJson.asset; that._properties = tilesetJson.properties; that._geometricError = tilesetJson.geometricError; that._gltfUpAxis = gltfUpAxis; - that._root = data.root; that._readyPromise.resolve(that); }).otherwise(function(error) { that._readyPromise.reject(error); @@ -996,92 +1001,80 @@ define([ * * @private */ - Cesium3DTileset.prototype.loadTileset = function(tilesetUrl, parentTile) { - var that = this; - - // We don't know the distance of the tileset until tiles.json is loaded, so use the default distance for now - return RequestScheduler.request(tilesetUrl, loadJson, undefined, RequestType.TILES3D).then(function(tilesetJson) { - if (that.isDestroyed()) { - return when.reject('tileset is destroyed'); - } - - if (!defined(tilesetJson.asset) || (tilesetJson.asset.version !== '0.0')) { - throw new DeveloperError('The tileset must be 3D Tiles version 0.0. See https://github.com/AnalyticalGraphicsInc/3d-tiles#spec-status'); - } + Cesium3DTileset.prototype.loadTileset = function(tilesetUrl, tilesetJson, parentTile) { + if (!defined(tilesetJson.asset) || (tilesetJson.asset.version !== '0.0')) { + throw new DeveloperError('The tileset must be 3D Tiles version 0.0. See https://github.com/AnalyticalGraphicsInc/3d-tiles#spec-status'); + } - var stats = that._statistics; + var stats = this._statistics; - // Append the version to the baseUrl - var hasVersionQuery = /[?&]v=/.test(tilesetUrl); - if (!hasVersionQuery) { - var versionQuery = '?v=' + defaultValue(tilesetJson.asset.tilesetVersion, '0.0'); - that._baseUrl = joinUrls(that._baseUrl, versionQuery); - tilesetUrl = joinUrls(tilesetUrl, versionQuery, false); - } + // Append the version to the baseUrl + var hasVersionQuery = /[?&]v=/.test(tilesetUrl); + if (!hasVersionQuery) { + var versionQuery = '?v=' + defaultValue(tilesetJson.asset.tilesetVersion, '0.0'); + this._baseUrl = joinUrls(this._baseUrl, versionQuery); + tilesetUrl = joinUrls(tilesetUrl, versionQuery, false); + } - // A tileset.json referenced from a tile may exist in a different directory than the root tileset. - // Get the baseUrl relative to the external tileset. - var baseUrl = getBaseUri(tilesetUrl, true); - var rootTile = new Cesium3DTile(that, baseUrl, tilesetJson.root, parentTile); + // A tileset.json referenced from a tile may exist in a different directory than the root tileset. + // Get the baseUrl relative to the external tileset. + var baseUrl = getBaseUri(tilesetUrl, true); + var rootTile = new Cesium3DTile(this, baseUrl, tilesetJson.root, parentTile); - // If there is a parentTile, add the root of the currently loading tileset - // to parentTile's children, and update its _depth. - if (defined(parentTile)) { - parentTile.children.push(rootTile); - rootTile._depth = parentTile._depth + 1; - } + // If there is a parentTile, add the root of the currently loading tileset + // to parentTile's children, and update its _depth. + if (defined(parentTile)) { + parentTile.children.push(rootTile); + rootTile._depth = parentTile._depth + 1; + } - ++stats.numberTotal; + ++stats.numberTotal; - var stack = []; - stack.push({ - header : tilesetJson.root, - cesium3DTile : rootTile - }); + var stack = []; + stack.push({ + header : tilesetJson.root, + cesium3DTile : rootTile + }); - while (stack.length > 0) { - var tile = stack.pop(); - var tile3D = tile.cesium3DTile; - var children = tile.header.children; - if (defined(children)) { - var length = children.length; - for (var k = 0; k < length; ++k) { - var childHeader = children[k]; - var childTile = new Cesium3DTile(that, baseUrl, childHeader, tile3D); - tile3D.children.push(childTile); - childTile._depth = tile3D._depth + 1; - ++stats.numberTotal; - stack.push({ - header : childHeader, - cesium3DTile : childTile - }); - } + while (stack.length > 0) { + var tile = stack.pop(); + var tile3D = tile.cesium3DTile; + var children = tile.header.children; + if (defined(children)) { + var length = children.length; + for (var k = 0; k < length; ++k) { + var childHeader = children[k]; + var childTile = new Cesium3DTile(this, baseUrl, childHeader, tile3D); + tile3D.children.push(childTile); + childTile._depth = tile3D._depth + 1; + ++stats.numberTotal; + stack.push({ + header : childHeader, + cesium3DTile : childTile + }); } - Cesium3DTileOptimizations.checkChildrenWithinParent(tile3D, true); - - // Create a load heap, one for each unique server. We can only make limited requests to a given - // server so it is unnecessary to keep a queue of all tiles needed to be loaded. - // Instead of creating a list of all tiles to load and then sorting it entirely to find the best ones, - // we keep just a heap so we have the best `maximumRequestsPerServer` to load. The order of these does - // not matter much as we will try to load them all. - // The heap approach is a O(n log k) to find the best tiles for loading. - var requestServer = tile3D.requestServer; - if (defined(requestServer)) { - if (!defined(that._requestHeaps[requestServer])) { - var heap = new Heap(sortForLoad); - that._requestHeaps[requestServer] = heap; - heap.maximumSize = RequestScheduler.maximumRequestsPerServer; - heap.reserve(heap.maximumSize); - } - tile3D._requestHeap = that._requestHeaps[requestServer]; + } + Cesium3DTileOptimizations.checkChildrenWithinParent(tile3D, true); + + // Create a load heap, one for each unique server. We can only make limited requests to a given + // server so it is unnecessary to keep a queue of all tiles needed to be loaded. + // Instead of creating a list of all tiles to load and then sorting it entirely to find the best ones, + // we keep just a heap so we have the best `maximumRequestsPerServer` to load. The order of these does + // not matter much as we will try to load them all. + // The heap approach is a O(n log k) to find the best tiles for loading. + var requestServer = tile3D.requestServer; + if (defined(requestServer)) { + if (!defined(this._requestHeaps[requestServer])) { + var heap = new Heap(sortForLoad); + this._requestHeaps[requestServer] = heap; + heap.maximumSize = RequestScheduler.maximumRequestsPerServer; + heap.reserve(heap.maximumSize); } + tile3D._requestHeap = this._requestHeaps[requestServer]; } + } - return { - tilesetJson : tilesetJson, - root : rootTile - }; - }); + return rootTile; }; var scratchPositionNormal = new Cartesian3(); @@ -1237,23 +1230,25 @@ define([ if (!outOfCore) { return; } - if (!tile.canRequestContent()) { + + if (tile.hasEmptyContent) { return; } - tile.requestContent(); - var stats = tileset._statistics; - if (!tile.contentUnloaded) { - ++stats.numberOfPendingRequests; + var requested = tile.requestContent(); - var removeFunction = removeFromProcessingQueue(tileset, tile); - tile.content.contentReadyToProcessPromise.then(addToProcessingQueue(tileset, tile)).otherwise(removeFunction); - tile.content.readyPromise.then(removeFunction).otherwise(removeFunction); - } else { + if (!requested) { ++stats.numberOfAttemptedRequests; + return; } + + ++stats.numberOfPendingRequests; + + var removeFunction = removeFromProcessingQueue(tileset, tile); + tile.contentReadyToProcessPromise.then(addToProcessingQueue(tileset, tile)); + tile.contentReadyPromise.then(removeFunction).otherwise(removeFunction); } function selectTile(tileset, tile, frameState) { @@ -1261,7 +1256,7 @@ define([ // zoomed into a neighborhood and can cull the skyscrapers in the root node. if (tile.contentReady && ( (tile.visibilityPlaneMask === CullingVolume.MASK_INSIDE) || - (tile.contentsVisibility(frameState) !== Intersect.OUTSIDE) + (tile.contentVisibility(frameState) !== Intersect.OUTSIDE) )) { tileset._selectedTiles.push(tile); @@ -1338,8 +1333,8 @@ define([ var original = finalQueue.get(i); var tile = original; // traverse up the tree to find a ready ancestor - if (tile.hasContent || tile.hasTilesetContent) { // could be Empty3DTileContent - while (defined(tile) && !(tile.hasContent && tile.contentReady)) { + if (!tile.hasEmptyContent) { + while (defined(tile) && !(tile.hasRenderableContent && tile.contentReady)) { if (!tile.contentReady) { tileset._hasMixedContent = true; } @@ -1520,7 +1515,7 @@ define([ function selectionHeuristic(tileset, ancestor, tile) { var skipLevels = tileset.skipLODs ? tileset._skipLevels : 0; var skipSSEFactor = tileset.skipLODs ? tileset.skipSSEFactor : 0.1; - return (ancestor !== tile && tile.hasContent && !tileset.immediatelyLoadDesiredLOD) && + return (ancestor !== tile && tile.hasRenderableContent && !tileset.immediatelyLoadDesiredLOD) && (tile._sse < ancestor._sse / skipSSEFactor) && (tile._depth > ancestor._depth + skipLevels); } @@ -1605,12 +1600,7 @@ define([ var loadSiblings = tileset.loadSiblings; if (tile.hasTilesetContent) { - loadTile(tile); - if (!tile.contentReady) { - finalQueue.push(tile); - } else { - updateAndPushChildren(tileset, tile, frameState, stack, loadSiblings, outOfCore); - } + updateAndPushChildren(tileset, tile, frameState, stack, loadSiblings, outOfCore); } else { if (tile.refine === Cesium3DTileRefine.ADD) { loadAndAddToQueue(tileset, tile, finalQueue); @@ -1737,7 +1727,7 @@ define([ // Remove from processing queue tileset._processingQueue.splice(index, 1); --tileset._statistics.numberProcessing; - if (tile.hasContent) { + if (tile.hasRenderableContent) { // RESEARCH_IDEA: ability to unload tiles (without content) for an // external tileset when all the tiles are unloaded. ++tileset._statistics.numberContentReady; diff --git a/Source/Scene/Composite3DTileContent.js b/Source/Scene/Composite3DTileContent.js index 7bbc5d4b7350..3542dcde479a 100644 --- a/Source/Scene/Composite3DTileContent.js +++ b/Source/Scene/Composite3DTileContent.js @@ -37,21 +37,20 @@ define([ * * @private */ - function Composite3DTileContent(tileset, tile, url, factory) { + function Composite3DTileContent(tileset, tile, url, arrayBuffer, byteOffset, factory) { this._url = url; this._tileset = tileset; this._tile = tile; this._contents = []; - this._factory = factory; /** * The following properties are part of the {@link Cesium3DTileContent} interface. */ - this.state = Cesium3DTileContentState.UNLOADED; this.batchTable = undefined; - this._contentReadyToProcessPromise = when.defer(); this._readyPromise = when.defer(); + + initialize(this, arrayBuffer, byteOffset, factory); } defineProperties(Composite3DTileContent.prototype, { @@ -145,15 +144,6 @@ define([ } }, - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - contentReadyToProcessPromise : { - get : function() { - return this._contentReadyToProcessPromise.promise; - } - }, - /** * Part of the {@link Cesium3DTileContent} interface. */ @@ -182,53 +172,12 @@ define([ var sizeOfUint32 = Uint32Array.BYTES_PER_ELEMENT; - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - Composite3DTileContent.prototype.request = function() { - var that = this; - - var distance = this._tile.distanceToCamera; - var promise = RequestScheduler.schedule(new Request({ - url : this._url, - server : this._tile.requestServer, - requestFunction : loadArrayBuffer, - type : RequestType.TILES3D, - distance : distance - })); - - if (!defined(promise)) { - return false; - } - - this.state = Cesium3DTileContentState.LOADING; - promise.then(function(arrayBuffer) { - if (that.isDestroyed()) { - return when.reject('tileset is destroyed'); - } - that.initialize(arrayBuffer); - }).otherwise(function(error) { - that.state = Cesium3DTileContentState.FAILED; - that._readyPromise.reject(error); - }); - return true; - }; - - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - Composite3DTileContent.prototype.initialize = function(arrayBuffer, byteOffset) { + function initialize(content, arrayBuffer, byteOffset, factory) { byteOffset = defaultValue(byteOffset, 0); var uint8Array = new Uint8Array(arrayBuffer); - var magic = getMagic(uint8Array, byteOffset); - if (magic !== 'cmpt') { - throw new DeveloperError('Invalid Composite Tile. Expected magic=cmpt. Read magic=' + magic); - } - var view = new DataView(arrayBuffer); - - byteOffset += sizeOfUint32; // Skip magic number + byteOffset += sizeOfUint32; // Skip magic //>>includeStart('debug', pragmas.debug); var version = view.getUint32(byteOffset, true); @@ -244,9 +193,6 @@ define([ var tilesLength = view.getUint32(byteOffset, true); byteOffset += sizeOfUint32; - this.state = Cesium3DTileContentState.PROCESSING; - this._contentReadyToProcessPromise.resolve(this); - var contentPromises = []; for (var i = 0; i < tilesLength; ++i) { @@ -255,12 +201,11 @@ define([ // Tile byte length is stored after magic and version var tileByteLength = view.getUint32(byteOffset + sizeOfUint32 * 2, true); - var contentFactory = this._factory[tileType]; + var contentFactory = factory[tileType]; if (defined(contentFactory)) { - var content = contentFactory(this._tileset, this._tile, this._url); - content.initialize(arrayBuffer, byteOffset); - this._contents.push(content); + var innerContent = contentFactory(content._tileset, content._tile, content._url, arrayBuffer, byteOffset); + content._contents.push(innerContent); contentPromises.push(content.readyPromise); } else { throw new DeveloperError('Unknown tile content type, ' + tileType + ', inside Composite tile'); @@ -269,16 +214,12 @@ define([ byteOffset += tileByteLength; } - var that = this; - when.all(contentPromises).then(function() { - that.state = Cesium3DTileContentState.READY; - that._readyPromise.resolve(that); + content._readyPromise.resolve(content); }).otherwise(function(error) { - that.state = Cesium3DTileContentState.FAILED; - that._readyPromise.reject(error); + content._readyPromise.reject(error); }); - }; + } /** * Part of the {@link Cesium3DTileContent} interface. diff --git a/Source/Scene/Empty3DTileContent.js b/Source/Scene/Empty3DTileContent.js index 503577a7811c..350558131e02 100644 --- a/Source/Scene/Empty3DTileContent.js +++ b/Source/Scene/Empty3DTileContent.js @@ -1,14 +1,10 @@ /*global define*/ define([ '../Core/defineProperties', - '../Core/destroyObject', - '../ThirdParty/when', - './Cesium3DTileContentState' + '../Core/destroyObject' ], function( defineProperties, - destroyObject, - when, - Cesium3DTileContentState) { + destroyObject) { 'use strict'; /** @@ -25,20 +21,8 @@ define([ /** * The following properties are part of the {@link Cesium3DTileContent} interface. */ - this.state = undefined; this.batchTable = undefined; this.featurePropertiesDirty = false; - - this._contentReadyToProcessPromise = when.defer(); - this._readyPromise = when.defer(); - - // Transition into the PROCESSING state. - this.state = Cesium3DTileContentState.PROCESSING; - this._contentReadyToProcessPromise.resolve(this); - - // Transition into the READY state. - this.state = Cesium3DTileContentState.READY; - this._readyPromise.resolve(this); } defineProperties(Empty3DTileContent.prototype, { diff --git a/Source/Scene/Instanced3DModel3DTileContent.js b/Source/Scene/Instanced3DModel3DTileContent.js index 9e9c543b1373..f12a093106ce 100644 --- a/Source/Scene/Instanced3DModel3DTileContent.js +++ b/Source/Scene/Instanced3DModel3DTileContent.js @@ -13,23 +13,18 @@ define([ '../Core/Ellipsoid', '../Core/getAbsoluteUri', '../Core/getBaseUri', - '../Core/getMagic', '../Core/getStringFromTypedArray', '../Core/joinUrls', - '../Core/loadArrayBuffer', '../Core/Math', '../Core/Matrix3', '../Core/Matrix4', '../Core/Quaternion', - '../Core/Request', - '../Core/RequestScheduler', '../Core/RequestType', '../Core/Transforms', '../Core/TranslationRotationScale', '../ThirdParty/Uri', '../ThirdParty/when', './Cesium3DTileBatchTable', - './Cesium3DTileContentState', './Cesium3DTileFeature', './Cesium3DTileFeatureTable', './ModelInstanceCollection' @@ -47,23 +42,18 @@ define([ Ellipsoid, getAbsoluteUri, getBaseUri, - getMagic, getStringFromTypedArray, joinUrls, - loadArrayBuffer, CesiumMath, Matrix3, Matrix4, Quaternion, - Request, - RequestScheduler, RequestType, Transforms, TranslationRotationScale, Uri, when, Cesium3DTileBatchTable, - Cesium3DTileContentState, Cesium3DTileFeature, Cesium3DTileFeatureTable, ModelInstanceCollection) { @@ -79,7 +69,7 @@ define([ * * @private */ - function Instanced3DModel3DTileContent(tileset, tile, url) { + function Instanced3DModel3DTileContent(tileset, tile, url, arrayBuffer, byteOffset) { this._modelInstanceCollection = undefined; this._url = url; this._tileset = tileset; @@ -88,13 +78,12 @@ define([ /** * The following properties are part of the {@link Cesium3DTileContent} interface. */ - this.state = Cesium3DTileContentState.UNLOADED; this.batchTable = undefined; this.featurePropertiesDirty = false; - this._contentReadyToProcessPromise = when.defer(); - this._readyPromise = when.defer(); this._features = undefined; + + initialize(this, arrayBuffer, byteOffset); } defineProperties(Instanced3DModel3DTileContent.prototype, { @@ -103,11 +92,7 @@ define([ */ featuresLength : { get : function() { - if (defined(this._modelInstanceCollection)) { - return this._modelInstanceCollection.length; - } else { - return 0; - } + return this.batchTable.featuresLength; } }, @@ -125,9 +110,9 @@ define([ */ trianglesLength : { get : function() { - var collection = this._modelInstanceCollection; - if (defined(collection) && defined(collection._model)) { - return collection._model.trianglesLength; + var model = this._modelInstanceCollection._model; + if (defined(model)) { + return model.trianglesLength; } return 0; } @@ -138,9 +123,9 @@ define([ */ vertexMemorySizeInBytes : { get : function() { - var collection = this._modelInstanceCollection; - if (defined(collection) && defined(collection._model)) { - return collection._model.vertexMemorySizeInBytes; + var model = this._modelInstanceCollection._model; + if (defined(model)) { + return model.vertexMemorySizeInBytes; } return 0; } @@ -151,9 +136,9 @@ define([ */ textureMemorySizeInBytes : { get : function() { - var collection = this._modelInstanceCollection; - if (defined(collection) && defined(collection._model)) { - return collection._model.textureMemorySizeInBytes; + var model = this._modelInstanceCollection._model; + if (defined(model)) { + return model.textureMemorySizeInBytes; } return 0; } @@ -164,10 +149,7 @@ define([ */ batchTableMemorySizeInBytes : { get : function() { - if (defined(this.batchTable)) { - return this.batchTable.memorySizeInBytes; - } - return 0; + return this.batchTable.memorySizeInBytes; } }, @@ -180,21 +162,12 @@ define([ } }, - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - contentReadyToProcessPromise : { - get : function() { - return this._contentReadyToProcessPromise.promise; - } - }, - /** * Part of the {@link Cesium3DTileContent} interface. */ readyPromise : { get : function() { - return this._readyPromise.promise; + return this._modelInstanceCollection.readyPromise; } } }); @@ -235,55 +208,16 @@ define([ var sizeOfUint32 = Uint32Array.BYTES_PER_ELEMENT; - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - Instanced3DModel3DTileContent.prototype.request = function() { - var that = this; - var distance = this._tile.distanceToCamera; - var promise = RequestScheduler.schedule(new Request({ - url : this._url, - server : this._tile.requestServer, - requestFunction : loadArrayBuffer, - type : RequestType.TILES3D, - distance : distance - })); - - if (!defined(promise)) { - return false; - } - - this.state = Cesium3DTileContentState.LOADING; - promise.then(function(arrayBuffer) { - if (that.isDestroyed()) { - return when.reject('tileset is destroyed'); - } - that.initialize(arrayBuffer); - }).otherwise(function(error) { - that.state = Cesium3DTileContentState.FAILED; - that._readyPromise.reject(error); - }); - return true; - }; - - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - Instanced3DModel3DTileContent.prototype.initialize = function(arrayBuffer, byteOffset) { + function initialize(content, arrayBuffer, byteOffset) { var byteStart = defaultValue(byteOffset, 0); byteOffset = defaultValue(byteOffset, 0); var uint8Array = new Uint8Array(arrayBuffer); - var magic = getMagic(uint8Array, byteOffset); - if (magic !== 'i3dm') { - throw new DeveloperError('Invalid Instanced 3D Model. Expected magic=i3dm. Read magic=' + magic); - } - var view = new DataView(arrayBuffer); - byteOffset += sizeOfUint32; // Skip magic number + byteOffset += sizeOfUint32; // Skip magic - var version = view.getUint32(byteOffset, true); //>>includeStart('debug', pragmas.debug); + var version = view.getUint32(byteOffset, true); if (version !== 1) { throw new DeveloperError('Only Instanced 3D Model version 1 is supported. Version ' + version + ' is not.'); } @@ -351,7 +285,7 @@ define([ } } - this.batchTable = new Cesium3DTileBatchTable(this, instancesLength, batchTableJson, batchTableBinary); + content.batchTable = new Cesium3DTileBatchTable(content, instancesLength, batchTableJson, batchTableBinary); var gltfByteLength = byteStart + byteLength - byteOffset; //>>includeStart('debug', pragmas.debug); @@ -365,22 +299,22 @@ define([ // Create model instance collection var collectionOptions = { instances : new Array(instancesLength), - batchTable : this.batchTable, + batchTable : content.batchTable, cull : false, // Already culled by 3D Tiles url : undefined, requestType : RequestType.TILES3D, gltf : undefined, basePath : undefined, incrementallyLoadTextures : false, - upAxis : this._tileset._gltfUpAxis + upAxis : content._tileset._gltfUpAxis }; if (gltfFormat === 0) { var gltfUrl = getStringFromTypedArray(gltfView); - collectionOptions.url = getAbsoluteUri(joinUrls(getBaseUri(this._url, true), gltfUrl)); + collectionOptions.url = getAbsoluteUri(joinUrls(getBaseUri(content._url, true), gltfUrl)); } else { collectionOptions.gltf = gltfView; - collectionOptions.basePath = getBaseUri(this._url, true); + collectionOptions.basePath = getAbsoluteUri(getBaseUri(content._url, true)); } var eastNorthUp = featureTable.getGlobalProperty('EAST_NORTH_UP'); @@ -513,21 +447,8 @@ define([ }; } - var modelInstanceCollection = new ModelInstanceCollection(collectionOptions); - this._modelInstanceCollection = modelInstanceCollection; - this.state = Cesium3DTileContentState.PROCESSING; - this._contentReadyToProcessPromise.resolve(this); - - var that = this; - - modelInstanceCollection.readyPromise.then(function(modelInstanceCollection) { - that.state = Cesium3DTileContentState.READY; - that._readyPromise.resolve(that); - }).otherwise(function(error) { - that.state = Cesium3DTileContentState.FAILED; - that._readyPromise.reject(error); - }); - }; + content._modelInstanceCollection = new ModelInstanceCollection(collectionOptions); + } /** * Part of the {@link Cesium3DTileContent} interface. diff --git a/Source/Scene/PointCloud3DTileContent.js b/Source/Scene/PointCloud3DTileContent.js index 07034d7618d7..c640c3978f8f 100644 --- a/Source/Scene/PointCloud3DTileContent.js +++ b/Source/Scene/PointCloud3DTileContent.js @@ -10,16 +10,11 @@ define([ '../Core/defineProperties', '../Core/destroyObject', '../Core/DeveloperError', - '../Core/getMagic', '../Core/getStringFromTypedArray', - '../Core/loadArrayBuffer', '../Core/Matrix3', '../Core/Matrix4', '../Core/oneTimeWarning', '../Core/PrimitiveType', - '../Core/Request', - '../Core/RequestScheduler', - '../Core/RequestType', '../Core/Transforms', '../Core/WebGLConstants', '../Renderer/Buffer', @@ -34,7 +29,6 @@ define([ './BlendingState', './Cesium3DTileBatchTable', './Cesium3DTileColorBlendMode', - './Cesium3DTileContentState', './Cesium3DTileFeature', './Cesium3DTileFeatureTable', './SceneMode' @@ -49,16 +43,11 @@ define([ defineProperties, destroyObject, DeveloperError, - getMagic, getStringFromTypedArray, - loadArrayBuffer, Matrix3, Matrix4, oneTimeWarning, PrimitiveType, - Request, - RequestScheduler, - RequestType, Transforms, WebGLConstants, Buffer, @@ -73,7 +62,6 @@ define([ BlendingState, Cesium3DTileBatchTable, Cesium3DTileColorBlendMode, - Cesium3DTileContentState, Cesium3DTileFeature, Cesium3DTileFeatureTable, SceneMode) { @@ -89,7 +77,7 @@ define([ * * @private */ - function PointCloud3DTileContent(tileset, tile, url) { + function PointCloud3DTileContent(tileset, tile, url, arrayBuffer, byteOffset) { this._url = url; this._tileset = tileset; this._tile = tile; @@ -132,15 +120,15 @@ define([ /** * The following properties are part of the {@link Cesium3DTileContent} interface. */ - this.state = Cesium3DTileContentState.UNLOADED; this.batchTable = undefined; this.featurePropertiesDirty = false; - this._contentReadyToProcessPromise = when.defer(); this._readyPromise = when.defer(); this._features = undefined; this._pointsLength = 0; this._vertexMemorySizeInBytes = 0; + + initialize(this, arrayBuffer, byteOffset); } defineProperties(PointCloud3DTileContent.prototype, { @@ -213,15 +201,6 @@ define([ } }, - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - contentReadyToProcessPromise : { - get : function() { - return this._contentReadyToProcessPromise.promise; - } - }, - /** * Part of the {@link Cesium3DTileContent} interface. */ @@ -282,52 +261,12 @@ define([ var sizeOfUint32 = Uint32Array.BYTES_PER_ELEMENT; - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - PointCloud3DTileContent.prototype.request = function() { - var that = this; - - var distance = this._tile.distanceToCamera; - var promise = RequestScheduler.schedule(new Request({ - url : this._url, - server : this._tile.requestServer, - requestFunction : loadArrayBuffer, - type : RequestType.TILES3D, - distance : distance - })); - - if (!defined(promise)) { - return false; - } - - this.state = Cesium3DTileContentState.LOADING; - promise.then(function(arrayBuffer) { - if (that.isDestroyed()) { - return when.reject('tileset is destroyed'); - } - that.initialize(arrayBuffer); - }).otherwise(function(error) { - that.state = Cesium3DTileContentState.FAILED; - that._readyPromise.reject(error); - }); - return true; - }; - - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - PointCloud3DTileContent.prototype.initialize = function(arrayBuffer, byteOffset) { + function initialize(content, arrayBuffer, byteOffset) { byteOffset = defaultValue(byteOffset, 0); var uint8Array = new Uint8Array(arrayBuffer); - var magic = getMagic(uint8Array, byteOffset); - if (magic !== 'pnts') { - throw new DeveloperError('Invalid Points tile. Expected magic=pnts. Read magic=' + magic); - } - var view = new DataView(arrayBuffer); - byteOffset += sizeOfUint32; // Skip magic number + byteOffset += sizeOfUint32; // Skip magic //>>includeStart('debug', pragmas.debug); var version = view.getUint32(byteOffset, true); @@ -398,7 +337,7 @@ define([ positions = featureTable.getPropertyArray('POSITION', ComponentDatatype.FLOAT, 3); var rtcCenter = featureTable.getGlobalProperty('RTC_CENTER'); if (defined(rtcCenter)) { - this._rtcCenter = Cartesian3.unpack(rtcCenter); + content._rtcCenter = Cartesian3.unpack(rtcCenter); } } else if (defined(featureTableJson.POSITION_QUANTIZED)) { positions = featureTable.getPropertyArray('POSITION_QUANTIZED', ComponentDatatype.UNSIGNED_SHORT, 3); @@ -410,7 +349,7 @@ define([ throw new DeveloperError('Global property: QUANTIZED_VOLUME_SCALE must be defined for quantized positions.'); } //>>includeEnd('debug'); - this._quantizedVolumeScale = Cartesian3.unpack(quantizedVolumeScale); + content._quantizedVolumeScale = Cartesian3.unpack(quantizedVolumeScale); var quantizedVolumeOffset = featureTable.getGlobalProperty('QUANTIZED_VOLUME_OFFSET'); //>>includeStart('debug', pragmas.debug); @@ -418,7 +357,7 @@ define([ throw new DeveloperError('Global property: QUANTIZED_VOLUME_OFFSET must be defined for quantized positions.'); } //>>includeEnd('debug'); - this._quantizedVolumeOffset = Cartesian3.unpack(quantizedVolumeOffset); + content._quantizedVolumeOffset = Cartesian3.unpack(quantizedVolumeOffset); } //>>includeStart('debug', pragmas.debug); @@ -442,13 +381,13 @@ define([ isRGB565 = true; } else if (defined(featureTableJson.CONSTANT_RGBA)) { var constantRGBA = featureTable.getGlobalProperty('CONSTANT_RGBA'); - this._constantColor = Color.fromBytes(constantRGBA[0], constantRGBA[1], constantRGBA[2], constantRGBA[3], this._constantColor); + content._constantColor = Color.fromBytes(constantRGBA[0], constantRGBA[1], constantRGBA[2], constantRGBA[3], content._constantColor); } else { // Use a default constant color - this._constantColor = Color.clone(Color.DARKGRAY, this._constantColor); + content._constantColor = Color.clone(Color.DARKGRAY, content._constantColor); } - this._isTranslucent = isTranslucent; + content._isTranslucent = isTranslucent; // Get the normals var normals; @@ -486,7 +425,7 @@ define([ // Copy the batchTableBinary section and let the underlying ArrayBuffer be freed batchTableBinary = new Uint8Array(batchTableBinary); } - this.batchTable = new Cesium3DTileBatchTable(this, batchLength, batchTableJson, batchTableBinary); + content.batchTable = new Cesium3DTileBatchTable(content, batchLength, batchTableJson, batchTableBinary); } // If points are not batched and there are per-point properties, use these properties for styling purposes @@ -508,25 +447,22 @@ define([ } } - this._parsedContent = { + content._parsedContent = { positions : positions, colors : colors, normals : normals, batchIds : batchIds, styleableProperties : styleableProperties }; - this._pointsLength = pointsLength; - - this._isQuantized = isQuantized; - this._isOctEncoded16P = isOctEncoded16P; - this._isRGB565 = isRGB565; - this._hasColors = defined(colors); - this._hasNormals = defined(normals); - this._hasBatchIds = defined(batchIds); - - this.state = Cesium3DTileContentState.PROCESSING; - this._contentReadyToProcessPromise.resolve(this); - }; + content._pointsLength = pointsLength; + + content._isQuantized = isQuantized; + content._isOctEncoded16P = isOctEncoded16P; + content._isRGB565 = isRGB565; + content._hasColors = defined(colors); + content._hasNormals = defined(normals); + content._hasBatchIds = defined(batchIds); + } var positionLocation = 0; var colorLocation = 1; @@ -1210,8 +1146,6 @@ define([ createShaders(this, frameState, tileset.style); updateModelMatrix = true; - // Set state to ready - this.state = Cesium3DTileContentState.READY; this._readyPromise.resolve(this); this._parsedContent = undefined; // Unload } diff --git a/Source/Scene/Tileset3DTileContent.js b/Source/Scene/Tileset3DTileContent.js index 4110b9cf525a..d401d2162fbf 100644 --- a/Source/Scene/Tileset3DTileContent.js +++ b/Source/Scene/Tileset3DTileContent.js @@ -1,16 +1,20 @@ /*global define*/ define([ + '../Core/defaultValue', '../Core/defined', '../Core/defineProperties', '../Core/destroyObject', - '../ThirdParty/when', - './Cesium3DTileContentState' + '../Core/DeveloperError', + '../Core/getStringFromTypedArray', + '../ThirdParty/when' ], function( + defaultValue, defined, defineProperties, destroyObject, - when, - Cesium3DTileContentState) { + DeveloperError, + getStringFromTypedArray, + when) { 'use strict'; /** @@ -23,7 +27,7 @@ define([ * * @private */ - function Tileset3DTileContent(tileset, tile, url) { + function Tileset3DTileContent(tileset, tile, url, arrayBuffer, byteOffset) { this._tileset = tileset; this._tile = tile; this._url = url; @@ -31,12 +35,12 @@ define([ /** * The following properties are part of the {@link Cesium3DTileContent} interface. */ - this.state = Cesium3DTileContentState.UNLOADED; this.batchTable = undefined; this.featurePropertiesDirty = false; - this._contentReadyToProcessPromise = when.defer(); this._readyPromise = when.defer(); + + initialize(this, arrayBuffer, byteOffset); } defineProperties(Tileset3DTileContent.prototype, { @@ -103,15 +107,6 @@ define([ } }, - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - contentReadyToProcessPromise : { - get : function() { - return this._contentReadyToProcessPromise.promise; - } - }, - /** * Part of the {@link Cesium3DTileContent} interface. */ @@ -122,6 +117,22 @@ define([ } }); + function initialize(content, arrayBuffer, byteOffset) { + byteOffset = defaultValue(byteOffset, 0); + var uint8Array = new Uint8Array(arrayBuffer); + var jsonString = getStringFromTypedArray(uint8Array, byteOffset); + var tilesetJson; + + try { + tilesetJson = JSON.parse(jsonString); + } catch (error) { + content._readyPromise.reject(new DeveloperError('Invalid json content')); + } + + content._tileset.loadTileset(content._url, tilesetJson, content._tile); + content._readyPromise.resolve(content); + } + /** * Part of the {@link Cesium3DTileContent} interface. Tileset3DTileContent * always returns false since a tile of this type does not have any features. @@ -138,31 +149,6 @@ define([ return undefined; }; - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - Tileset3DTileContent.prototype.request = function() { - var that = this; - - this.state = Cesium3DTileContentState.LOADING; - this._tileset.loadTileset(this._url, this._tile).then(function() { - that.state = Cesium3DTileContentState.PROCESSING; - that._contentReadyToProcessPromise.resolve(that); - that.state = Cesium3DTileContentState.READY; - that._readyPromise.resolve(that); - }).otherwise(function(error) { - that.state = Cesium3DTileContentState.FAILED; - that._readyPromise.reject(error); - }); - return true; - }; - - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - Tileset3DTileContent.prototype.initialize = function(arrayBuffer, byteOffset) { - }; - /** * Part of the {@link Cesium3DTileContent} interface. */ diff --git a/Specs/Scene/Cesium3DTilesetSpec.js b/Specs/Scene/Cesium3DTilesetSpec.js index 9bc1ae00271f..53b86e4a07d8 100644 --- a/Specs/Scene/Cesium3DTilesetSpec.js +++ b/Specs/Scene/Cesium3DTilesetSpec.js @@ -271,7 +271,6 @@ defineSuite([ expect(tileset._geometricError).toEqual(240.0); expect(tileset._root).toBeDefined(); - expect(tileset._root.descendantsWithContent).toBeUndefined(); expect(tileset.url).toEqual(tilesetUrl); }); });