diff --git a/CHANGES.md b/CHANGES.md
index c6feeed64477..18366f3727fd 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -21,6 +21,8 @@
##### Additions :tada:
- Added `Scene.pickVoxel` to pick individual cells from a `VoxelPrimitive`, and `VoxelCell` to report information about the picked cell. [#11828](https://github.com/CesiumGS/cesium/pull/11828)
+- Added `Scene.defaultLogDepthbuffer` to allow changing the default behavior of the `logDepthBuffer` for newly created `Scene` instances. [#11859](https://github.com/CesiumGS/cesium/pull/11859)
+- Added `SensorVolumePortionToDisplay` to assist `CzmlDataSource` in parsing CZML. [#11859](https://github.com/CesiumGS/cesium/pull/11859)
- Added support for I3S Building Scene Layer. [#11678](https://github.com/CesiumGS/cesium/pull/11678)
##### Deprecated :hourglass_flowing_sand:
diff --git a/packages/engine/Source/Core/IntersectionTests.js b/packages/engine/Source/Core/IntersectionTests.js
index c8cbcbddebea..295b467bdb45 100644
--- a/packages/engine/Source/Core/IntersectionTests.js
+++ b/packages/engine/Source/Core/IntersectionTests.js
@@ -508,7 +508,10 @@ function addWithCancellationCheck(left, right, tolerance) {
return difference;
}
-function quadraticVectorExpression(A, b, c, x, w) {
+/**
+ * @private
+ */
+IntersectionTests.quadraticVectorExpression = function (A, b, c, x, w) {
const xSquared = x * x;
const wSquared = w * w;
@@ -634,7 +637,7 @@ function quadraticVectorExpression(A, b, c, x, w) {
}
return solutions;
-}
+};
const firstAxisScratch = new Cartesian3();
const secondAxisScratch = new Cartesian3();
@@ -740,7 +743,7 @@ IntersectionTests.grazingAltitudeLocation = function (ray, ellipsoid) {
const b = Matrix3.multiplyByVector(temp, position, bCart);
// Solve for the solutions to the expression in standard form:
- const solutions = quadraticVectorExpression(
+ const solutions = IntersectionTests.quadraticVectorExpression(
A,
Cartesian3.negate(b, firstAxisScratch),
0.0,
diff --git a/packages/engine/Source/DataSources/CzmlDataSource.js b/packages/engine/Source/DataSources/CzmlDataSource.js
index fed70f81705b..6bcf7006b3ee 100644
--- a/packages/engine/Source/DataSources/CzmlDataSource.js
+++ b/packages/engine/Source/DataSources/CzmlDataSource.js
@@ -90,6 +90,7 @@ import VelocityOrientationProperty from "./VelocityOrientationProperty.js";
import VelocityVectorProperty from "./VelocityVectorProperty.js";
import WallGraphics from "./WallGraphics.js";
import Cesium3DTilesetGraphics from "./Cesium3DTilesetGraphics.js";
+import SensorVolumePortionToDisplay from "../Scene/SensorVolumePortionToDisplay.js";
// A marker type to distinguish CZML properties where we need to end up with a unit vector.
// The data is still loaded into Cartesian3 objects but they are normalized.
@@ -576,6 +577,10 @@ function unwrapInterval(type, czmlInterval, sourceUri) {
return unwrapQuaternionInterval(czmlInterval);
case Rotation:
return defaultValue(czmlInterval.number, czmlInterval);
+ case SensorVolumePortionToDisplay:
+ return SensorVolumePortionToDisplay[
+ defaultValue(czmlInterval.portionToDisplay, czmlInterval)
+ ];
case ShadowMode:
return ShadowMode[
defaultValue(
@@ -598,7 +603,7 @@ function unwrapInterval(type, czmlInterval, sourceUri) {
defaultValue(czmlInterval.verticalOrigin, czmlInterval)
];
default:
- throw new RuntimeError(type);
+ throw new RuntimeError(`Unknown CzmlDataSource interval type: ${type}`);
}
}
@@ -5006,31 +5011,54 @@ Object.defineProperties(CzmlDataSource.prototype, {
* @type {CzmlDataSource.UpdaterFunction[]}
*/
CzmlDataSource.updaters = [
- processBillboard, //
- processBox, //
- processCorridor, //
- processCylinder, //
- processEllipse, //
- processEllipsoid, //
- processLabel, //
- processModel, //
- processName, //
- processDescription, //
- processPath, //
- processPoint, //
- processPolygon, //
- processPolyline, //
- processPolylineVolume, //
- processProperties, //
- processRectangle, //
- processPosition, //
- processTileset, //
- processViewFrom, //
- processWall, //
- processOrientation, //
+ processBillboard,
+ processBox,
+ processCorridor,
+ processCylinder,
+ processEllipse,
+ processEllipsoid,
+ processLabel,
+ processModel,
+ processName,
+ processDescription,
+ processPath,
+ processPoint,
+ processPolygon,
+ processPolyline,
+ processPolylineVolume,
+ processProperties,
+ processRectangle,
+ processPosition,
+ processTileset,
+ processViewFrom,
+ processWall,
+ processOrientation,
processAvailability,
];
+/**
+ * Add the provided updater to the list of updaters if not already included
+ * @private
+ * @param {CzmlDataSource.UpdaterFunction} updater
+ */
+CzmlDataSource.registerUpdater = function (updater) {
+ if (!CzmlDataSource.updaters.includes(updater)) {
+ CzmlDataSource.updaters.push(updater);
+ }
+};
+
+/**
+ * Remove the provided updater from the list of updaters if already included
+ * @private
+ * @param {CzmlDataSource.UpdaterFunction} updater
+ */
+CzmlDataSource.unregisterUpdater = function (updater) {
+ if (CzmlDataSource.updaters.includes(updater)) {
+ const index = CzmlDataSource.updaters.indexOf(updater);
+ CzmlDataSource.updaters.splice(index, 1);
+ }
+};
+
/**
* Processes the provided url or CZML object without clearing any existing data.
*
diff --git a/packages/engine/Source/DataSources/DataSourceDisplay.js b/packages/engine/Source/DataSources/DataSourceDisplay.js
index 6ea22ddf41ba..eac541551705 100644
--- a/packages/engine/Source/DataSources/DataSourceDisplay.js
+++ b/packages/engine/Source/DataSources/DataSourceDisplay.js
@@ -120,6 +120,30 @@ function DataSourceDisplay(options) {
this._ready = false;
}
+const ExtraVisualizers = [];
+/**
+ * Add the provided Visualizer to the default visualizers callback if not already included
+ * @private
+ * @param {Visualizer} visualizer Visualizer class to add
+ */
+DataSourceDisplay.registerVisualizer = function (visualizer) {
+ if (!ExtraVisualizers.includes(visualizer)) {
+ ExtraVisualizers.push(visualizer);
+ }
+};
+
+/**
+ * Remove the provided Visualizer from the default visualizers callback if it's already included
+ * @private
+ * @param {Visualizer} visualizer Visualizer class to remove
+ */
+DataSourceDisplay.unregisterVisualizer = function (visualizer) {
+ if (ExtraVisualizers.includes(visualizer)) {
+ const index = ExtraVisualizers.indexOf(visualizer);
+ ExtraVisualizers.splice(index, 1);
+ }
+};
+
/**
* Gets or sets the default function which creates an array of visualizers used for visualization.
* By default, this function uses all standard visualizers.
@@ -151,6 +175,9 @@ DataSourceDisplay.defaultVisualizersCallback = function (
dataSource._primitives,
dataSource._groundPrimitives
),
+ ...ExtraVisualizers.map(
+ (VisualizerClass) => new VisualizerClass(scene, entities)
+ ),
];
};
diff --git a/packages/engine/Source/DataSources/Entity.js b/packages/engine/Source/DataSources/Entity.js
index c7d20e8c0a3f..998108671b35 100644
--- a/packages/engine/Source/DataSources/Entity.js
+++ b/packages/engine/Source/DataSources/Entity.js
@@ -41,6 +41,8 @@ import WallGraphics from "./WallGraphics.js";
const cartoScratch = new Cartographic();
+const ExtraPropertyNames = [];
+
function createConstantPositionProperty(value) {
return new ConstantPositionProperty(value);
}
@@ -127,7 +129,7 @@ function Entity(options) {
"corridor",
"cylinder",
"description",
- "ellipse", //
+ "ellipse",
"ellipsoid",
"label",
"model",
@@ -136,7 +138,7 @@ function Entity(options) {
"path",
"plane",
"point",
- "polygon", //
+ "polygon",
"polyline",
"polylineVolume",
"position",
@@ -144,6 +146,7 @@ function Entity(options) {
"rectangle",
"viewFrom",
"wall",
+ ...ExtraPropertyNames,
];
this._billboard = undefined;
@@ -494,6 +497,21 @@ Object.defineProperties(Entity.prototype, {
wall: createPropertyTypeDescriptor("wall", WallGraphics),
});
+/**
+ * Add the specified type and construct the properties for it in the Entity class
+ * @private
+ * @param {string} propertyName name of the property that controls/accesses this entity type
+ * @param {{ constructor: function }} Type The Graphics class to associate with this entity type
+ */
+Entity.registerEntityType = function (propertyName, Type) {
+ Object.defineProperties(Entity.prototype, {
+ [propertyName]: createPropertyTypeDescriptor(propertyName, Type),
+ });
+ if (!ExtraPropertyNames.includes(propertyName)) {
+ ExtraPropertyNames.push(propertyName);
+ }
+};
+
/**
* Given a time, returns true if this object should have data during that time.
*
diff --git a/packages/engine/Source/DataSources/GeometryUpdaterSet.js b/packages/engine/Source/DataSources/GeometryUpdaterSet.js
new file mode 100644
index 000000000000..6dd0ba4ec90e
--- /dev/null
+++ b/packages/engine/Source/DataSources/GeometryUpdaterSet.js
@@ -0,0 +1,114 @@
+import destroyObject from "../Core/destroyObject.js";
+import Event from "../Core/Event.js";
+import EventHelper from "../Core/EventHelper.js";
+import BoxGeometryUpdater from "./BoxGeometryUpdater.js";
+import CorridorGeometryUpdater from "./CorridorGeometryUpdater.js";
+import CylinderGeometryUpdater from "./CylinderGeometryUpdater.js";
+import EllipseGeometryUpdater from "./EllipseGeometryUpdater.js";
+import EllipsoidGeometryUpdater from "./EllipsoidGeometryUpdater.js";
+import PlaneGeometryUpdater from "./PlaneGeometryUpdater.js";
+import PolygonGeometryUpdater from "./PolygonGeometryUpdater.js";
+import PolylineVolumeGeometryUpdater from "./PolylineVolumeGeometryUpdater.js";
+import RectangleGeometryUpdater from "./RectangleGeometryUpdater.js";
+import WallGeometryUpdater from "./WallGeometryUpdater.js";
+
+/** @type {GeometryUpdater[]} */
+const geometryUpdaters = [
+ BoxGeometryUpdater,
+ CylinderGeometryUpdater,
+ CorridorGeometryUpdater,
+ EllipseGeometryUpdater,
+ EllipsoidGeometryUpdater,
+ PlaneGeometryUpdater,
+ PolygonGeometryUpdater,
+ PolylineVolumeGeometryUpdater,
+ RectangleGeometryUpdater,
+ WallGeometryUpdater,
+];
+
+/**
+ * Manages a set of "updater" classes for the {@link GeometryVisualizer} for each entity
+ *
+ * @private
+ * @param {Entity} entity
+ * @param {Scene} scene
+ */
+function GeometryUpdaterSet(entity, scene) {
+ this.entity = entity;
+ this.scene = scene;
+ const updaters = new Array(geometryUpdaters.length);
+ const geometryChanged = new Event();
+ const eventHelper = new EventHelper();
+ for (let i = 0; i < updaters.length; i++) {
+ const updater = new geometryUpdaters[i](entity, scene);
+ eventHelper.add(updater.geometryChanged, (geometry) => {
+ geometryChanged.raiseEvent(geometry);
+ });
+ updaters[i] = updater;
+ }
+ this.updaters = updaters;
+ this.geometryChanged = geometryChanged;
+ this.eventHelper = eventHelper;
+
+ this._removeEntitySubscription = entity.definitionChanged.addEventListener(
+ GeometryUpdaterSet.prototype._onEntityPropertyChanged,
+ this
+ );
+}
+
+GeometryUpdaterSet.prototype._onEntityPropertyChanged = function (
+ entity,
+ propertyName,
+ newValue,
+ oldValue
+) {
+ const updaters = this.updaters;
+ for (let i = 0; i < updaters.length; i++) {
+ updaters[i]._onEntityPropertyChanged(
+ entity,
+ propertyName,
+ newValue,
+ oldValue
+ );
+ }
+};
+
+GeometryUpdaterSet.prototype.forEach = function (callback) {
+ const updaters = this.updaters;
+ for (let i = 0; i < updaters.length; i++) {
+ callback(updaters[i]);
+ }
+};
+
+GeometryUpdaterSet.prototype.destroy = function () {
+ this.eventHelper.removeAll();
+ const updaters = this.updaters;
+ for (let i = 0; i < updaters.length; i++) {
+ updaters[i].destroy();
+ }
+ this._removeEntitySubscription();
+ destroyObject(this);
+};
+
+/**
+ * Add the provided updater to the default list of updaters if not already included
+ * @param {GeometryUpdater} updater
+ */
+GeometryUpdaterSet.registerUpdater = function (updater) {
+ if (!geometryUpdaters.includes(updater)) {
+ geometryUpdaters.push(updater);
+ }
+};
+
+/**
+ * Remove the provided updater from the default list of updaters if included
+ * @param {GeometryUpdater} updater
+ */
+GeometryUpdaterSet.unregisterUpdater = function (updater) {
+ if (geometryUpdaters.includes(updater)) {
+ const index = geometryUpdaters.indexOf(updater);
+ geometryUpdaters.splice(index, 1);
+ }
+};
+
+export default GeometryUpdaterSet;
diff --git a/packages/engine/Source/DataSources/GeometryVisualizer.js b/packages/engine/Source/DataSources/GeometryVisualizer.js
index 710478944371..e2d1ed306a0f 100644
--- a/packages/engine/Source/DataSources/GeometryVisualizer.js
+++ b/packages/engine/Source/DataSources/GeometryVisualizer.js
@@ -4,105 +4,23 @@ import Check from "../Core/Check.js";
import defaultValue from "../Core/defaultValue.js";
import defined from "../Core/defined.js";
import destroyObject from "../Core/destroyObject.js";
-import Event from "../Core/Event.js";
-import EventHelper from "../Core/EventHelper.js";
import ClassificationType from "../Scene/ClassificationType.js";
import MaterialAppearance from "../Scene/MaterialAppearance.js";
import PerInstanceColorAppearance from "../Scene/PerInstanceColorAppearance.js";
import ShadowMode from "../Scene/ShadowMode.js";
import BoundingSphereState from "./BoundingSphereState.js";
-import BoxGeometryUpdater from "./BoxGeometryUpdater.js";
import ColorMaterialProperty from "./ColorMaterialProperty.js";
-import CorridorGeometryUpdater from "./CorridorGeometryUpdater.js";
-import CylinderGeometryUpdater from "./CylinderGeometryUpdater.js";
import DynamicGeometryBatch from "./DynamicGeometryBatch.js";
-import EllipseGeometryUpdater from "./EllipseGeometryUpdater.js";
-import EllipsoidGeometryUpdater from "./EllipsoidGeometryUpdater.js";
import Entity from "./Entity.js";
-import PlaneGeometryUpdater from "./PlaneGeometryUpdater.js";
-import PolygonGeometryUpdater from "./PolygonGeometryUpdater.js";
-import PolylineVolumeGeometryUpdater from "./PolylineVolumeGeometryUpdater.js";
-import RectangleGeometryUpdater from "./RectangleGeometryUpdater.js";
+import GeometryUpdaterSet from "./GeometryUpdaterSet.js";
import StaticGeometryColorBatch from "./StaticGeometryColorBatch.js";
import StaticGeometryPerMaterialBatch from "./StaticGeometryPerMaterialBatch.js";
import StaticGroundGeometryColorBatch from "./StaticGroundGeometryColorBatch.js";
import StaticGroundGeometryPerMaterialBatch from "./StaticGroundGeometryPerMaterialBatch.js";
import StaticOutlineGeometryBatch from "./StaticOutlineGeometryBatch.js";
-import WallGeometryUpdater from "./WallGeometryUpdater.js";
const emptyArray = [];
-const geometryUpdaters = [
- BoxGeometryUpdater,
- CylinderGeometryUpdater,
- CorridorGeometryUpdater,
- EllipseGeometryUpdater,
- EllipsoidGeometryUpdater,
- PlaneGeometryUpdater,
- PolygonGeometryUpdater,
- PolylineVolumeGeometryUpdater,
- RectangleGeometryUpdater,
- WallGeometryUpdater,
-];
-
-function GeometryUpdaterSet(entity, scene) {
- this.entity = entity;
- this.scene = scene;
- const updaters = new Array(geometryUpdaters.length);
- const geometryChanged = new Event();
- function raiseEvent(geometry) {
- geometryChanged.raiseEvent(geometry);
- }
- const eventHelper = new EventHelper();
- for (let i = 0; i < updaters.length; i++) {
- const updater = new geometryUpdaters[i](entity, scene);
- eventHelper.add(updater.geometryChanged, raiseEvent);
- updaters[i] = updater;
- }
- this.updaters = updaters;
- this.geometryChanged = geometryChanged;
- this.eventHelper = eventHelper;
-
- this._removeEntitySubscription = entity.definitionChanged.addEventListener(
- GeometryUpdaterSet.prototype._onEntityPropertyChanged,
- this
- );
-}
-
-GeometryUpdaterSet.prototype._onEntityPropertyChanged = function (
- entity,
- propertyName,
- newValue,
- oldValue
-) {
- const updaters = this.updaters;
- for (let i = 0; i < updaters.length; i++) {
- updaters[i]._onEntityPropertyChanged(
- entity,
- propertyName,
- newValue,
- oldValue
- );
- }
-};
-
-GeometryUpdaterSet.prototype.forEach = function (callback) {
- const updaters = this.updaters;
- for (let i = 0; i < updaters.length; i++) {
- callback(updaters[i]);
- }
-};
-
-GeometryUpdaterSet.prototype.destroy = function () {
- this.eventHelper.removeAll();
- const updaters = this.updaters;
- for (let i = 0; i < updaters.length; i++) {
- updaters[i].destroy();
- }
- this._removeEntitySubscription();
- destroyObject(this);
-};
-
/**
* A general purpose visualizer for geometry represented by {@link Primitive} instances.
* @alias GeometryVisualizer
@@ -293,6 +211,24 @@ function GeometryVisualizer(
);
}
+/**
+ * Add the provided updater to the default list of updaters if not already included
+ * @private
+ * @param {GeometryUpdater} updater
+ */
+GeometryVisualizer.registerUpdater = function (updater) {
+ GeometryUpdaterSet.registerUpdater(updater);
+};
+
+/**
+ * Remove the provided updater from the default list of updaters if included
+ * @private
+ * @param {GeometryUpdater} updater
+ */
+GeometryVisualizer.unregisterUpdater = function (updater) {
+ GeometryUpdaterSet.unregisterUpdater(updater);
+};
+
/**
* Updates all of the primitives created by this visualizer to match their
* Entity counterpart at the given time.
diff --git a/packages/engine/Source/Renderer/ContextLimits.js b/packages/engine/Source/Renderer/ContextLimits.js
index 6bdb837cf60e..b6c5e5731f13 100644
--- a/packages/engine/Source/Renderer/ContextLimits.js
+++ b/packages/engine/Source/Renderer/ContextLimits.js
@@ -1,4 +1,6 @@
/**
+ * These are set in the constructor for {@link Context}
+ *
* @private
*/
const ContextLimits = {
diff --git a/packages/engine/Source/Scene/Primitive.js b/packages/engine/Source/Scene/Primitive.js
index 12870094fdcb..970a719a3d80 100644
--- a/packages/engine/Source/Scene/Primitive.js
+++ b/packages/engine/Source/Scene/Primitive.js
@@ -1174,15 +1174,19 @@ function loadAsynchronous(primitive, frameState) {
instanceIds.push(instances[i].id);
//>>includeStart('debug', pragmas.debug);
- if (!defined(geometry._workerName)) {
+ if (
+ (defined(geometry._workerName) && defined(geometry._workerPath)) ||
+ (!defined(geometry._workerName) && !defined(geometry._workerPath))
+ ) {
throw new DeveloperError(
- "_workerName must be defined for asynchronous geometry."
+ "Must define either _workerName or _workerPath for asynchronous geometry."
);
}
//>>includeEnd('debug');
subTasks.push({
moduleName: geometry._workerName,
+ modulePath: geometry._workerPath,
geometry: geometry,
});
}
diff --git a/packages/engine/Source/Scene/Scene.js b/packages/engine/Source/Scene/Scene.js
index 1d49771e5d3d..36a8193ce61b 100644
--- a/packages/engine/Source/Scene/Scene.js
+++ b/packages/engine/Source/Scene/Scene.js
@@ -172,7 +172,7 @@ function Scene(options) {
this._globeHeightDirty = undefined;
this._cameraUnderground = false;
- this._logDepthBuffer = context.fragmentDepth;
+ this._logDepthBuffer = Scene.defaultLogDepthBuffer && context.fragmentDepth;
this._logDepthBufferDirty = true;
this._tweens = new TweenCollection();
@@ -734,6 +734,12 @@ function Scene(options) {
this.initializeFrame();
}
+/**
+ * Use this to set the default value for {@link Scene#logarithmicDepthBuffer} in newly constructed Scenes
+ * This property relies on fragmentDepth being supported.
+ */
+Scene.defaultLogDepthBuffer = true;
+
function updateGlobeListeners(scene, globe) {
for (let i = 0; i < scene._removeGlobeCallbacks.length; ++i) {
scene._removeGlobeCallbacks[i]();
diff --git a/packages/engine/Source/Scene/SensorVolumePortionToDisplay.js b/packages/engine/Source/Scene/SensorVolumePortionToDisplay.js
new file mode 100644
index 000000000000..5fafdcb63bdc
--- /dev/null
+++ b/packages/engine/Source/Scene/SensorVolumePortionToDisplay.js
@@ -0,0 +1,69 @@
+import { DeveloperError } from "@cesium/engine";
+
+/**
+ * Constants used to indicated what part of the sensor volume to display.
+ *
+ * @enum {Number}
+ */
+const SensorVolumePortionToDisplay = {
+ /**
+ * 0x0000. Display the complete sensor volume.
+ *
+ * @type {Number}
+ * @constant
+ */
+ COMPLETE: 0x0000,
+ /**
+ * 0x0001. Display the portion of the sensor volume that lies below the true horizon of the ellipsoid.
+ *
+ * @type {Number}
+ * @constant
+ */
+ BELOW_ELLIPSOID_HORIZON: 0x0001,
+ /**
+ * 0x0002. Display the portion of the sensor volume that lies above the true horizon of the ellipsoid.
+ *
+ * @type {Number}
+ * @constant
+ */
+ ABOVE_ELLIPSOID_HORIZON: 0x0002,
+};
+
+/**
+ * Validates that the provided value is a valid {@link SensorVolumePortionToDisplay} enumeration value.
+ *
+ * @param {SensorVolumePortionToDisplay} portionToDisplay The value to validate.
+ *
+ * @returns {Boolean} true
if the provided value is a valid enumeration value; otherwise, false
.
+ */
+SensorVolumePortionToDisplay.validate = function (portionToDisplay) {
+ return (
+ portionToDisplay === SensorVolumePortionToDisplay.COMPLETE ||
+ portionToDisplay === SensorVolumePortionToDisplay.BELOW_ELLIPSOID_HORIZON ||
+ portionToDisplay === SensorVolumePortionToDisplay.ABOVE_ELLIPSOID_HORIZON
+ );
+};
+
+/**
+ * Converts the provided value to its corresponding enumeration string.
+ *
+ * @param {SensorVolumePortionToDisplay} portionToDisplay The value to be converted to its corresponding enumeration string.
+ *
+ * @returns {String} The enumeration string corresponding to the value.
+ */
+SensorVolumePortionToDisplay.toString = function (portionToDisplay) {
+ switch (portionToDisplay) {
+ case SensorVolumePortionToDisplay.COMPLETE:
+ return "COMPLETE";
+ case SensorVolumePortionToDisplay.BELOW_ELLIPSOID_HORIZON:
+ return "BELOW_ELLIPSOID_HORIZON";
+ case SensorVolumePortionToDisplay.ABOVE_ELLIPSOID_HORIZON:
+ return "ABOVE_ELLIPSOID_HORIZON";
+ default:
+ throw new DeveloperError(
+ "SensorVolumePortionToDisplay value is not valid and cannot be converted to a String."
+ );
+ }
+};
+
+export default SensorVolumePortionToDisplay;
diff --git a/packages/engine/Source/Workers/createGeometry.js b/packages/engine/Source/Workers/createGeometry.js
index 063453e50e56..e6b63094a2bd 100644
--- a/packages/engine/Source/Workers/createGeometry.js
+++ b/packages/engine/Source/Workers/createGeometry.js
@@ -1,23 +1,46 @@
+import DeveloperError from "../Core/DeveloperError.js";
+import defaultValue from "../Core/defaultValue.js";
import defined from "../Core/defined.js";
import PrimitivePipeline from "../Scene/PrimitivePipeline.js";
import createTaskProcessorWorker from "./createTaskProcessorWorker.js";
+/* global require */
const moduleCache = {};
-async function getModule(moduleName) {
- let module = moduleCache[moduleName];
- if (!defined(module)) {
+async function getModule(moduleName, modulePath) {
+ let module = defaultValue(moduleCache[modulePath] ?? moduleCache[moduleName]);
+
+ if (defined(module)) {
+ return module;
+ }
+
+ if (defined(modulePath)) {
+ // ignore moduleName and use the path to import
if (typeof exports === "object") {
// Use CommonJS-style require.
- /* global require */
- moduleCache[module] = module = require(`Workers/${moduleName}`);
+ module = require(modulePath);
} else {
// Use ESM-style dynamic import
- const result = await import(`./${moduleName}.js`);
+ const result = await import(modulePath);
module = result.default;
- moduleCache[module] = module;
}
+
+ moduleCache[modulePath] = module;
+ return module;
}
+
+ if (typeof exports === "object") {
+ // Use CommonJS-style require.
+ module = require(`Workers/${moduleName}`);
+ } else {
+ // Use ESM-style dynamic import
+ const result = defined(modulePath)
+ ? await import(modulePath)
+ : await import(`./${moduleName}.js`);
+ module = result.default;
+ }
+
+ moduleCache[moduleName] = module;
return module;
}
@@ -30,11 +53,17 @@ async function createGeometry(parameters, transferableObjects) {
const task = subTasks[i];
const geometry = task.geometry;
const moduleName = task.moduleName;
+ const modulePath = task.modulePath;
+
+ if (defined(moduleName) && defined(modulePath)) {
+ throw new DeveloperError("Must only set moduleName or modulePath");
+ }
- if (defined(moduleName)) {
- resultsOrPromises[i] = getModule(moduleName).then((createFunction) =>
- createFunction(geometry, task.offset)
- );
+ if (defined(moduleName) || defined(modulePath)) {
+ resultsOrPromises[i] = getModule(
+ moduleName,
+ modulePath
+ ).then((createFunction) => createFunction(geometry, task.offset));
} else {
// Already created geometry
resultsOrPromises[i] = geometry;
diff --git a/packages/engine/Specs/DataSources/CzmlDataSourceSpec.js b/packages/engine/Specs/DataSources/CzmlDataSourceSpec.js
index cf46759076af..7db764e5982d 100644
--- a/packages/engine/Specs/DataSources/CzmlDataSourceSpec.js
+++ b/packages/engine/Specs/DataSources/CzmlDataSourceSpec.js
@@ -10123,4 +10123,24 @@ describe("DataSources/CzmlDataSource", function () {
expect(e.properties.custom_wsenDegrees.getValue(documentStopDate)).toEqual(Rectangle.fromDegrees(37, 16, 25, 23));
});
});
+
+ it("registers custom updaters", () => {
+ function processFakeEntity() {}
+
+ expect(CzmlDataSource.updaters.length)
+ .withContext("length before register")
+ .toEqual(23);
+
+ CzmlDataSource.registerUpdater(processFakeEntity);
+
+ expect(CzmlDataSource.updaters.length)
+ .withContext("length after register")
+ .toEqual(24);
+ expect(CzmlDataSource.updaters[23]).toEqual(processFakeEntity);
+
+ CzmlDataSource.unregisterUpdater(processFakeEntity);
+ expect(CzmlDataSource.updaters.length)
+ .withContext("length after unregister")
+ .toEqual(23);
+ });
});
diff --git a/packages/engine/Specs/DataSources/DataSourceDisplaySpec.js b/packages/engine/Specs/DataSources/DataSourceDisplaySpec.js
index a37466c6be9f..f0209dfe10be 100644
--- a/packages/engine/Specs/DataSources/DataSourceDisplaySpec.js
+++ b/packages/engine/Specs/DataSources/DataSourceDisplaySpec.js
@@ -9,6 +9,15 @@ import {
Entity,
GroundPolylinePrimitive,
GroundPrimitive,
+ defined,
+ BillboardVisualizer,
+ GeometryVisualizer,
+ LabelVisualizer,
+ ModelVisualizer,
+ Cesium3DTilesetVisualizer,
+ PointVisualizer,
+ PathVisualizer,
+ PolylineVisualizer,
} from "../../index.js";
import createScene from "../../../../Specs/createScene.js";
@@ -39,7 +48,7 @@ describe(
});
afterEach(function () {
- if (!display.isDestroyed()) {
+ if (defined(display) && !display.isDestroyed()) {
display.destroy();
}
dataSourceCollection.removeAll();
@@ -597,6 +606,57 @@ describe(
true
);
});
+
+ it("has expected default visualizers", () => {
+ const dataSource = new MockDataSource();
+ const entityCluster = dataSource.clustering;
+ const callback = DataSourceDisplay.defaultVisualizersCallback(
+ scene,
+ entityCluster,
+ dataSource
+ );
+ expect(callback.length).toEqual(8);
+ expect(callback[0]).toBeInstanceOf(BillboardVisualizer);
+ expect(callback[1]).toBeInstanceOf(GeometryVisualizer);
+ expect(callback[2]).toBeInstanceOf(LabelVisualizer);
+ expect(callback[3]).toBeInstanceOf(ModelVisualizer);
+ expect(callback[4]).toBeInstanceOf(Cesium3DTilesetVisualizer);
+ expect(callback[5]).toBeInstanceOf(PointVisualizer);
+ expect(callback[6]).toBeInstanceOf(PathVisualizer);
+ expect(callback[7]).toBeInstanceOf(PolylineVisualizer);
+ });
+
+ it("registers extra visualizers", () => {
+ function FakeVisualizer() {}
+ const dataSource = new MockDataSource();
+ const entityCluster = dataSource.clustering;
+
+ const callback = DataSourceDisplay.defaultVisualizersCallback(
+ scene,
+ entityCluster,
+ dataSource
+ );
+ expect(callback.length).withContext("length before register").toEqual(8);
+
+ DataSourceDisplay.registerVisualizer(FakeVisualizer);
+ const callback2 = DataSourceDisplay.defaultVisualizersCallback(
+ scene,
+ entityCluster,
+ dataSource
+ );
+ expect(callback2.length).withContext("length after register").toEqual(9);
+ expect(callback2[8]).toBeInstanceOf(FakeVisualizer);
+
+ DataSourceDisplay.unregisterVisualizer(FakeVisualizer);
+ const callback3 = DataSourceDisplay.defaultVisualizersCallback(
+ scene,
+ entityCluster,
+ dataSource
+ );
+ expect(callback3.length)
+ .withContext("length after unregister")
+ .toEqual(8);
+ });
},
"WebGL"
);
diff --git a/packages/engine/Specs/DataSources/GeometryUpdaterSetSpec.js b/packages/engine/Specs/DataSources/GeometryUpdaterSetSpec.js
new file mode 100644
index 000000000000..79da7d2f5a34
--- /dev/null
+++ b/packages/engine/Specs/DataSources/GeometryUpdaterSetSpec.js
@@ -0,0 +1,64 @@
+import createScene from "../../../../Specs/createScene.js";
+import {
+ BoxGeometryUpdater,
+ CorridorGeometryUpdater,
+ CylinderGeometryUpdater,
+ EllipseGeometryUpdater,
+ EllipsoidGeometryUpdater,
+ Entity,
+ Event,
+ GeometryUpdaterSet,
+ PlaneGeometryUpdater,
+ PolygonGeometryUpdater,
+ PolylineVolumeGeometryUpdater,
+ RectangleGeometryUpdater,
+ WallGeometryUpdater,
+} from "../../index.js";
+
+describe("GeometryUpdaterSet", () => {
+ let scene;
+ beforeAll(function () {
+ scene = createScene();
+ });
+
+ afterAll(function () {
+ scene.destroyForSpecs();
+ });
+
+ it("has expected defaults", () => {
+ const updaterSet = new GeometryUpdaterSet(new Entity(), scene);
+
+ expect(updaterSet.updaters.length).toEqual(10);
+ expect(updaterSet.updaters[0]).toBeInstanceOf(BoxGeometryUpdater);
+ expect(updaterSet.updaters[1]).toBeInstanceOf(CylinderGeometryUpdater);
+ expect(updaterSet.updaters[2]).toBeInstanceOf(CorridorGeometryUpdater);
+ expect(updaterSet.updaters[3]).toBeInstanceOf(EllipseGeometryUpdater);
+ expect(updaterSet.updaters[4]).toBeInstanceOf(EllipsoidGeometryUpdater);
+ expect(updaterSet.updaters[5]).toBeInstanceOf(PlaneGeometryUpdater);
+ expect(updaterSet.updaters[6]).toBeInstanceOf(PolygonGeometryUpdater);
+ expect(updaterSet.updaters[7]).toBeInstanceOf(
+ PolylineVolumeGeometryUpdater
+ );
+ expect(updaterSet.updaters[8]).toBeInstanceOf(RectangleGeometryUpdater);
+ expect(updaterSet.updaters[9]).toBeInstanceOf(WallGeometryUpdater);
+ });
+
+ it("registers new updater", () => {
+ function FakeUpdater() {}
+ FakeUpdater.prototype.geometryChanged = new Event();
+
+ GeometryUpdaterSet.registerUpdater(FakeUpdater);
+
+ const updaterSet = new GeometryUpdaterSet(new Entity(), scene);
+
+ expect(updaterSet.updaters.length).toEqual(11);
+ expect(updaterSet.updaters[10]).toBeInstanceOf(FakeUpdater);
+
+ GeometryUpdaterSet.unregisterUpdater(FakeUpdater);
+ const updaterSet2 = new GeometryUpdaterSet(new Entity(), scene);
+
+ expect(updaterSet2.updaters.length)
+ .withContext("length after unregister")
+ .toEqual(10);
+ });
+});
diff --git a/packages/engine/Specs/DataSources/GeometryVisualizerSpec.js b/packages/engine/Specs/DataSources/GeometryVisualizerSpec.js
index 329334097cfa..8b8aae5048a2 100644
--- a/packages/engine/Specs/DataSources/GeometryVisualizerSpec.js
+++ b/packages/engine/Specs/DataSources/GeometryVisualizerSpec.js
@@ -21,6 +21,8 @@ import {
MaterialAppearance,
PerInstanceColorAppearance,
ShadowMode,
+ Event,
+ GeometryUpdaterSet,
} from "../../index.js";
import createDynamicProperty from "../../../../Specs/createDynamicProperty.js";
@@ -1014,6 +1016,24 @@ describe(
visualizer.destroy();
});
});
+
+ it("registers new updater", () => {
+ function FakeUpdater() {}
+ FakeUpdater.prototype.geometryChanged = new Event();
+ const spy = spyOn(GeometryUpdaterSet, "registerUpdater");
+
+ GeometryUpdaterSet.registerUpdater(FakeUpdater);
+ expect(spy).toHaveBeenCalledOnceWith(FakeUpdater);
+ });
+
+ it("unregisters custom updaters", () => {
+ function FakeUpdater() {}
+ FakeUpdater.prototype.geometryChanged = new Event();
+ const spy = spyOn(GeometryUpdaterSet, "unregisterUpdater");
+
+ GeometryUpdaterSet.unregisterUpdater(FakeUpdater);
+ expect(spy).toHaveBeenCalledOnceWith(FakeUpdater);
+ });
},
"WebGL"
);
diff --git a/packages/engine/Specs/Scene/Model/ModelSpec.js b/packages/engine/Specs/Scene/Model/ModelSpec.js
index 1da9e3a50f34..7e9bacb2efed 100644
--- a/packages/engine/Specs/Scene/Model/ModelSpec.js
+++ b/packages/engine/Specs/Scene/Model/ModelSpec.js
@@ -1282,6 +1282,7 @@ describe(
// Renders without style.
let original;
+ verifyRender(model, true);
expect(renderOptions).toRenderAndCall(function (rgba) {
original = rgba;
});
@@ -1292,6 +1293,7 @@ describe(
});
model.style = style;
+ verifyRender(model, true);
expect(renderOptions).toRenderAndCall(function (rgba) {
expect(rgba[0]).toEqual(original[0]);
expect(rgba[1]).toBeLessThan(original[1]);
@@ -1305,6 +1307,7 @@ describe(
});
model.style = style;
+ verifyRender(model, true);
expect(renderOptions).toRenderAndCall(function (rgba) {
expect(rgba[0]).toBeLessThan(original[0]);
expect(rgba[1]).toBeLessThan(original[1]);
diff --git a/packages/engine/Specs/Scene/SceneSpec.js b/packages/engine/Specs/Scene/SceneSpec.js
index ce22169ec504..082c3e1dce7e 100644
--- a/packages/engine/Specs/Scene/SceneSpec.js
+++ b/packages/engine/Specs/Scene/SceneSpec.js
@@ -127,79 +127,93 @@ describe(
});
}
- it("constructor has expected defaults", function () {
- expect(scene.canvas).toBeInstanceOf(HTMLCanvasElement);
- expect(scene.primitives).toBeInstanceOf(PrimitiveCollection);
- expect(scene.camera).toBeInstanceOf(Camera);
- expect(scene.screenSpaceCameraController).toBeInstanceOf(
- ScreenSpaceCameraController
- );
- expect(scene.mapProjection).toBeInstanceOf(GeographicProjection);
- expect(scene.frameState).toBeInstanceOf(FrameState);
- expect(scene.tweens).toBeInstanceOf(TweenCollection);
-
- const contextAttributes = scene.context._gl.getContextAttributes();
- // Do not check depth and antialias since they are requests not requirements
- expect(contextAttributes.alpha).toEqual(false);
- expect(contextAttributes.stencil).toEqual(true);
- expect(contextAttributes.premultipliedAlpha).toEqual(true);
- expect(contextAttributes.preserveDrawingBuffer).toEqual(false);
- expect(scene._depthPlane._ellipsoidOffset).toEqual(0);
- });
-
- it("constructor sets options", function () {
- const webglOptions = {
- alpha: true,
- depth: false,
- stencil: true,
- antialias: false,
- premultipliedAlpha: false,
- preserveDrawingBuffer: true,
- };
- const mapProjection = new WebMercatorProjection();
+ describe("constructor", () => {
+ it("has expected defaults", function () {
+ expect(scene.canvas).toBeInstanceOf(HTMLCanvasElement);
+ expect(scene.primitives).toBeInstanceOf(PrimitiveCollection);
+ expect(scene.camera).toBeInstanceOf(Camera);
+ expect(scene.screenSpaceCameraController).toBeInstanceOf(
+ ScreenSpaceCameraController
+ );
+ expect(scene.mapProjection).toBeInstanceOf(GeographicProjection);
+ expect(scene.frameState).toBeInstanceOf(FrameState);
+ expect(scene.tweens).toBeInstanceOf(TweenCollection);
- const s = createScene({
- contextOptions: {
- webgl: webglOptions,
- },
- mapProjection: mapProjection,
- depthPlaneEllipsoidOffset: Number.POSITIVE_INFINITY,
+ const contextAttributes = scene.context._gl.getContextAttributes();
+ // Do not check depth and antialias since they are requests not requirements
+ expect(contextAttributes.alpha).toEqual(false);
+ expect(contextAttributes.stencil).toEqual(true);
+ expect(contextAttributes.premultipliedAlpha).toEqual(true);
+ expect(contextAttributes.preserveDrawingBuffer).toEqual(false);
+ expect(scene._depthPlane._ellipsoidOffset).toEqual(0);
});
- const contextAttributes = s.context._gl.getContextAttributes();
- expect(contextAttributes.alpha).toEqual(webglOptions.alpha);
- expect(contextAttributes.depth).toEqual(webglOptions.depth);
- expect(contextAttributes.stencil).toEqual(webglOptions.stencil);
- expect(contextAttributes.antialias).toEqual(webglOptions.antialias);
- expect(contextAttributes.premultipliedAlpha).toEqual(
- webglOptions.premultipliedAlpha
- );
- expect(contextAttributes.preserveDrawingBuffer).toEqual(
- webglOptions.preserveDrawingBuffer
- );
- expect(s.mapProjection).toEqual(mapProjection);
- expect(s._depthPlane._ellipsoidOffset).toEqual(Number.POSITIVE_INFINITY);
+ it("respects default log depth buffer override", () => {
+ const previous = Scene.defaultLogDepthBuffer;
- s.destroyForSpecs();
- });
+ Scene.defaultLogDepthBuffer = false;
+ const newScene = createScene();
+ expect(newScene._logDepthBuffer).toEqual(false);
- it("constructor throws without options", function () {
- expect(function () {
- return new Scene();
- }).toThrowDeveloperError();
- });
+ Scene.defaultLogDepthBuffer = previous;
+ });
- it("constructor throws without options.canvas", function () {
- expect(function () {
- return new Scene({});
- }).toThrowDeveloperError();
- });
+ it("sets options", function () {
+ const webglOptions = {
+ alpha: true,
+ depth: false,
+ stencil: true,
+ antialias: false,
+ premultipliedAlpha: false,
+ preserveDrawingBuffer: true,
+ };
+ const mapProjection = new WebMercatorProjection();
+
+ const s = createScene({
+ contextOptions: {
+ webgl: webglOptions,
+ },
+ mapProjection: mapProjection,
+ depthPlaneEllipsoidOffset: Number.POSITIVE_INFINITY,
+ });
- it("draws background color", function () {
- expect(scene).toRender([0, 0, 0, 255]);
+ const contextAttributes = s.context._gl.getContextAttributes();
+ expect(contextAttributes.alpha).toEqual(webglOptions.alpha);
+ expect(contextAttributes.depth).toEqual(webglOptions.depth);
+ expect(contextAttributes.stencil).toEqual(webglOptions.stencil);
+ expect(contextAttributes.antialias).toEqual(webglOptions.antialias);
+ expect(contextAttributes.premultipliedAlpha).toEqual(
+ webglOptions.premultipliedAlpha
+ );
+ expect(contextAttributes.preserveDrawingBuffer).toEqual(
+ webglOptions.preserveDrawingBuffer
+ );
+ expect(s.mapProjection).toEqual(mapProjection);
+ expect(s._depthPlane._ellipsoidOffset).toEqual(
+ Number.POSITIVE_INFINITY
+ );
- scene.backgroundColor = Color.BLUE;
- expect(scene).toRender([0, 0, 255, 255]);
+ s.destroyForSpecs();
+ });
+
+ it("throws without options", function () {
+ expect(function () {
+ return new Scene();
+ }).toThrowDeveloperError();
+ });
+
+ it("throws without options.canvas", function () {
+ expect(function () {
+ return new Scene({});
+ }).toThrowDeveloperError();
+ });
+
+ it("draws background color", function () {
+ expect(scene).toRender([0, 0, 0, 255]);
+
+ scene.backgroundColor = Color.BLUE;
+ expect(scene).toRender([0, 0, 255, 255]);
+ });
});
it("calls afterRender functions", function () {