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 knockout from "../../ThirdParty/knockout.js"; import getElement from "../getElement.js"; import InspectorShared from "../InspectorShared.js"; import Cesium3DTilesInspectorViewModel from "./Cesium3DTilesInspectorViewModel.js"; /** * Inspector widget to aid in debugging 3D Tiles * * @alias Cesium3DTilesInspector * @constructor * * @param {Element|String} container The DOM element or ID that will contain the widget. * @param {Scene} scene the Scene instance to use. */ function Cesium3DTilesInspector(container, scene) { //>>includeStart('debug', pragmas.debug); Check.defined("container", container); Check.typeOf.object("scene", scene); //>>includeEnd('debug'); container = getElement(container); const element = document.createElement("div"); const performanceContainer = document.createElement("div"); performanceContainer.setAttribute("data-bind", "visible: performance"); const viewModel = new Cesium3DTilesInspectorViewModel( scene, performanceContainer ); this._viewModel = viewModel; this._container = container; this._element = element; const text = document.createElement("div"); text.textContent = "3D Tiles Inspector"; text.className = "cesium-cesiumInspector-button"; text.setAttribute("data-bind", "click: toggleInspector"); element.appendChild(text); element.className = "cesium-cesiumInspector cesium-3DTilesInspector"; element.setAttribute( "data-bind", 'css: { "cesium-cesiumInspector-visible" : inspectorVisible, "cesium-cesiumInspector-hidden" : !inspectorVisible}' ); container.appendChild(element); const panel = document.createElement("div"); this._panel = panel; panel.className = "cesium-cesiumInspector-dropDown"; element.appendChild(panel); const createSection = InspectorShared.createSection; const createCheckbox = InspectorShared.createCheckbox; const tilesetPanelContents = createSection( panel, "Tileset", "tilesetVisible", "toggleTileset" ); const displayPanelContents = createSection( panel, "Display", "displayVisible", "toggleDisplay" ); const updatePanelContents = createSection( panel, "Update", "updateVisible", "toggleUpdate" ); const loggingPanelContents = createSection( panel, "Logging", "loggingVisible", "toggleLogging" ); const tileDebugLabelsPanelContents = createSection( panel, "Tile Debug Labels", "tileDebugLabelsVisible", "toggleTileDebugLabels" ); const stylePanelContents = createSection( panel, "Style", "styleVisible", "toggleStyle" ); const optimizationPanelContents = createSection( panel, "Optimization", "optimizationVisible", "toggleOptimization" ); const properties = document.createElement("div"); properties.className = "field-group"; const propertiesLabel = document.createElement("label"); propertiesLabel.className = "field-label"; propertiesLabel.appendChild(document.createTextNode("Properties: ")); const propertiesField = document.createElement("div"); propertiesField.setAttribute("data-bind", "text: properties"); properties.appendChild(propertiesLabel); properties.appendChild(propertiesField); tilesetPanelContents.appendChild(properties); tilesetPanelContents.appendChild( makeButton("togglePickTileset", "Pick Tileset", "pickActive") ); tilesetPanelContents.appendChild( makeButton("trimTilesCache", "Trim Tiles Cache") ); tilesetPanelContents.appendChild(createCheckbox("Enable Picking", "picking")); displayPanelContents.appendChild(createCheckbox("Colorize", "colorize")); displayPanelContents.appendChild(createCheckbox("Wireframe", "wireframe")); displayPanelContents.appendChild( createCheckbox("Bounding Volumes", "showBoundingVolumes") ); displayPanelContents.appendChild( createCheckbox("Content Volumes", "showContentBoundingVolumes") ); displayPanelContents.appendChild( createCheckbox("Request Volumes", "showRequestVolumes") ); displayPanelContents.appendChild( createCheckbox("Point Cloud Shading", "pointCloudShading") ); const pointCloudShadingContainer = document.createElement("div"); pointCloudShadingContainer.setAttribute( "data-bind", "visible: pointCloudShading" ); pointCloudShadingContainer.appendChild( makeRangeInput("geometricErrorScale", 0, 2, 0.01, "Geometric Error Scale") ); pointCloudShadingContainer.appendChild( makeRangeInput("maximumAttenuation", 0, 32, 1, "Maximum Attenuation") ); pointCloudShadingContainer.appendChild( makeRangeInput("baseResolution", 0, 1, 0.01, "Base Resolution") ); pointCloudShadingContainer.appendChild( createCheckbox("Eye Dome Lighting (EDL)", "eyeDomeLighting") ); displayPanelContents.appendChild(pointCloudShadingContainer); const edlContainer = document.createElement("div"); edlContainer.setAttribute("data-bind", "visible: eyeDomeLighting"); edlContainer.appendChild( makeRangeInput("eyeDomeLightingStrength", 0, 2.0, 0.1, "EDL Strength") ); edlContainer.appendChild( makeRangeInput("eyeDomeLightingRadius", 0, 4.0, 0.1, "EDL Radius") ); pointCloudShadingContainer.appendChild(edlContainer); updatePanelContents.appendChild( createCheckbox("Freeze Frame", "freezeFrame") ); updatePanelContents.appendChild( createCheckbox("Dynamic Screen Space Error", "dynamicScreenSpaceError") ); const sseContainer = document.createElement("div"); sseContainer.appendChild( makeRangeInput( "maximumScreenSpaceError", 0, 128, 1, "Maximum Screen Space Error" ) ); updatePanelContents.appendChild(sseContainer); const dynamicScreenSpaceErrorContainer = document.createElement("div"); dynamicScreenSpaceErrorContainer.setAttribute( "data-bind", "visible: dynamicScreenSpaceError" ); dynamicScreenSpaceErrorContainer.appendChild( makeRangeInput( "dynamicScreenSpaceErrorDensitySliderValue", 0, 1, 0.005, "Screen Space Error Density", "dynamicScreenSpaceErrorDensity" ) ); dynamicScreenSpaceErrorContainer.appendChild( makeRangeInput( "dynamicScreenSpaceErrorFactor", 1, 10, 0.1, "Screen Space Error Factor" ) ); updatePanelContents.appendChild(dynamicScreenSpaceErrorContainer); loggingPanelContents.appendChild( createCheckbox("Performance", "performance") ); loggingPanelContents.appendChild(performanceContainer); loggingPanelContents.appendChild( createCheckbox("Statistics", "showStatistics") ); const statistics = document.createElement("div"); statistics.className = "cesium-3dTilesInspector-statistics"; statistics.setAttribute( "data-bind", "html: statisticsText, visible: showStatistics" ); loggingPanelContents.appendChild(statistics); loggingPanelContents.appendChild( createCheckbox("Pick Statistics", "showPickStatistics") ); const pickStatistics = document.createElement("div"); pickStatistics.className = "cesium-3dTilesInspector-statistics"; pickStatistics.setAttribute( "data-bind", "html: pickStatisticsText, visible: showPickStatistics" ); loggingPanelContents.appendChild(pickStatistics); const stylePanelEditor = document.createElement("div"); stylePanelContents.appendChild(stylePanelEditor); stylePanelEditor.appendChild(document.createTextNode("Color Blend Mode: ")); const blendDropdown = document.createElement("select"); blendDropdown.setAttribute( "data-bind", "options: colorBlendModes, " + 'optionsText: "text", ' + 'optionsValue: "value", ' + "value: colorBlendMode" ); stylePanelEditor.appendChild(blendDropdown); const styleEditor = document.createElement("textarea"); styleEditor.setAttribute( "data-bind", "textInput: styleString, event: { keydown: styleEditorKeyPress }" ); stylePanelEditor.className = "cesium-cesiumInspector-styleEditor"; stylePanelEditor.appendChild(styleEditor); const closeStylesBtn = makeButton("compileStyle", "Compile (Ctrl+Enter)"); stylePanelEditor.appendChild(closeStylesBtn); const errorBox = document.createElement("div"); errorBox.className = "cesium-cesiumInspector-error"; errorBox.setAttribute("data-bind", "text: editorError"); stylePanelEditor.appendChild(errorBox); tileDebugLabelsPanelContents.appendChild( createCheckbox("Show Picked Only", "showOnlyPickedTileDebugLabel") ); tileDebugLabelsPanelContents.appendChild( createCheckbox("Geometric Error", "showGeometricError") ); tileDebugLabelsPanelContents.appendChild( createCheckbox("Rendering Statistics", "showRenderingStatistics") ); tileDebugLabelsPanelContents.appendChild( createCheckbox("Memory Usage (MB)", "showMemoryUsage") ); tileDebugLabelsPanelContents.appendChild(createCheckbox("Url", "showUrl")); optimizationPanelContents.appendChild( createCheckbox("Skip Tile LODs", "skipLevelOfDetail") ); const skipScreenSpaceErrorFactorContainer = document.createElement("div"); skipScreenSpaceErrorFactorContainer.appendChild( makeRangeInput("skipScreenSpaceErrorFactor", 1, 50, 1, "Skip SSE Factor") ); optimizationPanelContents.appendChild(skipScreenSpaceErrorFactorContainer); const baseScreenSpaceError = document.createElement("div"); baseScreenSpaceError.appendChild( makeRangeInput( "baseScreenSpaceError", 0, 4096, 1, "SSE before skipping LOD" ) ); optimizationPanelContents.appendChild(baseScreenSpaceError); const skipLevelsContainer = document.createElement("div"); skipLevelsContainer.appendChild( makeRangeInput("skipLevels", 0, 10, 1, "Min. levels to skip") ); optimizationPanelContents.appendChild(skipLevelsContainer); optimizationPanelContents.appendChild( createCheckbox( "Load only tiles that meet the max SSE.", "immediatelyLoadDesiredLevelOfDetail" ) ); optimizationPanelContents.appendChild( createCheckbox("Load siblings of visible tiles", "loadSiblings") ); knockout.applyBindings(viewModel, element); } Object.defineProperties(Cesium3DTilesInspector.prototype, { /** * Gets the parent container. * @memberof Cesium3DTilesInspector.prototype * * @type {Element} */ container: { get: function () { return this._container; }, }, /** * Gets the view model. * @memberof Cesium3DTilesInspector.prototype * * @type {Cesium3DTilesInspectorViewModel} */ viewModel: { get: function () { return this._viewModel; }, }, }); /** * @returns {Boolean} true if the object has been destroyed, false otherwise. */ Cesium3DTilesInspector.prototype.isDestroyed = function () { return false; }; /** * Destroys the widget. Should be called if permanently * removing the widget from layout. */ Cesium3DTilesInspector.prototype.destroy = function () { knockout.cleanNode(this._element); this._container.removeChild(this._element); this.viewModel.destroy(); return destroyObject(this); }; function makeRangeInput(property, min, max, step, text, displayProperty) { displayProperty = defaultValue(displayProperty, property); const input = document.createElement("input"); input.setAttribute("data-bind", `value: ${displayProperty}`); input.type = "number"; const slider = document.createElement("input"); slider.type = "range"; slider.min = min; slider.max = max; slider.step = step; slider.setAttribute("data-bind", `valueUpdate: "input", value: ${property}`); const wrapper = document.createElement("div"); wrapper.appendChild(slider); const container = document.createElement("div"); container.className = "cesium-cesiumInspector-slider"; container.appendChild(document.createTextNode(text)); container.appendChild(input); container.appendChild(wrapper); return container; } function makeButton(action, text, active) { const button = document.createElement("button"); button.type = "button"; button.textContent = text; button.className = "cesium-cesiumInspector-pickButton"; let binding = `click: ${action}`; if (defined(active)) { binding += `, css: {"cesium-cesiumInspector-pickButtonHighlight" : ${active}}`; } button.setAttribute("data-bind", binding); return button; } export default Cesium3DTilesInspector;