babylon.debugLayer.ts 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. module BABYLON {
  2. export class DebugLayer {
  3. private _scene: Scene;
  4. private _enabled: boolean = false;
  5. private _labelsEnabled: boolean = false;
  6. private _displayStatistics = true;
  7. private _displayTree = false;
  8. private _displayLogs = false;
  9. private _globalDiv: HTMLDivElement;
  10. private _statsDiv: HTMLDivElement;
  11. private _statsSubsetDiv: HTMLDivElement;
  12. private _optionsDiv: HTMLDivElement;
  13. private _optionsSubsetDiv: HTMLDivElement;
  14. private _logDiv: HTMLDivElement;
  15. private _logSubsetDiv: HTMLDivElement;
  16. private _treeDiv: HTMLDivElement;
  17. private _treeSubsetDiv: HTMLDivElement;
  18. private _drawingCanvas: HTMLCanvasElement;
  19. private _drawingContext: CanvasRenderingContext2D;
  20. private _syncPositions: () => void;
  21. private _syncData: () => void;
  22. private _onCanvasClick: (evt: MouseEvent) => void;
  23. private _clickPosition: any;
  24. private _ratio: number;
  25. private _identityMatrix = Matrix.Identity();
  26. private _showUI: boolean;
  27. private _needToRefreshMeshesTree: boolean;
  28. public shouldDisplayLabel: (node: Node) => boolean;
  29. public shouldDisplayAxis: (mesh: Mesh) => boolean;
  30. public axisRatio = 0.02;
  31. constructor(scene: Scene) {
  32. this._scene = scene;
  33. this._syncPositions = (): void => {
  34. var engine = this._scene.getEngine();
  35. var canvasRect = engine.getRenderingCanvasClientRect();
  36. if (this._showUI) {
  37. this._statsDiv.style.right = "0";
  38. this._statsDiv.style.bottom = "10px";
  39. this._statsDiv.style.width = "300px";
  40. this._statsDiv.style.height = "auto";
  41. this._statsSubsetDiv.style.maxHeight = (canvasRect.height - 60) + "px";
  42. this._optionsDiv.style.left = "0px";
  43. this._optionsDiv.style.top = "10px";
  44. this._optionsDiv.style.width = "200px";
  45. this._optionsDiv.style.height = "auto";
  46. this._optionsSubsetDiv.style.maxHeight = (canvasRect.height * 0.6) + "px";
  47. this._logDiv.style.left = "0px";
  48. this._logDiv.style.bottom = "10px";
  49. this._logDiv.style.width = "600px";
  50. this._logDiv.style.height = "auto";
  51. this._treeDiv.style.right = "0px";
  52. this._treeDiv.style.top = "10px";
  53. this._treeDiv.style.width = "300px";
  54. this._treeDiv.style.height = "auto";
  55. }
  56. this._globalDiv.style.left = canvasRect.left + "px";
  57. this._globalDiv.style.top = canvasRect.top + "px";
  58. this._globalDiv.style.width = canvasRect.width + "px";
  59. this._globalDiv.style.height = canvasRect.height + "px";
  60. this._drawingCanvas.style.left = "0px";
  61. this._drawingCanvas.style.top = "0px";
  62. this._drawingCanvas.style.width = engine.getRenderWidth() + "px";
  63. this._drawingCanvas.style.height = engine.getRenderHeight() + "px";
  64. var devicePixelRatio = window.devicePixelRatio || 1;
  65. var context = <any>this._drawingContext;
  66. var backingStoreRatio = context.webkitBackingStorePixelRatio ||
  67. context.mozBackingStorePixelRatio ||
  68. context.msBackingStorePixelRatio ||
  69. context.oBackingStorePixelRatio ||
  70. context.backingStorePixelRatio || 1;
  71. this._ratio = devicePixelRatio / backingStoreRatio;
  72. this._drawingCanvas.width = engine.getRenderWidth() * this._ratio;
  73. this._drawingCanvas.height = engine.getRenderHeight() * this._ratio;
  74. }
  75. this._onCanvasClick = (evt: MouseEvent): void => {
  76. this._clickPosition = {
  77. x: evt.clientX * this._ratio,
  78. y: evt.clientY * this._ratio
  79. };
  80. }
  81. this._syncData = (): void => {
  82. if (this._showUI) {
  83. if (this._displayStatistics) {
  84. this._displayStats();
  85. this._statsDiv.style.display = "";
  86. } else {
  87. this._statsDiv.style.display = "none";
  88. }
  89. if (this._displayLogs) {
  90. this._logDiv.style.display = "";
  91. } else {
  92. this._logDiv.style.display = "none";
  93. }
  94. if (this._displayTree) {
  95. this._treeDiv.style.display = "";
  96. if (this._needToRefreshMeshesTree) {
  97. this._needToRefreshMeshesTree = false;
  98. this._refreshMeshesTreeContent();
  99. }
  100. } else {
  101. this._treeDiv.style.display = "none";
  102. }
  103. }
  104. if (this._labelsEnabled || !this._showUI) {
  105. this._drawingContext.clearRect(0, 0, this._drawingCanvas.width, this._drawingCanvas.height);
  106. var engine = this._scene.getEngine();
  107. var viewport = this._scene.activeCamera.viewport;
  108. var globalViewport = viewport.toGlobal(engine);
  109. // Meshes
  110. var meshes = this._scene.getActiveMeshes();
  111. for (var index = 0; index < meshes.length; index++) {
  112. var mesh = meshes.data[index];
  113. var position = mesh.getBoundingInfo().boundingSphere.center;
  114. var projectedPosition = Vector3.Project(position, mesh.getWorldMatrix(), this._scene.getTransformMatrix(), globalViewport);
  115. if (mesh.renderOverlay || this.shouldDisplayAxis && this.shouldDisplayAxis(mesh)) {
  116. this._renderAxis(projectedPosition, mesh, globalViewport);
  117. }
  118. if (!this.shouldDisplayLabel || this.shouldDisplayLabel(mesh)) {
  119. this._renderLabel(mesh.name, projectedPosition, 12,
  120. () => { mesh.renderOverlay = !mesh.renderOverlay },
  121. () => { return mesh.renderOverlay ? 'red' : 'black'; });
  122. }
  123. }
  124. // Cameras
  125. var cameras = this._scene.cameras;
  126. for (index = 0; index < cameras.length; index++) {
  127. var camera = cameras[index];
  128. if (camera === this._scene.activeCamera) {
  129. continue;
  130. }
  131. projectedPosition = Vector3.Project(camera.position, this._identityMatrix, this._scene.getTransformMatrix(), globalViewport);
  132. if (!this.shouldDisplayLabel || this.shouldDisplayLabel(camera)) {
  133. this._renderLabel(camera.name, projectedPosition, 12,
  134. () => {
  135. this._scene.activeCamera.detachControl(engine.getRenderingCanvas());
  136. this._scene.activeCamera = camera;
  137. this._scene.activeCamera.attachControl(engine.getRenderingCanvas());
  138. },
  139. () => { return "purple"; });
  140. }
  141. }
  142. // Lights
  143. var lights = this._scene.lights;
  144. for (index = 0; index < lights.length; index++) {
  145. var light = <any>lights[index];
  146. if (light.position) {
  147. projectedPosition = Vector3.Project(light.position, this._identityMatrix, this._scene.getTransformMatrix(), globalViewport);
  148. if (!this.shouldDisplayLabel || this.shouldDisplayLabel(light)) {
  149. this._renderLabel(light.name, projectedPosition, -20,
  150. () => {
  151. light.setEnabled(!light.isEnabled());
  152. },
  153. () => { return light.isEnabled() ? "orange" : "gray"; });
  154. }
  155. }
  156. }
  157. }
  158. this._clickPosition = undefined;
  159. }
  160. }
  161. private _refreshMeshesTreeContent(): void {
  162. // Add meshes
  163. var sortedArray = this._scene.meshes.slice(0, this._scene.meshes.length);
  164. sortedArray.sort((a, b) => {
  165. if (a.name === b.name) {
  166. return 0;
  167. }
  168. return (a.name > b.name) ? 1 : -1;
  169. });
  170. for (var index = 0; index < sortedArray.length; index++) {
  171. var mesh = sortedArray[index];
  172. if (!mesh.isEnabled()) {
  173. continue;
  174. }
  175. this._generateAdvancedCheckBox(this._treeSubsetDiv, mesh.name, mesh.getTotalVertices() + " verts", mesh.isVisible, (element, mesh) => {
  176. mesh.isVisible = element.checked;
  177. }, mesh);
  178. }
  179. }
  180. private _renderSingleAxis(zero: Vector3, unit: Vector3, unitText: Vector3, label: string, color: string) {
  181. this._drawingContext.beginPath();
  182. this._drawingContext.moveTo(zero.x, zero.y);
  183. this._drawingContext.lineTo(unit.x, unit.y);
  184. this._drawingContext.strokeStyle = color;
  185. this._drawingContext.lineWidth = 4;
  186. this._drawingContext.stroke();
  187. this._drawingContext.font = "normal 14px Segoe UI";
  188. this._drawingContext.fillStyle = color;
  189. this._drawingContext.fillText(label, unitText.x, unitText.y);
  190. }
  191. private _renderAxis(projectedPosition: Vector3, mesh: Mesh, globalViewport: Viewport) {
  192. var position = mesh.getBoundingInfo().boundingSphere.center;
  193. var worldMatrix = mesh.getWorldMatrix();
  194. var unprojectedVector = Vector3.UnprojectFromTransform(projectedPosition.add(new Vector3(this._drawingCanvas.width * this.axisRatio, 0, 0)), globalViewport.width, globalViewport.height, worldMatrix, this._scene.getTransformMatrix());
  195. var unit = (unprojectedVector.subtract(position)).length();
  196. var xAxis = Vector3.Project(position.add(new Vector3(unit, 0, 0)), worldMatrix, this._scene.getTransformMatrix(), globalViewport);
  197. var xAxisText = Vector3.Project(position.add(new Vector3(unit * 1.5, 0, 0)), worldMatrix, this._scene.getTransformMatrix(), globalViewport);
  198. this._renderSingleAxis(projectedPosition, xAxis, xAxisText, "x", "#FF0000");
  199. var yAxis = Vector3.Project(position.add(new Vector3(0, unit, 0)), worldMatrix, this._scene.getTransformMatrix(), globalViewport);
  200. var yAxisText = Vector3.Project(position.add(new Vector3(0, unit * 1.5, 0)), worldMatrix, this._scene.getTransformMatrix(), globalViewport);
  201. this._renderSingleAxis(projectedPosition, yAxis, yAxisText, "y", "#00FF00");
  202. var zAxis = Vector3.Project(position.add(new Vector3(0, 0, unit)), worldMatrix, this._scene.getTransformMatrix(), globalViewport);
  203. var zAxisText = Vector3.Project(position.add(new Vector3(0, 0, unit * 1.5)), worldMatrix, this._scene.getTransformMatrix(), globalViewport);
  204. this._renderSingleAxis(projectedPosition, zAxis, zAxisText, "z", "#0000FF");
  205. }
  206. private _renderLabel(text: string, projectedPosition: Vector3, labelOffset: number, onClick: () => void, getFillStyle: () => string): void {
  207. if (projectedPosition.z > 0 && projectedPosition.z < 1.0) {
  208. this._drawingContext.font = "normal 12px Segoe UI";
  209. var textMetrics = this._drawingContext.measureText(text);
  210. var centerX = projectedPosition.x - textMetrics.width / 2;
  211. var centerY = projectedPosition.y;
  212. if (this._isClickInsideRect(centerX - 5, centerY - labelOffset - 12, textMetrics.width + 10, 17)) {
  213. onClick();
  214. }
  215. this._drawingContext.beginPath();
  216. this._drawingContext.rect(centerX - 5, centerY - labelOffset - 12, textMetrics.width + 10, 17);
  217. this._drawingContext.fillStyle = getFillStyle();
  218. this._drawingContext.globalAlpha = 0.5;
  219. this._drawingContext.fill();
  220. this._drawingContext.globalAlpha = 1.0;
  221. this._drawingContext.strokeStyle = '#FFFFFF';
  222. this._drawingContext.lineWidth = 1;
  223. this._drawingContext.stroke();
  224. this._drawingContext.fillStyle = "#FFFFFF";
  225. this._drawingContext.fillText(text, centerX, centerY - labelOffset);
  226. this._drawingContext.beginPath();
  227. this._drawingContext.arc(projectedPosition.x, centerY, 5, 0, 2 * Math.PI, false);
  228. this._drawingContext.fill();
  229. }
  230. }
  231. private _isClickInsideRect(x: number, y: number, width: number, height: number): boolean {
  232. if (!this._clickPosition) {
  233. return false;
  234. }
  235. if (this._clickPosition.x < x || this._clickPosition.x > x + width) {
  236. return false;
  237. }
  238. if (this._clickPosition.y < y || this._clickPosition.y > y + height) {
  239. return false;
  240. }
  241. return true;
  242. }
  243. public isVisible(): boolean {
  244. return this._enabled;
  245. }
  246. public hide() {
  247. if (!this._enabled) {
  248. return;
  249. }
  250. this._enabled = false;
  251. var engine = this._scene.getEngine();
  252. var parentElement = engine.getRenderingCanvas().parentElement;
  253. this._scene.unregisterAfterRender(this._syncData);
  254. parentElement.removeChild(this._globalDiv);
  255. window.removeEventListener("resize", this._syncPositions);
  256. this._scene.forceShowBoundingBoxes = false;
  257. this._scene.forceWireframe = false;
  258. StandardMaterial.DiffuseTextureEnabled = true;
  259. StandardMaterial.AmbientTextureEnabled = true;
  260. StandardMaterial.SpecularTextureEnabled = true;
  261. StandardMaterial.EmissiveTextureEnabled = true;
  262. StandardMaterial.BumpTextureEnabled = true;
  263. StandardMaterial.OpacityTextureEnabled = true;
  264. StandardMaterial.ReflectionTextureEnabled = true;
  265. this._scene.shadowsEnabled = true;
  266. this._scene.particlesEnabled = true;
  267. this._scene.postProcessesEnabled = true;
  268. this._scene.collisionsEnabled = true;
  269. this._scene.lightsEnabled = true;
  270. this._scene.texturesEnabled = true;
  271. this._scene.lensFlaresEnabled = true;
  272. this._scene.proceduralTexturesEnabled = true;
  273. this._scene.renderTargetsEnabled = true;
  274. engine.getRenderingCanvas().removeEventListener("click", this._onCanvasClick);
  275. }
  276. public show(showUI: boolean = true) {
  277. if (this._enabled) {
  278. return;
  279. }
  280. this._enabled = true;
  281. this._showUI = showUI;
  282. var engine = this._scene.getEngine();
  283. this._scene.registerAfterRender(this._syncData);
  284. this._globalDiv = document.createElement("div");
  285. document.body.appendChild(this._globalDiv);
  286. this._generateDOMelements();
  287. window.addEventListener("resize", this._syncPositions);
  288. engine.getRenderingCanvas().addEventListener("click", this._onCanvasClick);
  289. this._syncPositions();
  290. }
  291. private _clearLabels(): void {
  292. this._drawingContext.clearRect(0, 0, this._drawingCanvas.width, this._drawingCanvas.height);
  293. for (var index = 0; index < this._scene.meshes.length; index++) {
  294. var mesh = this._scene.meshes[index];
  295. mesh.renderOverlay = false;
  296. }
  297. }
  298. private _generateheader(root: HTMLDivElement, text: string): void {
  299. var header = document.createElement("div");
  300. header.innerHTML = text + "&nbsp;";
  301. header.style.textAlign = "right";
  302. header.style.width = "100%";
  303. header.style.color = "white";
  304. header.style.backgroundColor = "Black";
  305. header.style.padding = "5px 5px 4px 0px";
  306. header.style.marginLeft = "-5px";
  307. root.appendChild(header);
  308. }
  309. private _generateTexBox(root: HTMLDivElement, title: string): void {
  310. var label = document.createElement("label");
  311. label.innerHTML = title;
  312. root.appendChild(label);
  313. root.appendChild(document.createElement("br"));
  314. }
  315. private _generateAdvancedCheckBox(root: HTMLDivElement, leftTitle: string, rightTitle: string, initialState: boolean, task: (element, tag) => void, tag: any = null): void {
  316. var label = document.createElement("label");
  317. var boundingBoxesCheckbox = document.createElement("input");
  318. boundingBoxesCheckbox.type = "checkbox";
  319. boundingBoxesCheckbox.checked = initialState;
  320. boundingBoxesCheckbox.addEventListener("change", (evt: Event) => {
  321. task(evt.target, tag);
  322. });
  323. label.appendChild(boundingBoxesCheckbox);
  324. var container = document.createElement("span");
  325. var leftPart = document.createElement("span");
  326. var rightPart = document.createElement("span");
  327. rightPart.style.cssFloat = "right";
  328. leftPart.innerHTML = leftTitle;
  329. rightPart.innerHTML = rightTitle;
  330. container.appendChild(leftPart);
  331. container.appendChild(rightPart);
  332. label.appendChild(container);
  333. root.appendChild(label);
  334. root.appendChild(document.createElement("br"));
  335. }
  336. private _generateCheckBox(root: HTMLDivElement, title: string, initialState: boolean, task: (element, tag) => void, tag: any = null): void {
  337. var label = document.createElement("label");
  338. var boundingBoxesCheckbox = document.createElement("input");
  339. boundingBoxesCheckbox.type = "checkbox";
  340. boundingBoxesCheckbox.checked = initialState;
  341. boundingBoxesCheckbox.addEventListener("change", (evt: Event) => {
  342. task(evt.target, tag);
  343. });
  344. label.appendChild(boundingBoxesCheckbox);
  345. label.appendChild(document.createTextNode(title));
  346. root.appendChild(label);
  347. root.appendChild(document.createElement("br"));
  348. }
  349. private _generateRadio(root: HTMLDivElement, title: string, name: string, initialState: boolean, task: (element, tag) => void, tag: any = null): void {
  350. var label = document.createElement("label");
  351. var boundingBoxesRadio = document.createElement("input");
  352. boundingBoxesRadio.type = "radio";
  353. boundingBoxesRadio.name = name;
  354. boundingBoxesRadio.checked = initialState;
  355. boundingBoxesRadio.addEventListener("change", (evt: Event) => {
  356. task(evt.target, tag);
  357. });
  358. label.appendChild(boundingBoxesRadio);
  359. label.appendChild(document.createTextNode(title));
  360. root.appendChild(label);
  361. root.appendChild(document.createElement("br"));
  362. }
  363. private _generateDOMelements(): void {
  364. this._globalDiv.id = "DebugLayer";
  365. this._globalDiv.style.position = "absolute";
  366. // Drawing canvas
  367. this._drawingCanvas = document.createElement("canvas");
  368. this._drawingCanvas.id = "DebugLayerDrawingCanvas";
  369. this._drawingCanvas.style.position = "absolute";
  370. this._drawingCanvas.style.pointerEvents = "none";
  371. this._drawingContext = this._drawingCanvas.getContext("2d");
  372. this._globalDiv.appendChild(this._drawingCanvas);
  373. if (this._showUI) {
  374. var background = "rgba(128, 128, 128, 0.4)";
  375. var border = "rgb(180, 180, 180) solid 1px";
  376. // Stats
  377. this._statsDiv = document.createElement("div");
  378. this._statsDiv.id = "DebugLayerStats";
  379. this._statsDiv.style.border = border;
  380. this._statsDiv.style.position = "absolute";
  381. this._statsDiv.style.background = background;
  382. this._statsDiv.style.padding = "0px 0px 0px 5px";
  383. this._statsDiv.style.pointerEvents = "none";
  384. this._statsDiv.style.overflowY = "auto";
  385. this._generateheader(this._statsDiv, "Statistics");
  386. this._statsSubsetDiv = document.createElement("div");
  387. this._statsSubsetDiv.style.paddingTop = "5px";
  388. this._statsSubsetDiv.style.paddingBottom = "5px";
  389. this._statsDiv.appendChild(this._statsSubsetDiv);
  390. // Tree
  391. this._treeDiv = document.createElement("div");
  392. this._treeDiv.id = "DebugLayerTree";
  393. this._treeDiv.style.border = border;
  394. this._treeDiv.style.position = "absolute";
  395. this._treeDiv.style.background = background;
  396. this._treeDiv.style.padding = "0px 0px 0px 5px";
  397. this._treeDiv.style.display = "none";
  398. this._generateheader(this._treeDiv, "Meshes tree");
  399. this._treeSubsetDiv = document.createElement("div");
  400. this._treeSubsetDiv.style.paddingTop = "5px";
  401. this._treeSubsetDiv.style.paddingRight = "5px";
  402. this._treeSubsetDiv.style.overflowY = "auto";
  403. this._treeSubsetDiv.style.maxHeight = "300px";
  404. this._treeDiv.appendChild(this._treeSubsetDiv);
  405. this._needToRefreshMeshesTree = true;
  406. // Logs
  407. this._logDiv = document.createElement("div");
  408. this._logDiv.style.border = border;
  409. this._logDiv.id = "DebugLayerLogs";
  410. this._logDiv.style.position = "absolute";
  411. this._logDiv.style.background = background;
  412. this._logDiv.style.padding = "0px 0px 0px 5px";
  413. this._logDiv.style.display = "none";
  414. this._generateheader(this._logDiv, "Logs");
  415. this._logSubsetDiv = document.createElement("div");
  416. this._logSubsetDiv.style.paddingTop = "5px";
  417. this._logSubsetDiv.style.overflowY = "auto";
  418. this._logSubsetDiv.style.maxHeight = "200px";
  419. this._logSubsetDiv.style.fontSize = "12px";
  420. this._logSubsetDiv.style.fontFamily = "consolas";
  421. this._logSubsetDiv.innerHTML = Tools.LogCache;
  422. this._logDiv.appendChild(this._logSubsetDiv);
  423. Tools.OnNewCacheEntry = (entry: string) => {
  424. this._logSubsetDiv.innerHTML = entry + this._logSubsetDiv.innerHTML;
  425. }
  426. // Options
  427. this._optionsDiv = document.createElement("div");
  428. this._optionsDiv.id = "DebugLayerOptions";
  429. this._optionsDiv.style.border = border;
  430. this._optionsDiv.style.position = "absolute";
  431. this._optionsDiv.style.background = background;
  432. this._optionsDiv.style.padding = "0px 0px 0px 5px";
  433. this._optionsDiv.style.overflowY = "auto";
  434. this._generateheader(this._optionsDiv, "Options");
  435. this._optionsSubsetDiv = document.createElement("div");
  436. this._optionsSubsetDiv.style.paddingTop = "5px";
  437. this._optionsSubsetDiv.style.paddingBottom = "5px";
  438. this._optionsSubsetDiv.style.overflowY = "auto";
  439. this._optionsSubsetDiv.style.maxHeight = "200px";
  440. this._optionsDiv.appendChild(this._optionsSubsetDiv);
  441. this._generateTexBox(this._optionsSubsetDiv, "<b>General:</b>");
  442. this._generateCheckBox(this._optionsSubsetDiv, "Statistics", this._displayStatistics, (element) => { this._displayStatistics = element.checked });
  443. this._generateCheckBox(this._optionsSubsetDiv, "Logs", this._displayLogs, (element) => { this._displayLogs = element.checked });
  444. this._generateCheckBox(this._optionsSubsetDiv, "Meshes tree", this._displayTree, (element) => {
  445. this._displayTree = element.checked;
  446. this._needToRefreshMeshesTree = true;
  447. });
  448. this._generateCheckBox(this._optionsSubsetDiv, "Bounding boxes", this._scene.forceShowBoundingBoxes, (element) => { this._scene.forceShowBoundingBoxes = element.checked });
  449. this._generateCheckBox(this._optionsSubsetDiv, "Clickable labels", this._labelsEnabled, (element) => {
  450. this._labelsEnabled = element.checked;
  451. if (!this._labelsEnabled) {
  452. this._clearLabels();
  453. }
  454. });
  455. this._generateCheckBox(this._optionsSubsetDiv, "Generate user marks", Tools.PerformanceLogLevel === Tools.PerformanceUserMarkLogLevel,
  456. (element) => {
  457. if (element.checked) {
  458. Tools.PerformanceLogLevel = Tools.PerformanceUserMarkLogLevel;
  459. } else {
  460. Tools.PerformanceLogLevel = Tools.PerformanceNoneLogLevel;
  461. }
  462. });
  463. ;
  464. this._optionsSubsetDiv.appendChild(document.createElement("br"));
  465. this._generateTexBox(this._optionsSubsetDiv, "<b>Rendering mode:</b>");
  466. this._generateRadio(this._optionsSubsetDiv, "Solid", "renderMode", !this._scene.forceWireframe && !this._scene.forcePointsCloud, (element) => {
  467. if (element.checked) {
  468. this._scene.forceWireframe = false;
  469. this._scene.forcePointsCloud = false;
  470. }
  471. });
  472. this._generateRadio(this._optionsSubsetDiv, "Wireframe", "renderMode", this._scene.forceWireframe, (element) => {
  473. if (element.checked) {
  474. this._scene.forceWireframe = true;
  475. this._scene.forcePointsCloud = false;
  476. }
  477. });
  478. this._generateRadio(this._optionsSubsetDiv, "Point", "renderMode", this._scene.forcePointsCloud, (element) => {
  479. if (element.checked) {
  480. this._scene.forceWireframe = false;
  481. this._scene.forcePointsCloud = true;
  482. }
  483. });
  484. this._optionsSubsetDiv.appendChild(document.createElement("br"));
  485. this._generateTexBox(this._optionsSubsetDiv, "<b>Texture channels:</b>");
  486. this._generateCheckBox(this._optionsSubsetDiv, "Diffuse", StandardMaterial.DiffuseTextureEnabled, (element) => { StandardMaterial.DiffuseTextureEnabled = element.checked });
  487. this._generateCheckBox(this._optionsSubsetDiv, "Ambient", StandardMaterial.AmbientTextureEnabled, (element) => { StandardMaterial.AmbientTextureEnabled = element.checked });
  488. this._generateCheckBox(this._optionsSubsetDiv, "Specular", StandardMaterial.SpecularTextureEnabled, (element) => { StandardMaterial.SpecularTextureEnabled = element.checked });
  489. this._generateCheckBox(this._optionsSubsetDiv, "Emissive", StandardMaterial.EmissiveTextureEnabled, (element) => { StandardMaterial.EmissiveTextureEnabled = element.checked });
  490. this._generateCheckBox(this._optionsSubsetDiv, "Bump", StandardMaterial.BumpTextureEnabled, (element) => { StandardMaterial.BumpTextureEnabled = element.checked });
  491. this._generateCheckBox(this._optionsSubsetDiv, "Opacity", StandardMaterial.OpacityTextureEnabled, (element) => { StandardMaterial.OpacityTextureEnabled = element.checked });
  492. this._generateCheckBox(this._optionsSubsetDiv, "Reflection", StandardMaterial.ReflectionTextureEnabled, (element) => { StandardMaterial.ReflectionTextureEnabled = element.checked });
  493. this._generateCheckBox(this._optionsSubsetDiv, "Fresnel", StandardMaterial.FresnelEnabled, (element) => { StandardMaterial.FresnelEnabled = element.checked });
  494. this._optionsSubsetDiv.appendChild(document.createElement("br"));
  495. this._generateTexBox(this._optionsSubsetDiv, "<b>Options:</b>");
  496. this._generateCheckBox(this._optionsSubsetDiv, "Animations", this._scene.animationsEnabled, (element) => { this._scene.animationsEnabled = element.checked });
  497. this._generateCheckBox(this._optionsSubsetDiv, "Collisions", this._scene.collisionsEnabled, (element) => { this._scene.collisionsEnabled = element.checked });
  498. this._generateCheckBox(this._optionsSubsetDiv, "Fog", this._scene.fogEnabled, (element) => { this._scene.fogEnabled = element.checked });
  499. this._generateCheckBox(this._optionsSubsetDiv, "Lens flares", this._scene.lensFlaresEnabled, (element) => { this._scene.lensFlaresEnabled = element.checked });
  500. this._generateCheckBox(this._optionsSubsetDiv, "Lights", this._scene.lightsEnabled, (element) => { this._scene.lightsEnabled = element.checked });
  501. this._generateCheckBox(this._optionsSubsetDiv, "Particles", this._scene.particlesEnabled, (element) => { this._scene.particlesEnabled = element.checked });
  502. this._generateCheckBox(this._optionsSubsetDiv, "Post-processes", this._scene.postProcessesEnabled, (element) => { this._scene.postProcessesEnabled = element.checked });
  503. this._generateCheckBox(this._optionsSubsetDiv, "Procedural textures", this._scene.proceduralTexturesEnabled, (element) => { this._scene.proceduralTexturesEnabled = element.checked });
  504. this._generateCheckBox(this._optionsSubsetDiv, "Render targets", this._scene.renderTargetsEnabled, (element) => { this._scene.renderTargetsEnabled = element.checked });
  505. this._generateCheckBox(this._optionsSubsetDiv, "Shadows", this._scene.shadowsEnabled, (element) => { this._scene.shadowsEnabled = element.checked });
  506. this._generateCheckBox(this._optionsSubsetDiv, "Skeletons", this._scene.skeletonsEnabled, (element) => { this._scene.skeletonsEnabled = element.checked });
  507. this._generateCheckBox(this._optionsSubsetDiv, "Textures", this._scene.texturesEnabled, (element) => { this._scene.texturesEnabled = element.checked });
  508. // Global
  509. this._globalDiv.appendChild(this._statsDiv);
  510. this._globalDiv.appendChild(this._logDiv);
  511. this._globalDiv.appendChild(this._optionsDiv);
  512. this._globalDiv.appendChild(this._treeDiv);
  513. this._globalDiv.style.fontFamily = "Segoe UI, Arial";
  514. this._globalDiv.style.fontSize = "14px";
  515. this._globalDiv.style.color = "white";
  516. }
  517. }
  518. private _displayStats() {
  519. var scene = this._scene;
  520. var engine = scene.getEngine();
  521. this._statsSubsetDiv.innerHTML = "Babylon.js v" + Engine.Version + " - <b>" + Tools.Format(Tools.GetFps(), 0) + " fps</b><br><br>"
  522. + "Total meshes: " + scene.meshes.length + "<br>"
  523. + "Total vertices: " + scene.getTotalVertices() + "<br>"
  524. + "Active meshes: " + scene.getActiveMeshes().length + "<br>"
  525. + "Active vertices: " + scene.getActiveVertices() + "<br>"
  526. + "Active bones: " + scene.getActiveBones() + "<br>"
  527. + "Active particles: " + scene.getActiveParticles() + "<br><br>"
  528. + "Frame duration: " + Tools.Format(scene.getLastFrameDuration()) + " ms<br>"
  529. + "<b>Draw calls: " + engine.drawCalls + "</b><br><br>"
  530. + "<i>Evaluate Active Meshes duration:</i> " + Tools.Format(scene.getEvaluateActiveMeshesDuration()) + " ms<br>"
  531. + "<i>Render Targets duration:</i> " + Tools.Format(scene.getRenderTargetsDuration()) + " ms<br>"
  532. + "<i>Particles duration:</i> " + Tools.Format(scene.getParticlesDuration()) + " ms<br>"
  533. + "<i>Sprites duration:</i> " + Tools.Format(scene.getSpritesDuration()) + " ms<br>"
  534. + "<i>Render duration:</i> <b>" + Tools.Format(scene.getRenderDuration()) + " ms</b>";
  535. }
  536. }
  537. }