mirror of https://github.com/CesiumGS/cesium.git
Compare commits
13 Commits
72d166e961
...
b4ee10c6df
| Author | SHA1 | Date |
|---|---|---|
|
|
b4ee10c6df | |
|
|
ee2b3813b2 | |
|
|
4e3980cc53 | |
|
|
48bbf6fd4f | |
|
|
59b9f79c4a | |
|
|
6a07d54781 | |
|
|
e2024b33bb | |
|
|
165d426689 | |
|
|
0daebfe832 | |
|
|
9bd92a616f | |
|
|
df75727e02 | |
|
|
f79f19f6fc | |
|
|
9311afbe3d |
|
|
@ -7,7 +7,8 @@
|
|||
#### Fixes :wrench:
|
||||
|
||||
- Billboards using `imageSubRegion` now render as expected. [#12585](https://github.com/CesiumGS/cesium/issues/12585)
|
||||
- Improved scaling of SVGs in billboards [#TODO](https://github.com/CesiumGS/cesium/issues/TODO)
|
||||
- Improved scaling of SVGs in billboards [#13020](https://github.com/CesiumGS/cesium/issues/13020)
|
||||
- Fixed unexpected outline artifacts around billboards [#13038](https://github.com/CesiumGS/cesium/issues/13038)
|
||||
|
||||
#### Additions :tada:
|
||||
|
||||
|
|
|
|||
|
|
@ -790,7 +790,17 @@ Resource.prototype.appendForwardSlash = function () {
|
|||
* @returns {Promise<ArrayBuffer>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if <code>request.throttle</code> is true and the request does not have high enough priority.
|
||||
*
|
||||
* @example
|
||||
* // load a single URL asynchronously
|
||||
* // load a single URL asynchronously.
|
||||
* // Note that fetchArrayBuffer may return 'undefined', and this will cause
|
||||
* // an error here. There is no way to know when it will return 'undefined'
|
||||
* // or an actual promise. If it returns 'undefined', it is necessary to
|
||||
* // call it again, until it returns the actual promise. But it may not be
|
||||
* // called again after it returned a promise, because then there will be
|
||||
* // multiple promises. Also note that the returned promise may be
|
||||
* // rejected and receive 'undefined' as the error, so it's impossible to
|
||||
* // know WHY it was rejected. So you can either ignore that, or just try
|
||||
* // it again, hoping that it will not be rejected next time.
|
||||
* // If you are reading this: GOOD LUCK!
|
||||
* resource.fetchArrayBuffer().then(function(arrayBuffer) {
|
||||
* // use the data
|
||||
* }).catch(function(error) {
|
||||
|
|
|
|||
|
|
@ -122,6 +122,8 @@ TexturePacker.prototype._findNode = function (node, { width, height }) {
|
|||
return node;
|
||||
}
|
||||
|
||||
const borderPadding = this._borderPadding;
|
||||
|
||||
// Vertical split (childNode1 = left half, childNode2 = right half).
|
||||
if (widthDifference > heightDifference) {
|
||||
node.childNode1 = new TextureNode({
|
||||
|
|
@ -130,12 +132,18 @@ TexturePacker.prototype._findNode = function (node, { width, height }) {
|
|||
width,
|
||||
height: nodeHeight,
|
||||
});
|
||||
|
||||
// Apply padding only along the vertical "cut".
|
||||
const widthDifferencePadded = widthDifference - borderPadding;
|
||||
|
||||
if (widthDifferencePadded > 0) {
|
||||
node.childNode2 = new TextureNode({
|
||||
x: rectangle.x + width,
|
||||
x: rectangle.x + width + borderPadding,
|
||||
y: rectangle.y,
|
||||
width: widthDifference,
|
||||
width: widthDifferencePadded,
|
||||
height: nodeHeight,
|
||||
});
|
||||
}
|
||||
|
||||
return this._findNode(node.childNode1, { width, height });
|
||||
}
|
||||
|
|
@ -147,12 +155,19 @@ TexturePacker.prototype._findNode = function (node, { width, height }) {
|
|||
width: nodeWidth,
|
||||
height,
|
||||
});
|
||||
|
||||
// Apply padding only along the horizontal "cut".
|
||||
const heightDifferencePadded = heightDifference - borderPadding;
|
||||
|
||||
if (heightDifferencePadded > 0) {
|
||||
node.childNode2 = new TextureNode({
|
||||
x: rectangle.x,
|
||||
y: rectangle.y + height,
|
||||
y: rectangle.y + height + borderPadding,
|
||||
width: nodeWidth,
|
||||
height: heightDifference,
|
||||
height: heightDifferencePadded,
|
||||
});
|
||||
}
|
||||
|
||||
return this._findNode(node.childNode1, { width, height });
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,16 +21,12 @@ import RequestState from "../Core/RequestState.js";
|
|||
import RequestType from "../Core/RequestType.js";
|
||||
import Resource from "../Core/Resource.js";
|
||||
import RuntimeError from "../Core/RuntimeError.js";
|
||||
import Cesium3DContentGroup from "./Cesium3DContentGroup.js";
|
||||
import Cesium3DTileContentFactory from "./Cesium3DTileContentFactory.js";
|
||||
import Cesium3DTileContentState from "./Cesium3DTileContentState.js";
|
||||
import Cesium3DTileContentType from "./Cesium3DTileContentType.js";
|
||||
import Cesium3DTileOptimizationHint from "./Cesium3DTileOptimizationHint.js";
|
||||
import Cesium3DTilePass from "./Cesium3DTilePass.js";
|
||||
import Cesium3DTileRefine from "./Cesium3DTileRefine.js";
|
||||
import Empty3DTileContent from "./Empty3DTileContent.js";
|
||||
import findContentMetadata from "./findContentMetadata.js";
|
||||
import findGroupMetadata from "./findGroupMetadata.js";
|
||||
import findTileMetadata from "./findTileMetadata.js";
|
||||
import hasExtension from "./hasExtension.js";
|
||||
import Multiple3DTileContent from "./Multiple3DTileContent.js";
|
||||
|
|
@ -43,6 +39,8 @@ import TileBoundingSphere from "./TileBoundingSphere.js";
|
|||
import TileOrientedBoundingBox from "./TileOrientedBoundingBox.js";
|
||||
import Pass from "../Renderer/Pass.js";
|
||||
import VerticalExaggeration from "../Core/VerticalExaggeration.js";
|
||||
import finishContent from "./finishContent.js";
|
||||
import Dynamic3DTileContent from "./Dynamic3DTileContent.js";
|
||||
|
||||
/**
|
||||
* A tile in a {@link Cesium3DTileset}. When a tile is first created, its content is not loaded;
|
||||
|
|
@ -62,19 +60,6 @@ function Cesium3DTile(tileset, baseResource, header, parent) {
|
|||
this._tileset = tileset;
|
||||
this._header = header;
|
||||
|
||||
const hasContentsArray = defined(header.contents);
|
||||
const hasMultipleContents =
|
||||
(hasContentsArray && header.contents.length > 1) ||
|
||||
hasExtension(header, "3DTILES_multiple_contents");
|
||||
|
||||
// In the 1.0 schema, content is stored in tile.content instead of tile.contents
|
||||
const contentHeader =
|
||||
hasContentsArray && !hasMultipleContents
|
||||
? header.contents[0]
|
||||
: header.content;
|
||||
|
||||
this._contentHeader = contentHeader;
|
||||
|
||||
/**
|
||||
* The local transform of this tile.
|
||||
* @type {Matrix4}
|
||||
|
|
@ -131,22 +116,6 @@ function Cesium3DTile(tileset, baseResource, header, parent) {
|
|||
);
|
||||
this._boundingVolume2D = undefined;
|
||||
|
||||
let contentBoundingVolume;
|
||||
|
||||
if (defined(contentHeader) && defined(contentHeader.boundingVolume)) {
|
||||
// Non-leaf tiles may have a content bounding-volume, which is a tight-fit bounding volume
|
||||
// around only the features in the tile. This box is useful for culling for rendering,
|
||||
// but not for culling for traversing the tree since it does not guarantee spatial coherence, i.e.,
|
||||
// since it only bounds features in the tile, not the entire tile, children may be
|
||||
// outside of this box.
|
||||
contentBoundingVolume = this.createBoundingVolume(
|
||||
contentHeader.boundingVolume,
|
||||
computedTransform,
|
||||
);
|
||||
}
|
||||
this._contentBoundingVolume = contentBoundingVolume;
|
||||
this._contentBoundingVolume2D = undefined;
|
||||
|
||||
let viewerRequestVolume;
|
||||
if (defined(header.viewerRequestVolume)) {
|
||||
viewerRequestVolume = this.createBoundingVolume(
|
||||
|
|
@ -178,27 +147,6 @@ function Cesium3DTile(tileset, baseResource, header, parent) {
|
|||
|
||||
this.updateGeometricErrorScale();
|
||||
|
||||
let refine;
|
||||
if (defined(header.refine)) {
|
||||
if (header.refine === "replace" || header.refine === "add") {
|
||||
Cesium3DTile._deprecationWarning(
|
||||
"lowercase-refine",
|
||||
`This tile uses a lowercase refine "${
|
||||
header.refine
|
||||
}". Instead use "${header.refine.toUpperCase()}".`,
|
||||
);
|
||||
}
|
||||
refine =
|
||||
header.refine.toUpperCase() === "REPLACE"
|
||||
? Cesium3DTileRefine.REPLACE
|
||||
: Cesium3DTileRefine.ADD;
|
||||
} else if (defined(parent)) {
|
||||
// Inherit from parent tile if omitted.
|
||||
refine = parent.refine;
|
||||
} else {
|
||||
refine = Cesium3DTileRefine.REPLACE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the type of refinement that is used when traversing this tile for rendering.
|
||||
*
|
||||
|
|
@ -206,7 +154,7 @@ function Cesium3DTile(tileset, baseResource, header, parent) {
|
|||
* @readonly
|
||||
* @private
|
||||
*/
|
||||
this.refine = refine;
|
||||
this.refine = determineRefine(header.refine, parent);
|
||||
|
||||
/**
|
||||
* Gets the tile's children.
|
||||
|
|
@ -229,58 +177,6 @@ function Cesium3DTile(tileset, baseResource, header, parent) {
|
|||
*/
|
||||
this.parent = parent;
|
||||
|
||||
let content;
|
||||
let hasEmptyContent = false;
|
||||
let contentState;
|
||||
let contentResource;
|
||||
let serverKey;
|
||||
|
||||
baseResource = Resource.createIfNeeded(baseResource);
|
||||
|
||||
if (hasMultipleContents) {
|
||||
contentState = Cesium3DTileContentState.UNLOADED;
|
||||
// Each content may have its own URI, but they all need to be resolved
|
||||
// relative to the tileset, so the base resource is used.
|
||||
contentResource = baseResource.clone();
|
||||
} else if (defined(contentHeader)) {
|
||||
let contentHeaderUri = contentHeader.uri;
|
||||
if (defined(contentHeader.url)) {
|
||||
Cesium3DTile._deprecationWarning(
|
||||
"contentUrl",
|
||||
'This tileset JSON uses the "content.url" property which has been deprecated. Use "content.uri" instead.',
|
||||
);
|
||||
contentHeaderUri = contentHeader.url;
|
||||
}
|
||||
if (contentHeaderUri === "") {
|
||||
Cesium3DTile._deprecationWarning(
|
||||
"contentUriEmpty",
|
||||
"content.uri property is an empty string, which creates a circular dependency, making this tileset invalid. Omit the content property instead",
|
||||
);
|
||||
content = new Empty3DTileContent(tileset, this);
|
||||
hasEmptyContent = true;
|
||||
contentState = Cesium3DTileContentState.READY;
|
||||
} else {
|
||||
contentState = Cesium3DTileContentState.UNLOADED;
|
||||
contentResource = baseResource.getDerivedResource({
|
||||
url: contentHeaderUri,
|
||||
});
|
||||
serverKey = RequestScheduler.getServerKey(
|
||||
contentResource.getUrlComponent(),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
content = new Empty3DTileContent(tileset, this);
|
||||
hasEmptyContent = true;
|
||||
contentState = Cesium3DTileContentState.READY;
|
||||
}
|
||||
|
||||
this._content = content;
|
||||
this._contentResource = contentResource;
|
||||
this._contentState = contentState;
|
||||
this._expiredContent = undefined;
|
||||
|
||||
this._serverKey = serverKey;
|
||||
|
||||
/**
|
||||
* When <code>true</code>, the tile has no content.
|
||||
*
|
||||
|
|
@ -289,7 +185,7 @@ function Cesium3DTile(tileset, baseResource, header, parent) {
|
|||
*
|
||||
* @private
|
||||
*/
|
||||
this.hasEmptyContent = hasEmptyContent;
|
||||
this.hasEmptyContent = false;
|
||||
|
||||
/**
|
||||
* When <code>true</code>, the tile's content points to an external tileset.
|
||||
|
|
@ -334,7 +230,7 @@ function Cesium3DTile(tileset, baseResource, header, parent) {
|
|||
*
|
||||
* @private
|
||||
*/
|
||||
this.hasRenderableContent = !hasEmptyContent;
|
||||
this.hasRenderableContent = false;
|
||||
|
||||
/**
|
||||
* When <code>true</code>, the tile contains content metadata from implicit tiling. This flag is set
|
||||
|
|
@ -362,7 +258,17 @@ function Cesium3DTile(tileset, baseResource, header, parent) {
|
|||
*
|
||||
* @private
|
||||
*/
|
||||
this.hasMultipleContents = hasMultipleContents;
|
||||
this.hasMultipleContents = false;
|
||||
|
||||
// Initialize the content-related properties
|
||||
this._contentBoundingVolume = undefined;
|
||||
this._contentBoundingVolume2D = undefined;
|
||||
this._content = undefined;
|
||||
this._contentResource = undefined;
|
||||
this._contentState = undefined;
|
||||
this._expiredContent = undefined;
|
||||
this._serverKey = undefined;
|
||||
initializeContent(this, baseResource, header);
|
||||
|
||||
/**
|
||||
* The node in the tileset's LRU cache, used to determine when to unload a tile's content.
|
||||
|
|
@ -483,7 +389,7 @@ function Cesium3DTile(tileset, baseResource, header, parent) {
|
|||
*/
|
||||
this.implicitSubtree = undefined;
|
||||
|
||||
// Members that are updated every frame for tree traversal and rendering optimizations:
|
||||
// Members that are updated every frame for tree traversal and rendering optimizations.
|
||||
this._distanceToCamera = 0.0;
|
||||
this._centerZDepth = 0.0;
|
||||
this._screenSpaceError = 0.0;
|
||||
|
|
@ -535,6 +441,161 @@ function Cesium3DTile(tileset, baseResource, header, parent) {
|
|||
this._request = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the content-related properties of the given tile.
|
||||
*
|
||||
* This assumes that the <code>_tileset</code> and the
|
||||
* <code>computedTransform</code> of the given tile have
|
||||
* already been set.
|
||||
*
|
||||
* It will initialize the following properties of the tile, based
|
||||
* on the given resource and header information:
|
||||
*
|
||||
* - _contentHeader
|
||||
* - _contentBoundingVolume
|
||||
* - _contentBoundingVolume2D
|
||||
* - _content
|
||||
* - _contentResource
|
||||
* - _contentState
|
||||
* - _expiredContent
|
||||
* - _serverKey
|
||||
* - hasEmptyContent
|
||||
* - hasRenderableContent
|
||||
* - hasMultipleContents
|
||||
*
|
||||
* The exact meaning of these properties has to be derived from
|
||||
* the code. This function was just introduced as first cleanup.
|
||||
*
|
||||
* @param {Cesium3DTile} tile The tile
|
||||
* @param {Resource} baseResource The base resource for the tileset
|
||||
* @param {object} header The JSON header for the tile
|
||||
*/
|
||||
function initializeContent(tile, baseResource, header) {
|
||||
const hasContentsArray = defined(header.contents);
|
||||
const hasMultipleContents =
|
||||
(hasContentsArray && header.contents.length > 1) ||
|
||||
hasExtension(header, "3DTILES_multiple_contents");
|
||||
|
||||
// In the 1.0 schema, content is stored in tile.content instead of tile.contents
|
||||
const contentHeader =
|
||||
hasContentsArray && !hasMultipleContents
|
||||
? header.contents[0]
|
||||
: header.content;
|
||||
|
||||
let contentBoundingVolume;
|
||||
|
||||
if (defined(contentHeader) && defined(contentHeader.boundingVolume)) {
|
||||
// Non-leaf tiles may have a content bounding-volume, which is a tight-fit bounding volume
|
||||
// around only the features in the tile. This box is useful for culling for rendering,
|
||||
// but not for culling for traversing the tree since it does not guarantee spatial coherence, i.e.,
|
||||
// since it only bounds features in the tile, not the entire tile, children may be
|
||||
// outside of this box.
|
||||
contentBoundingVolume = tile.createBoundingVolume(
|
||||
contentHeader.boundingVolume,
|
||||
tile.computedTransform,
|
||||
);
|
||||
}
|
||||
|
||||
let content;
|
||||
let contentState;
|
||||
let contentResource;
|
||||
let serverKey;
|
||||
let hasEmptyContent = false;
|
||||
|
||||
baseResource = Resource.createIfNeeded(baseResource);
|
||||
|
||||
if (hasMultipleContents) {
|
||||
contentState = Cesium3DTileContentState.UNLOADED;
|
||||
// Each content may have its own URI, but they all need to be resolved
|
||||
// relative to the tileset, so the base resource is used.
|
||||
contentResource = baseResource.clone();
|
||||
} else if (defined(contentHeader)) {
|
||||
let contentHeaderUri = contentHeader.uri;
|
||||
if (defined(contentHeader.url)) {
|
||||
Cesium3DTile._deprecationWarning(
|
||||
"contentUrl",
|
||||
'This tileset JSON uses the "content.url" property which has been deprecated. Use "content.uri" instead.',
|
||||
);
|
||||
contentHeaderUri = contentHeader.url;
|
||||
}
|
||||
if (contentHeaderUri === "") {
|
||||
Cesium3DTile._deprecationWarning(
|
||||
"contentUriEmpty",
|
||||
"content.uri property is an empty string, which creates a circular dependency, making this tileset invalid. Omit the content property instead",
|
||||
);
|
||||
content = new Empty3DTileContent(tile._tileset, tile);
|
||||
hasEmptyContent = true;
|
||||
contentState = Cesium3DTileContentState.READY;
|
||||
} else {
|
||||
contentState = Cesium3DTileContentState.UNLOADED;
|
||||
contentResource = baseResource.getDerivedResource({
|
||||
url: contentHeaderUri,
|
||||
});
|
||||
serverKey = RequestScheduler.getServerKey(
|
||||
contentResource.getUrlComponent(),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
content = new Empty3DTileContent(tile._tileset, tile);
|
||||
hasEmptyContent = true;
|
||||
contentState = Cesium3DTileContentState.READY;
|
||||
}
|
||||
|
||||
tile._contentHeader = contentHeader;
|
||||
tile._contentBoundingVolume = contentBoundingVolume;
|
||||
tile._contentBoundingVolume2D = undefined;
|
||||
tile._content = content;
|
||||
tile._contentResource = contentResource;
|
||||
tile._contentState = contentState;
|
||||
tile._expiredContent = undefined;
|
||||
tile._serverKey = serverKey;
|
||||
tile.hasEmptyContent = hasEmptyContent;
|
||||
tile.hasRenderableContent = !hasEmptyContent;
|
||||
tile.hasMultipleContents = hasMultipleContents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value for the 'refine' property of a tile.
|
||||
*
|
||||
* If the given value from the header is one of the known, deprecated
|
||||
* lowercase values ("add" or "remove"), then a deprecation warning
|
||||
* will be printed, and the corresponding constant will be returned.
|
||||
*
|
||||
* If the value is <code>undefined</code>, and the parent is not
|
||||
* <code>undefined</code>, then the value from the parent will
|
||||
* be inherited and returned.
|
||||
*
|
||||
* Otherwise, <code>REPLACE</code> is returned as the default.
|
||||
*
|
||||
* @param {string|undefined} headerRefine The refine value from the JSON
|
||||
* @param {Cesium3DTile|undefined} parent The parent tile
|
||||
* @returns {number} The <code>Cesium3DTileRefine</code> value
|
||||
*/
|
||||
function determineRefine(headerRefine, parent) {
|
||||
// Note: This will not create a warning for strings like "RePlAcE",
|
||||
// but still handle them by uppercasing them.
|
||||
if (defined(headerRefine)) {
|
||||
if (headerRefine === "replace" || headerRefine === "add") {
|
||||
Cesium3DTile._deprecationWarning(
|
||||
"lowercase-refine",
|
||||
`This tile uses a lowercase refine "${
|
||||
headerRefine
|
||||
}". Instead use "${headerRefine.toUpperCase()}".`,
|
||||
);
|
||||
}
|
||||
const refine =
|
||||
headerRefine.toUpperCase() === "REPLACE"
|
||||
? Cesium3DTileRefine.REPLACE
|
||||
: Cesium3DTileRefine.ADD;
|
||||
return refine;
|
||||
}
|
||||
if (defined(parent)) {
|
||||
// Inherit from parent tile if omitted.
|
||||
return parent.refine;
|
||||
}
|
||||
return Cesium3DTileRefine.REPLACE;
|
||||
}
|
||||
|
||||
// This can be overridden for testing purposes
|
||||
Cesium3DTile._deprecationWarning = deprecationWarning;
|
||||
|
||||
|
|
@ -1128,11 +1189,9 @@ Cesium3DTile.prototype.requestContent = function () {
|
|||
if (this.hasEmptyContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.hasMultipleContents) {
|
||||
return requestMultipleContents(this);
|
||||
}
|
||||
|
||||
return requestSingleContent(this);
|
||||
};
|
||||
|
||||
|
|
@ -1350,52 +1409,12 @@ async function makeContent(tile, arrayBuffer) {
|
|||
tile.hasRenderableContent = false;
|
||||
}
|
||||
|
||||
let content;
|
||||
const contentFactory = Cesium3DTileContentFactory[preprocessed.contentType];
|
||||
if (tile.isDestroyed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (defined(preprocessed.binaryPayload)) {
|
||||
content = await Promise.resolve(
|
||||
contentFactory(
|
||||
tileset,
|
||||
tile,
|
||||
tile._contentResource,
|
||||
preprocessed.binaryPayload.buffer,
|
||||
0,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
// JSON formats
|
||||
content = await Promise.resolve(
|
||||
contentFactory(
|
||||
tileset,
|
||||
tile,
|
||||
tile._contentResource,
|
||||
preprocessed.jsonPayload,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const resource = tile._contentResource;
|
||||
const contentHeader = tile._contentHeader;
|
||||
|
||||
if (tile.hasImplicitContentMetadata) {
|
||||
const subtree = tile.implicitSubtree;
|
||||
const coordinates = tile.implicitCoordinates;
|
||||
content.metadata = subtree.getContentMetadataView(coordinates, 0);
|
||||
} else if (!tile.hasImplicitContent) {
|
||||
content.metadata = findContentMetadata(tileset, contentHeader);
|
||||
}
|
||||
|
||||
const groupMetadata = findGroupMetadata(tileset, contentHeader);
|
||||
if (defined(groupMetadata)) {
|
||||
content.group = new Cesium3DContentGroup({
|
||||
metadata: groupMetadata,
|
||||
});
|
||||
}
|
||||
|
||||
return content;
|
||||
return finishContent(tile, resource, preprocessed, contentHeader, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1405,8 +1424,13 @@ async function makeContent(tile, arrayBuffer) {
|
|||
* @private
|
||||
*/
|
||||
Cesium3DTile.prototype.cancelRequests = function () {
|
||||
// XXX_DYNAMIC: This actually happens sometimes, but only when the tile is
|
||||
// in the "LOADING" state. Now... what do do with dynamic tiles?
|
||||
console.log("Cesium3DTile.cancelRequests is called");
|
||||
if (this.hasMultipleContents) {
|
||||
this._content.cancelRequests();
|
||||
} else if (this._content instanceof Dynamic3DTileContent) {
|
||||
this._content.cancelRequests();
|
||||
} else {
|
||||
this._request.cancel();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -309,8 +309,8 @@ Cesium3DTileContent.prototype.getFeature = function (batchId) {
|
|||
* </p>
|
||||
*
|
||||
* @param {boolean} enabled Whether to enable or disable debug settings.
|
||||
* @returns {Cesium3DTileFeature} The corresponding {@link Cesium3DTileFeature} object.
|
||||
|
||||
* @param {Color|undefined} color The color to apply
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
Cesium3DTileContent.prototype.applyDebugSettings = function (enabled, color) {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import Tileset3DTileContent from "./Tileset3DTileContent.js";
|
|||
import Vector3DTileContent from "./Vector3DTileContent.js";
|
||||
import GaussianSplat3DTileContent from "./GaussianSplat3DTileContent.js";
|
||||
import RuntimeError from "../Core/RuntimeError.js";
|
||||
import Dynamic3DTileContent from "./Dynamic3DTileContent.js";
|
||||
|
||||
/**
|
||||
* Maps a tile's magic field in its header to a new content object for the tile's payload.
|
||||
|
|
@ -54,6 +55,9 @@ const Cesium3DTileContentFactory = {
|
|||
externalTileset: function (tileset, tile, resource, json) {
|
||||
return Tileset3DTileContent.fromJson(tileset, tile, resource, json);
|
||||
},
|
||||
dynamicContents: function (tileset, tile, resource, json) {
|
||||
return Dynamic3DTileContent.fromJson(tileset, tile, resource, json);
|
||||
},
|
||||
geom: function (tileset, tile, resource, arrayBuffer, byteOffset) {
|
||||
return new Geometry3DTileContent(
|
||||
tileset,
|
||||
|
|
|
|||
|
|
@ -113,6 +113,16 @@ const Cesium3DTileContentType = {
|
|||
* @private
|
||||
*/
|
||||
EXTERNAL_TILESET: "externalTileset",
|
||||
/**
|
||||
* The content is a dynamic content, which contains an array of
|
||||
* content objects with 'keys' that identify which content is
|
||||
* active at a certain point in time.
|
||||
*
|
||||
* @type {string}
|
||||
* @constant
|
||||
* @private
|
||||
*/
|
||||
DYNAMIC_CONTENTS: "dynamicContents",
|
||||
/**
|
||||
* Multiple contents are handled separately from the other content types
|
||||
* due to differences in request scheduling.
|
||||
|
|
|
|||
|
|
@ -216,10 +216,82 @@ function Cesium3DTileset(options) {
|
|||
this._modelUpAxis = undefined;
|
||||
this._modelForwardAxis = undefined;
|
||||
this._cache = new Cesium3DTilesetCache();
|
||||
this._processingQueue = [];
|
||||
this._selectedTiles = [];
|
||||
|
||||
this._emptyTiles = [];
|
||||
|
||||
/**
|
||||
* The tiles that are 'selected' by the traversal.
|
||||
*
|
||||
* During the 'Cesium3DTileset.update' call, the tile traversal is
|
||||
* executed. This includes the execution of the 'selectTiles'
|
||||
* function of the traversal (which exists in different forms,
|
||||
* depending on the traversal - but it's not really an interface,
|
||||
* just different functions).
|
||||
*
|
||||
* The 'selectTiles' function will first clear this list of
|
||||
* selected tiles, and then fill it with the tiles that are
|
||||
* 'selected'.
|
||||
*
|
||||
* (This usually/roughly means that they are in the view frustum
|
||||
* and have the right level of detail, but the details may vary)
|
||||
*
|
||||
* Some of these tiles may also be moved into the '_requestedTiles'
|
||||
* as part of the traversal.
|
||||
*/
|
||||
this._selectedTiles = [];
|
||||
|
||||
/**
|
||||
* Tiles that are 'requested' according to the traversal.
|
||||
*
|
||||
* This is usually a subset of the '_selectedTiles': The list
|
||||
* of requested tiles is cleared at the beginning of the traversal,
|
||||
* and then some tiles that are 'selected' will also be added to
|
||||
* these 'requested' tiles.
|
||||
*
|
||||
* There is no clear definition of what a 'requested' tile is.
|
||||
* It roughly means that ~"their content has to be loaded".
|
||||
* The tiles are added to this list, usually in a function
|
||||
* called 'loadTile', which is literally saying that the tile
|
||||
* is added to this list "if appropriate".
|
||||
*
|
||||
* The important point is that AFTER the traversal, the
|
||||
* contents of these tiles will be loaded, meaning that
|
||||
* 'Cesium3DTile.requestContent' will be called for them,
|
||||
* and they will be added to the '_requestedTilesInFlight'.
|
||||
*
|
||||
* (Once the content is loaded, the tiles will be added to
|
||||
* the '_processingQueue');
|
||||
*/
|
||||
this._requestedTiles = [];
|
||||
|
||||
/**
|
||||
* The tiles for which a content request is currently "in flight".
|
||||
*
|
||||
* This list is filled with tiles from the '_requestedTiles'
|
||||
* in each frame. Tiles are removed from this list after each
|
||||
* frame (when 'cancelOutOfViewRequests' is called), if their
|
||||
* '_contentState' is no longer 'LOADING'.
|
||||
*
|
||||
* So a tile being in this list roughly means that its content
|
||||
* is currently being loaded.
|
||||
*/
|
||||
this._requestedTilesInFlight = [];
|
||||
|
||||
/**
|
||||
* The tiles that are currently being processed.
|
||||
*
|
||||
* These are the tiles that have been 'selected' and 'requested'
|
||||
* and whose content was eventually obtained. Before the next
|
||||
* rendering pass, these tiles will be "processed", meaning that
|
||||
* their 'Cesium3DTile.process' method will be called.
|
||||
*
|
||||
* This mainly means that the 'Cesium3DTileContent.update' function
|
||||
* of their content is called, loading data and creating WebGL
|
||||
* resources and doing other random stuff, which eventually leads
|
||||
* to the tile moving from the 'PROCESSING' state into the 'READY' state.
|
||||
*/
|
||||
this._processingQueue = [];
|
||||
|
||||
this._selectedTilesToStyle = [];
|
||||
this._loadTimestamp = undefined;
|
||||
this._timeSinceLoad = 0.0;
|
||||
|
|
@ -276,8 +348,6 @@ function Cesium3DTileset(options) {
|
|||
this._statisticsPerPass[i] = new Cesium3DTilesetStatistics();
|
||||
}
|
||||
|
||||
this._requestedTilesInFlight = [];
|
||||
|
||||
this._maximumPriority = {
|
||||
foveatedFactor: -Number.MAX_VALUE,
|
||||
depth: -Number.MAX_VALUE,
|
||||
|
|
@ -1077,6 +1147,17 @@ function Cesium3DTileset(options) {
|
|||
instanceFeatureIdLabel = `instanceFeatureId_${instanceFeatureIdLabel}`;
|
||||
}
|
||||
this._instanceFeatureIdLabel = instanceFeatureIdLabel;
|
||||
|
||||
/**
|
||||
* The function that determines which inner contents of a dynamic
|
||||
* contents object are currently active.
|
||||
*
|
||||
* See the setter of this property for details.
|
||||
*
|
||||
* @type {Function|undefined}
|
||||
* @private
|
||||
*/
|
||||
this._dynamicContentPropertyProvider = undefined;
|
||||
}
|
||||
|
||||
Object.defineProperties(Cesium3DTileset.prototype, {
|
||||
|
|
@ -2103,6 +2184,34 @@ Object.defineProperties(Cesium3DTileset.prototype, {
|
|||
this._instanceFeatureIdLabel = value;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* The function that provides the properties based on which inner
|
||||
* contents of a dynamic content should be active.
|
||||
*
|
||||
* This is a function that returns a JSON plain object. This object corresponds
|
||||
* to one 'key' of a dynamic content definition. It will cause the content
|
||||
* with this key to be the currently active content, namely, when the
|
||||
* "update" function of that content is called.
|
||||
*
|
||||
* @memberof Cesium3DTileset.prototype
|
||||
* @readonly
|
||||
* @type {Function|undefined}
|
||||
* @private
|
||||
*/
|
||||
dynamicContentPropertyProvider: {
|
||||
get: function () {
|
||||
return this._dynamicContentPropertyProvider;
|
||||
},
|
||||
set: function (value) {
|
||||
if (defined(value) && !defined(this._dynamicContentsDimensions)) {
|
||||
console.log(
|
||||
"This tileset does not contain the 3DTILES_dynamic extension. The given function will not have an effect.",
|
||||
);
|
||||
}
|
||||
this._dynamicContentPropertyProvider = value;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
@ -2261,6 +2370,18 @@ Cesium3DTileset.fromUrl = async function (url, options) {
|
|||
tileset._initialClippingPlanesOriginMatrix,
|
||||
);
|
||||
|
||||
// Extract the information about the "dimensions" of the dynamic contents,
|
||||
// if present.
|
||||
// XXX_DYNAMIC This should probably not be done here, but ...
|
||||
// maybe in the constructor or so...? The lifecycle, though...
|
||||
const hasDynamicContents = hasExtension(tilesetJson, "3DTILES_dynamic");
|
||||
if (hasDynamicContents) {
|
||||
const dynamicContentsExtension = tilesetJson.extensions["3DTILES_dynamic"];
|
||||
tileset._dynamicContentsDimensions = dynamicContentsExtension.dimensions;
|
||||
} else {
|
||||
tileset._dynamicContentsDimensions = undefined;
|
||||
}
|
||||
|
||||
return tileset;
|
||||
};
|
||||
|
||||
|
|
@ -2362,6 +2483,54 @@ Cesium3DTileset.prototype.loadTileset = function (
|
|||
return rootTile;
|
||||
};
|
||||
|
||||
/**
|
||||
* XXX_DYNAMIC A draft for a convenience function for the dynamic content
|
||||
* properties provider. Whether or not this should be offered depends on
|
||||
* how much we want to specialize all this for single ISO8601 date strings.
|
||||
* We could even omit the "timeDimensionName" if this was a fixed, specified
|
||||
* string like "isoTimeStamp" or so.
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* Set the function that determines which dynamic content is currently active,
|
||||
* based on the ISO8601 string representation of the current time of the given
|
||||
* clock.
|
||||
*
|
||||
* @param {string} timeDimensionName The name of the property that will
|
||||
* contain the ISO8601 date string of the current time of the clock
|
||||
* @param {Clock} clock The clock that provides the current time
|
||||
*/
|
||||
Cesium3DTileset.prototype.setDefaultTimeDynamicContentPropertyProvider =
|
||||
function (timeDimensionName, clock) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
Check.typeOf.string("timeDimensionName", timeDimensionName);
|
||||
Check.typeOf.object("clock", clock);
|
||||
//>>includeEnd('debug');
|
||||
|
||||
const dimensions = this._dynamicContentsDimensions;
|
||||
if (defined(dimensions)) {
|
||||
const dimensionNames = dimensions.map((d) => d.name);
|
||||
if (!dimensionNames.includes(timeDimensionName)) {
|
||||
console.log(
|
||||
`The time dimension name ${timeDimensionName} is not a valid dimension name. Valid dimension names are`,
|
||||
dimensionNames,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const dynamicContentPropertyProvider = () => {
|
||||
const currentTime = clock.currentTime;
|
||||
if (!defined(currentTime)) {
|
||||
return undefined;
|
||||
}
|
||||
const currentTimeString = JulianDate.toIso8601(currentTime);
|
||||
return {
|
||||
[timeDimensionName]: currentTimeString,
|
||||
};
|
||||
};
|
||||
this.dynamicContentPropertyProvider = dynamicContentPropertyProvider;
|
||||
};
|
||||
|
||||
/**
|
||||
* Make a {@link Cesium3DTile} for a specific tile. If the tile's header has implicit
|
||||
* tiling (3D Tiles 1.1) or uses the <code>3DTILES_implicit_tiling</code> extension,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -6,12 +6,9 @@ import Request from "../Core/Request.js";
|
|||
import RequestScheduler from "../Core/RequestScheduler.js";
|
||||
import RequestState from "../Core/RequestState.js";
|
||||
import RequestType from "../Core/RequestType.js";
|
||||
import Cesium3DContentGroup from "./Cesium3DContentGroup.js";
|
||||
import Cesium3DTileContentType from "./Cesium3DTileContentType.js";
|
||||
import Cesium3DTileContentFactory from "./Cesium3DTileContentFactory.js";
|
||||
import findContentMetadata from "./findContentMetadata.js";
|
||||
import findGroupMetadata from "./findGroupMetadata.js";
|
||||
import preprocess3DTileContent from "./preprocess3DTileContent.js";
|
||||
import finishContent from "./finishContent.js";
|
||||
|
||||
/**
|
||||
* A collection of contents for tiles that have multiple contents, either via the tile JSON (3D Tiles 1.1) or the <code>3DTILES_multiple_contents</code> extension.
|
||||
|
|
@ -35,7 +32,11 @@ import preprocess3DTileContent from "./preprocess3DTileContent.js";
|
|||
function Multiple3DTileContent(tileset, tile, tilesetResource, contentsJson) {
|
||||
this._tileset = tileset;
|
||||
this._tile = tile;
|
||||
this._tilesetResource = tilesetResource;
|
||||
|
||||
// XXX_DYNAMIC Was unused... ?!
|
||||
// This could be avoided by writing a COMMENT!!!
|
||||
//this._tilesetResource = tilesetResource;
|
||||
|
||||
this._contents = [];
|
||||
this._contentsCreated = false;
|
||||
|
||||
|
|
@ -532,8 +533,8 @@ async function createInnerContent(multipleContents, arrayBuffer, index) {
|
|||
try {
|
||||
const preprocessed = preprocess3DTileContent(arrayBuffer);
|
||||
|
||||
const tileset = multipleContents._tileset;
|
||||
const resource = multipleContents._innerContentResources[index];
|
||||
const contentHeader = multipleContents._innerContentHeaders[index];
|
||||
const tile = multipleContents._tile;
|
||||
|
||||
if (preprocessed.contentType === Cesium3DTileContentType.EXTERNAL_TILESET) {
|
||||
|
|
@ -546,42 +547,7 @@ async function createInnerContent(multipleContents, arrayBuffer, index) {
|
|||
preprocessed.contentType === Cesium3DTileContentType.GEOMETRY ||
|
||||
preprocessed.contentType === Cesium3DTileContentType.VECTOR;
|
||||
|
||||
let content;
|
||||
const contentFactory = Cesium3DTileContentFactory[preprocessed.contentType];
|
||||
if (defined(preprocessed.binaryPayload)) {
|
||||
content = await Promise.resolve(
|
||||
contentFactory(
|
||||
tileset,
|
||||
tile,
|
||||
resource,
|
||||
preprocessed.binaryPayload.buffer,
|
||||
0,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
// JSON formats
|
||||
content = await Promise.resolve(
|
||||
contentFactory(tileset, tile, resource, preprocessed.jsonPayload),
|
||||
);
|
||||
}
|
||||
|
||||
const contentHeader = multipleContents._innerContentHeaders[index];
|
||||
|
||||
if (tile.hasImplicitContentMetadata) {
|
||||
const subtree = tile.implicitSubtree;
|
||||
const coordinates = tile.implicitCoordinates;
|
||||
content.metadata = subtree.getContentMetadataView(coordinates, index);
|
||||
} else if (!tile.hasImplicitContent) {
|
||||
content.metadata = findContentMetadata(tileset, contentHeader);
|
||||
}
|
||||
|
||||
const groupMetadata = findGroupMetadata(tileset, contentHeader);
|
||||
if (defined(groupMetadata)) {
|
||||
content.group = new Cesium3DContentGroup({
|
||||
metadata: groupMetadata,
|
||||
});
|
||||
}
|
||||
return content;
|
||||
return finishContent(tile, resource, preprocessed, contentHeader, index);
|
||||
} catch (error) {
|
||||
handleInnerContentFailed(multipleContents, index, error);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
import defined from "../Core/defined.js";
|
||||
import Cesium3DTileContentFactory from "./Cesium3DTileContentFactory.js";
|
||||
import findContentMetadata from "./findContentMetadata.js";
|
||||
import findGroupMetadata from "./findGroupMetadata.js";
|
||||
import Cesium3DContentGroup from "./Cesium3DContentGroup.js";
|
||||
|
||||
/**
|
||||
* Finalize the creation of a <code>Cesium3DTileContent</code> object.
|
||||
*
|
||||
* This takes the information from the tile and the preprocessed content
|
||||
* data that was fetched from the resource, creates the proper
|
||||
* <code>Cesium3DTileContent</code> instance, and assigns the
|
||||
* content- and group metadata to it.
|
||||
*
|
||||
* @function
|
||||
*
|
||||
* @param {Cesium3DTile} tile The tile that contained the content
|
||||
* @param {Resource} resource The resource
|
||||
* @param {PreprocessedContent} preprocessed The return value of <code>preprocess3DTileContent</code>
|
||||
* @param {object} contentHeader the JSON header for a {@link Cesium3DTileContent}
|
||||
* @param {number} index The content index. This is 0 for a single content, or the index of the inner content for multiple contents.
|
||||
* @return {Cesium3DTileContent} The finished <code>Cesium3DTileContent</code>
|
||||
* @private
|
||||
*/
|
||||
async function finishContent(
|
||||
tile,
|
||||
resource,
|
||||
preprocessed,
|
||||
contentHeader,
|
||||
index,
|
||||
) {
|
||||
const tileset = tile._tileset;
|
||||
const contentFactory = Cesium3DTileContentFactory[preprocessed.contentType];
|
||||
let content;
|
||||
if (defined(preprocessed.binaryPayload)) {
|
||||
content = await Promise.resolve(
|
||||
contentFactory(
|
||||
tileset,
|
||||
tile,
|
||||
resource,
|
||||
preprocessed.binaryPayload.buffer,
|
||||
0,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
// JSON formats
|
||||
content = await Promise.resolve(
|
||||
contentFactory(tileset, tile, resource, preprocessed.jsonPayload),
|
||||
);
|
||||
}
|
||||
|
||||
if (tile.hasImplicitContentMetadata) {
|
||||
const subtree = tile.implicitSubtree;
|
||||
const coordinates = tile.implicitCoordinates;
|
||||
content.metadata = subtree.getContentMetadataView(coordinates, index);
|
||||
} else if (!tile.hasImplicitContent) {
|
||||
content.metadata = findContentMetadata(tileset, contentHeader);
|
||||
}
|
||||
|
||||
const groupMetadata = findGroupMetadata(tileset, contentHeader);
|
||||
if (defined(groupMetadata)) {
|
||||
content.group = new Cesium3DContentGroup({
|
||||
metadata: groupMetadata,
|
||||
});
|
||||
}
|
||||
return content;
|
||||
}
|
||||
export default finishContent;
|
||||
|
|
@ -84,6 +84,15 @@ function preprocess3DTileContent(arrayBuffer) {
|
|||
};
|
||||
}
|
||||
|
||||
if (defined(json.dynamicContents)) {
|
||||
// If this is not dynamic content, someone must have
|
||||
// added that 'dynamicContents' property maliciously.
|
||||
return {
|
||||
contentType: Cesium3DTileContentType.DYNAMIC_CONTENTS,
|
||||
jsonPayload: json,
|
||||
};
|
||||
}
|
||||
|
||||
throw new RuntimeError("Invalid tile content.");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -852,16 +852,16 @@ describe("Scene/TextureAtlas", function () {
|
|||
.2222222222222222...............
|
||||
.2222222222222222...............
|
||||
.2222222222222222...............
|
||||
.22222222222222223333333333.....
|
||||
.22222222222222223333333333.....
|
||||
.22222222222222223333333333.....
|
||||
.22222222222222223333333333.....
|
||||
.22222222222222223333333333.....
|
||||
.22222222222222223333333333.....
|
||||
.22222222222222223333333333.....
|
||||
.22222222222222223333333333.....
|
||||
.22222222222222223333333333.....
|
||||
.2222222222222222333333333301...
|
||||
.2222222222222222.3333333333....
|
||||
.2222222222222222.3333333333....
|
||||
.2222222222222222.3333333333....
|
||||
.2222222222222222.3333333333....
|
||||
.2222222222222222.3333333333....
|
||||
.2222222222222222.3333333333....
|
||||
.2222222222222222.3333333333....
|
||||
.2222222222222222.3333333333.1..
|
||||
.2222222222222222.3333333333....
|
||||
.2222222222222222.3333333333.0..
|
||||
................................
|
||||
`.trim(),
|
||||
);
|
||||
|
|
@ -926,9 +926,9 @@ describe("Scene/TextureAtlas", function () {
|
|||
.2222222222...
|
||||
.2222222222...
|
||||
.2222222222...
|
||||
.2222222222.1.
|
||||
.2222222222...
|
||||
.2222222222...
|
||||
.222222222201.
|
||||
.2222222222.0.
|
||||
..............
|
||||
`.trim(),
|
||||
);
|
||||
|
|
@ -976,16 +976,16 @@ describe("Scene/TextureAtlas", function () {
|
|||
.3333333333333333...............
|
||||
.3333333333333333...............
|
||||
.3333333333333333...............
|
||||
.33333333333333332222222222.....
|
||||
.33333333333333332222222222.....
|
||||
.33333333333333332222222222.....
|
||||
.33333333333333332222222222.....
|
||||
.33333333333333332222222222.....
|
||||
.33333333333333332222222222.....
|
||||
.33333333333333332222222222.....
|
||||
.33333333333333332222222222.....
|
||||
.33333333333333332222222222.....
|
||||
.3333333333333333222222222201...
|
||||
.3333333333333333.2222222222....
|
||||
.3333333333333333.2222222222....
|
||||
.3333333333333333.2222222222....
|
||||
.3333333333333333.2222222222....
|
||||
.3333333333333333.2222222222....
|
||||
.3333333333333333.2222222222....
|
||||
.3333333333333333.2222222222....
|
||||
.3333333333333333.2222222222.1..
|
||||
.3333333333333333.2222222222....
|
||||
.3333333333333333.2222222222.0..
|
||||
................................
|
||||
`.trim(),
|
||||
);
|
||||
|
|
@ -1337,6 +1337,108 @@ describe("Scene/TextureAtlas", function () {
|
|||
).contextToRender([0, 255, 0, 255]);
|
||||
});
|
||||
|
||||
it("adds custom padding with borderWidthInPixels", async function () {
|
||||
atlas = new TextureAtlas({ borderWidthInPixels: 0 });
|
||||
let indices = await addImages();
|
||||
|
||||
expect(drawAtlas(atlas, indices)).toBe(
|
||||
`
|
||||
................
|
||||
................
|
||||
................
|
||||
................
|
||||
................
|
||||
................
|
||||
2222222222......
|
||||
2222222222......
|
||||
2222222222......
|
||||
2222222222......
|
||||
2222222222......
|
||||
2222222222......
|
||||
22222222220.....
|
||||
22222222220.....
|
||||
22222222220.....
|
||||
222222222201....
|
||||
`.trim(),
|
||||
);
|
||||
|
||||
atlas = new TextureAtlas({ borderWidthInPixels: 2 });
|
||||
indices = await addImages();
|
||||
|
||||
expect(drawAtlas(atlas, indices)).toBe(
|
||||
`
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
..2222222222....................
|
||||
..2222222222....................
|
||||
..2222222222....................
|
||||
..2222222222..1.................
|
||||
..2222222222....................
|
||||
..2222222222....................
|
||||
..2222222222..0.................
|
||||
..2222222222..0.................
|
||||
..2222222222..0.................
|
||||
..2222222222..0.................
|
||||
................................
|
||||
................................
|
||||
`.trim(),
|
||||
);
|
||||
|
||||
atlas = new TextureAtlas({ borderWidthInPixels: 5 });
|
||||
indices = await addImages();
|
||||
|
||||
expect(drawAtlas(atlas, indices)).toBe(
|
||||
`
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
.....2222222222.................
|
||||
.....2222222222.................
|
||||
.....2222222222.................
|
||||
.....2222222222.................
|
||||
.....2222222222.................
|
||||
.....2222222222.................
|
||||
.....2222222222.....0...........
|
||||
.....2222222222.....0...........
|
||||
.....2222222222.....0...........
|
||||
.....2222222222.....0.....1.....
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
`.trim(),
|
||||
);
|
||||
|
||||
async function addImages() {
|
||||
const promise = Promise.all([
|
||||
atlas.addImage(tallGreenGuid, tallGreenImage),
|
||||
atlas.addImage(blueGuid, blueImage),
|
||||
atlas.addImage(bigBlueGuid, bigBlueImage),
|
||||
]);
|
||||
|
||||
return pollWhilePromise(promise, () => {
|
||||
atlas.update(scene.frameState.context);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it("GUID changes when atlas texure is modified", async function () {
|
||||
atlas = new TextureAtlas();
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue