diff --git a/package-lock.json b/package-lock.json index 16e76c219..1b7c3722d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ "@jsquash/webp": "1.5.0", "@playcanvas/eslint-config": "3.0.0", "@playcanvas/font-tools": "0.1.2", - "@playcanvas/inspector": "0.3.0", + "@playcanvas/inspector": "0.5.0", "@playcanvas/msdfgen-wasm": "0.1.1", "@playcanvas/observer": "1.7.1", "@playcanvas/pcui": "6.1.5", @@ -2030,9 +2030,9 @@ } }, "node_modules/@playcanvas/inspector": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@playcanvas/inspector/-/inspector-0.3.0.tgz", - "integrity": "sha512-6WDk0wjXdtnjn3WvkJyAQwkecurn4+Funy/Z0vgBEaSUM9SN4N6rHssH6E78LMHsOS8FrN0NfHMqBeMvl2ys3Q==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@playcanvas/inspector/-/inspector-0.5.0.tgz", + "integrity": "sha512-al40WBgZ2QJ1ifwEGKQWPQdb6/G0FOBnkzoqfJrkS/pwtNJjE2d1dG0VAmJlFzjEFPuSzNPa7spVeg9jD2XrIg==", "dev": true, "license": "MIT", "peerDependencies": { diff --git a/package.json b/package.json index 61ff4278c..178c6ff67 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "@jsquash/webp": "1.5.0", "@playcanvas/eslint-config": "3.0.0", "@playcanvas/font-tools": "0.1.2", - "@playcanvas/inspector": "0.3.0", + "@playcanvas/inspector": "0.5.0", "@playcanvas/msdfgen-wasm": "0.1.1", "@playcanvas/observer": "1.7.1", "@playcanvas/pcui": "6.1.5", diff --git a/sass/launch.scss b/sass/launch.scss index 5e3eac6a3..70a32d757 100644 --- a/sass/launch.scss +++ b/sass/launch.scss @@ -1,9 +1,3 @@ -@use 'sass:color'; - -$devtools-dark: #202020; -$devtools-bg: #303030; -$devtools-font: 'Courier New', monospace; - @font-face { font-family: inconsolatamedium; src: url('../static/fonts/Inconsolata-webfont.woff2') format('woff2'); @@ -11,13 +5,6 @@ $devtools-font: 'Courier New', monospace; font-style: normal; } -@font-face { - font-family: pc-icon; - src: url('../static/fonts/PlayIcons-Regular.woff2') format('woff2'); - font-weight: normal; - font-style: normal; -} - html { height: 100%; width: 100%; @@ -143,210 +130,3 @@ canvas:focus { right: 5px; top: 5px; } - -%no-select { - user-select: none; -} - -%font-icon { - font-family: pc-icon; -} - -body > #dev-tools { - position: absolute; - z-index: 10001; - bottom: 0; - left: 0; - right: 0; - width: auto; - height: 300px; - background-color: $devtools-bg; - overflow: hidden; - cursor: default; - border-top: 1px solid $devtools-dark; - - &.dragging { - cursor: grabbing; - } - - > .overview { - position: absolute; - left: 300px; - top: 0; - display: block; - background-color: $devtools-dark; - - @extend %no-select; - } - - > .timeline { - position: absolute; - left: 300px; - top: 24px; - display: block; - background-color: $devtools-bg; - - @extend %no-select; - } - - > .frame { - position: absolute; - top: 0; - left: 0; - width: 299px; - height: 300px; - border-right: 1px solid $devtools-dark; - overflow: auto; - color: #fff; - font-size: 12px; - font-family: $devtools-font; - - &::-webkit-scrollbar { - width: 4px; - height: 4px; - } - - &::-webkit-scrollbar-track { - background: $devtools-bg; - } - - &::-webkit-scrollbar-thumb { - background: $devtools-dark; - } - - &::-webkit-scrollbar-thumb:hover { - background: #fff; - } - - &::-webkit-scrollbar-corner { - background: $devtools-bg; - } - - > .panel { - overflow: hidden; - - > .header { - text-transform: uppercase; - height: 24px; - line-height: 24px; - padding: 0 8px; - font-size: 14px; - background-color: $devtools-dark; - cursor: pointer; - } - - > .row { - overflow: hidden; - margin: 4px 8px; - - > .title { - float: left; - width: 150px; - } - - > .field { - float: left; - } - - > select { - padding: 0; - margin: 0; - border: none; - width: calc(100% - 150px); - background-color: $devtools-dark; - color: #fff; - font-size: 12px; - font-family: $devtools-font; - } - - > input[type='text'] { - float: left; - padding: 4px 8px; - margin: 0; - border: none; - background-color: $devtools-dark; - color: #fff; - font-size: 12px; - line-height: 16px; - font-family: $devtools-font; - - &.framesSkip { - width: calc(100% - 140px - 16px); - margin-right: 4px; - } - } - - > .drawcallsLimitButton { - float: left; - width: 24px; - height: 24px; - line-height: 24px; - text-align: center; - margin-right: 4px; - background-color: $devtools-dark; - color: #fff; - cursor: pointer; - - &:hover { - background-color: #000; - } - - &:last-child { - margin-right: 0; - } - } - } - - &.folded { - height: 24px; - - > .header { - color: color.mix($devtools-dark, #fff, 50%); - } - } - } - } - - > .toolbar { - position: absolute; - top: 0; - right: 0; - bottom: 0; - width: 32px; - background-color: $devtools-dark; - - > .button { - width: 32px; - height: 32px; - line-height: 32px; - text-align: center; - color: #fff; - font-size: 16px; - cursor: pointer; - - @extend %font-icon; - - &:hover { - background-color: #000; - } - } - } - - &.minimized { - width: 32px; - height: 32px; - left: auto; - border-top: none; - - > .overview, - > .timeline, - > .frame { - display: none; - } - - > .toolbar { - position: static; - height: 32px; - } - } -} diff --git a/src/editor/viewport-controls/viewport-launch.ts b/src/editor/viewport-controls/viewport-launch.ts index d12e0f519..f14202e05 100644 --- a/src/editor/viewport-controls/viewport-launch.ts +++ b/src/editor/viewport-controls/viewport-launch.ts @@ -248,7 +248,7 @@ editor.once('load', () => { const optionProfiler = createOption('profiler', 'Profiler'); const tooltipProfiler = TooltipHandle.attach({ target: optionProfiler.parent.dom, - text: 'Enable the visual performance profiler in the launch page.', + text: 'Open the Inspector on its Performance tab, recording from the start of the application. Requires Engine 2.23 or later.', align: 'right', root: root }); diff --git a/src/launch/index.ts b/src/launch/index.ts index 3fdabca68..2c694e62e 100644 --- a/src/launch/index.ts +++ b/src/launch/index.ts @@ -29,13 +29,6 @@ import './viewport/viewport'; import './viewport/viewport-error-console'; import './viewport/viewport-tooltip'; -// tools -import './tools/tools'; -import './tools/tools-overview'; -import './tools/tools-timeline'; -import './tools/tools-frame'; -import './tools/tools-toolbar'; - // entities import './entities/entities'; import './entities/entities-sync'; diff --git a/src/launch/tools/tools-frame.ts b/src/launch/tools/tools-frame.ts deleted file mode 100644 index a007dd066..000000000 --- a/src/launch/tools/tools-frame.ts +++ /dev/null @@ -1,779 +0,0 @@ -import type { Observer } from '@playcanvas/observer'; - -import { bytesToHuman } from '@/common/utils'; - -editor.once('load', () => { - let enabled = editor.call('tools:enabled'); - const app = editor.call('viewport:app'); - if (!app) { - return; - } // webgl not available - - editor.on('tools:state', (state: boolean) => { - enabled = state; - }); - - const fieldsCustom = {}; - - const panel = document.createElement('div'); - panel.classList.add('frame'); - editor.call('tools:root').appendChild(panel); - - const addPanel = function (args: { title: string }) { - const element = document.createElement('div') as HTMLDivElement & { _header: HTMLDivElement }; - element.classList.add('panel'); - panel.appendChild(element); - - element._header = document.createElement('div'); - element._header.classList.add('header'); - element._header.textContent = args.title; - element.appendChild(element._header); - - element._header.addEventListener( - 'click', - () => { - if (element.classList.contains('folded')) { - element.classList.remove('folded'); - } else { - element.classList.add('folded'); - } - }, - false - ); - - return element; - }; - - const addField = function (args: { title?: string; value?: string }) { - const row = document.createElement('div') as HTMLDivElement & { - _title: HTMLDivElement; - _field: HTMLDivElement; - value: string; - }; - row.classList.add('row'); - - row._title = document.createElement('div'); - row._title.classList.add('title'); - row._title.textContent = args.title || ''; - row.appendChild(row._title); - - row._field = document.createElement('div'); - row._field.classList.add('field'); - row._field.textContent = args.value || '-'; - row.appendChild(row._field); - - Object.defineProperty(row, 'value', { - set: function (value: string | undefined) { - this._field.textContent = value !== undefined ? value : ''; - } - }); - - return row; - }; - - let panelApp = undefined; - - editor.method('tools:frame:field:add', (name: string, title: string, value: string) => { - const field = addField({ - title: title, - value: value - }); - fieldsCustom[name] = field; - panelApp.appendChild(field); - }); - - editor.method('tools:frame:field:value', (name: string, value: string) => { - if (!fieldsCustom[name]) { - return; - } - - fieldsCustom[name].value = value; - }); - - // frame - const panelFrame = addPanel({ - title: 'Frame' - }); - // scene - const panelScene = addPanel({ - title: 'Scene' - }); - // drawCalls - const panelDrawCalls = addPanel({ - title: 'Draw Calls' - }); - // batching - const panelBatching = addPanel({ - title: 'Batching' - }); - // particles - const panelParticles = addPanel({ - title: 'Particles' - }); - // shaders - const panelShaders = addPanel({ - title: 'Shaders' - }); - // lightmapper - const panelLightmap = addPanel({ - title: 'Lightmapper' - }); - // vram - const panelVram = addPanel({ - title: 'VRAM' - }); - // app - panelApp = addPanel({ - title: 'App' - }); - - const fields = [ - { - key: ['frame', 'fps'], - panel: panelFrame, - title: 'FPS', - update: false - }, - { - key: ['frame', 'ms'], - panel: panelFrame, - title: 'MS', - format: function (value: number) { - return value.toFixed(2); - } - }, - { - key: ['frame', 'cameras'], - title: 'Cameras', - panel: panelFrame - }, - { - key: ['frame', 'cullTime'], - title: 'Cull Time', - panel: panelFrame, - format: function (value: number) { - return value.toFixed(3); - } - }, - { - key: ['frame', 'sortTime'], - title: 'Sort Time', - panel: panelFrame, - format: function (value: number) { - return value.toFixed(3); - } - }, - { - key: ['frame', 'shaders'], - title: 'Shaders', - panel: panelFrame - }, - { - key: ['frame', 'materials'], - title: 'Materials', - panel: panelFrame - }, - { - key: ['frame', 'triangles'], - title: 'Triangles', - panel: panelFrame, - format: function (value: number) { - return value.toLocaleString(); - } - }, - { - key: ['frame', 'otherPrimitives'], - title: 'Other Primitives', - panel: panelFrame - }, - { - key: ['frame', 'shadowMapUpdates'], - title: 'ShadowMaps Updates', - panel: panelFrame - }, - { - key: ['frame', 'shadowMapTime'], - title: 'ShadowMaps Time', - panel: panelFrame, - format: function (value: number) { - return value.toFixed(2); - } - }, - { - key: ['frame', 'updateTime'], - title: 'Update Time', - panel: panelFrame, - format: function (value: number) { - return value.toFixed(2); - } - }, - { - key: ['frame', 'physicsTime'], - title: 'Physics Time', - panel: panelFrame, - format: function (value: number) { - return value.toFixed(2); - } - }, - { - key: ['frame', 'renderTime'], - title: 'Render Time', - panel: panelFrame, - format: function (value: number) { - return value.toFixed(2); - } - }, - { - key: ['frame', 'forwardTime'], - title: 'Forward Time', - panel: panelFrame, - format: function (value: number) { - return value.toFixed(2); - } - }, - { - key: ['scene', 'meshInstances'], - title: 'Mesh Instances', - panel: panelScene - }, - { - key: ['scene', 'drawCalls'], - title: 'Draw Calls (potential)', - panel: panelScene - }, - { - key: ['scene', 'lights'], - title: 'Lights', - panel: panelScene - }, - { - key: ['scene', 'dynamicLights'], - title: 'Lights (Dynamic)', - panel: panelScene - }, - { - key: ['scene', 'bakedLights'], - title: 'Lights (Baked)', - panel: panelScene - }, - { - key: ['drawCalls', 'total'], - title: 'Total', - panel: panelDrawCalls, - format: function (value: number) { - return value.toLocaleString(); - } - }, - { - key: ['drawCalls', 'forward'], - title: 'Forward', - panel: panelDrawCalls, - format: function (value: number) { - return value.toLocaleString(); - } - }, - { - key: ['drawCalls', 'skinned'], - title: 'Skinned', - panel: panelDrawCalls, - format: function (value: number) { - return value.toLocaleString(); - } - }, - { - key: ['drawCalls', 'shadow'], - title: 'Shadow', - panel: panelDrawCalls, - format: function (value: number) { - return value.toLocaleString(); - } - }, - { - key: ['drawCalls', 'depth'], - title: 'Depth', - panel: panelDrawCalls, - format: function (value: number) { - return value.toLocaleString(); - } - }, - { - key: ['drawCalls', 'instanced'], - title: 'Instanced', - panel: panelDrawCalls, - format: function (value: number) { - return value.toLocaleString(); - } - }, - { - key: ['drawCalls', 'removedByInstancing'], - title: 'Instancing Benefit', - panel: panelDrawCalls, - format: function (value: number) { - return `-${value.toLocaleString()}`; - } - }, - { - key: ['drawCalls', 'immediate'], - title: 'Immediate', - panel: panelDrawCalls, - format: function (value: number) { - return value.toLocaleString(); - } - }, - { - key: ['drawCalls', 'misc'], - title: 'Misc', - panel: panelDrawCalls, - format: function (value: number) { - return value.toLocaleString(); - } - }, - { - key: ['batcher', 'createTime'], - title: 'Create Time', - panel: panelBatching, - format: function (value: number) { - return value.toFixed(2); - } - }, - { - key: ['batcher', 'updateLastFrameTime'], - title: 'Update Last Frame Time', - panel: panelBatching, - format: function (value: number) { - return value.toFixed(2); - } - }, - { - key: ['particles', 'updatesPerFrame'], - title: 'Updates', - panel: panelParticles - }, - { - key: ['particles', 'frameTime'], - title: 'Update Time', - panel: panelParticles, - format: function (value: number) { - return value.toLocaleString(); - } - }, - { - key: ['shaders', 'linked'], - title: 'Linked', - panel: panelShaders, - format: function (value: number) { - return value.toLocaleString(); - } - }, - { - key: ['shaders', 'vsCompiled'], - title: 'Compiled VS', - panel: panelShaders, - format: function (value: number) { - return value.toLocaleString(); - } - }, - { - key: ['shaders', 'fsCompiled'], - title: 'Compiled FS', - panel: panelShaders, - format: function (value: number) { - return value.toLocaleString(); - } - }, - { - key: ['shaders', 'materialShaders'], - title: 'Materials', - panel: panelShaders, - format: function (value: number) { - return value.toLocaleString(); - } - }, - { - key: ['shaders', 'compileTime'], - title: 'Compile Time', - panel: panelShaders, - format: function (value: number) { - return value.toFixed(3); - } - }, - { - key: ['lightmapper', 'renderPasses'], - title: 'Render Passes', - panel: panelLightmap, - format: function (value: number) { - return value.toLocaleString(); - } - }, - { - key: ['lightmapper', 'lightmapCount'], - title: 'Textures', - panel: panelLightmap, - format: function (value: number) { - return value.toLocaleString(); - } - }, - { - key: ['lightmapper', 'shadersLinked'], - title: 'Shaders Linked', - panel: panelLightmap, - format: function (value: number) { - return value.toLocaleString(); - } - }, - { - key: ['lightmapper', 'totalRenderTime'], - title: 'Total Render Time', - panel: panelLightmap, - format: function (value: number) { - return value.toFixed(3); - } - }, - { - key: ['lightmapper', 'forwardTime'], - title: 'Forward Time', - panel: panelLightmap, - format: function (value: number) { - return value.toFixed(3); - } - }, - { - key: ['lightmapper', 'fboTime'], - title: 'FBO Time', - panel: panelLightmap, - format: function (value: number) { - return value.toFixed(3); - } - }, - { - key: ['lightmapper', 'shadowMapTime'], - title: 'ShadowMap Time', - panel: panelLightmap, - format: function (value: number) { - return value.toFixed(3); - } - }, - { - key: ['lightmapper', 'compileTime'], - title: 'Shader Compile Time', - panel: panelLightmap, - format: function (value: number) { - return value.toFixed(3); - } - }, - { - key: ['vram', 'ib'], - title: 'Index Buffers', - panel: panelVram, - format: bytesToHuman - }, - { - key: ['vram', 'vb'], - title: 'Vertex Buffers', - panel: panelVram, - format: bytesToHuman - }, - { - key: ['vram', 'texShadow'], - title: 'Shadowmaps', - panel: panelVram, - format: bytesToHuman - }, - { - key: ['vram', 'texLightmap'], - title: 'Lightmaps', - panel: panelVram, - format: bytesToHuman - }, - { - key: ['vram', 'texAsset'], - title: 'Texture Assets', - panel: panelVram, - format: bytesToHuman - }, - { - key: ['vram', 'tex'], - title: 'Textures Other', - panel: panelVram, - format: function (bytes: number) { - return bytesToHuman( - bytes - (app.stats.vram.texLightmap + app.stats.vram.texShadow + app.stats.vram.texAsset) - ); - } - }, - { - key: ['vram', 'tex'], - title: 'Textures Total', - panel: panelVram, - format: bytesToHuman - }, - { - key: ['vram', 'totalUsed'], - title: 'Total', - panel: panelVram, - format: bytesToHuman - } - ]; - - // create fields - type FieldItem = { - key: string[]; - panel: HTMLDivElement; - title?: string; - update?: boolean; - format?: (v: number) => string; - custom?: string; - field?: HTMLDivElement & { _title: HTMLDivElement; _field: HTMLDivElement; value: string }; - }; - for (let i = 0; i < fields.length; i++) { - const field = fields[i]; - const item = field as FieldItem; - item.field = addField({ - title: item.title || item.key[1] - }); - item.panel.appendChild(item.field); - - if (item.custom) { - fieldsCustom[item.custom] = item.field; - } - } - - // controls to skip rendering of draw calls - const row = document.createElement('div'); - row.classList.add('row'); - panelDrawCalls.appendChild(row); - - const title = document.createElement('div'); - title.classList.add('title'); - title.textContent = 'Camera Drawcalls Limit'; - title.style.fontSize = '11px'; - row.appendChild(title); - - let cameraSkipFrames = undefined; - let rowCameraSkip = undefined; - - const cameras = document.createElement('select'); - cameras.classList.add('cameras'); - row.appendChild(cameras); - cameras.addEventListener('mousedown', (evt: MouseEvent) => { - evt.stopPropagation(); - }); - cameras.addEventListener('change', () => { - if (cameras.value === 'none') { - rowCameraSkip.style.display = 'none'; - pc.ForwardRenderer.skipRenderCamera = null; - } else { - rowCameraSkip.style.display = ''; - - const entity = app.root.findByGuid(cameras.value); - if (entity && entity.camera) { - pc.ForwardRenderer.skipRenderCamera = entity.camera.camera; - pc.ForwardRenderer.skipRenderAfter = parseInt(cameraSkipFrames.value, 10) || 0; - } - } - }); - - const cameraIndex = {}; - let cameraAddQueue = []; - - const cameraNone = document.createElement('option'); - cameraNone.value = 'none'; - cameraNone.selected = true; - cameraNone.textContent = 'Disabled'; - cameras.appendChild(cameraNone); - - // frames control - rowCameraSkip = document.createElement('div'); - rowCameraSkip.classList.add('row'); - rowCameraSkip.style.display = 'none'; - panelDrawCalls.appendChild(rowCameraSkip); - - const cameraSkipFramesLeft0 = document.createElement('div'); - cameraSkipFramesLeft0.classList.add('drawcallsLimitButton'); - cameraSkipFramesLeft0.textContent = '|<'; - cameraSkipFramesLeft0.addEventListener('click', () => { - cameraSkipFrames.value = '0'; - pc.ForwardRenderer.skipRenderAfter = parseInt(cameraSkipFrames.value, 10) || 0; - }); - rowCameraSkip.appendChild(cameraSkipFramesLeft0); - - const cameraSkipFramesLeft10 = document.createElement('div'); - cameraSkipFramesLeft10.classList.add('drawcallsLimitButton'); - cameraSkipFramesLeft10.textContent = '<<'; - cameraSkipFramesLeft10.addEventListener('click', () => { - cameraSkipFrames.value = Math.max(0, (parseInt(cameraSkipFrames.value, 10) || 0) - 10); - pc.ForwardRenderer.skipRenderAfter = parseInt(cameraSkipFrames.value, 10) || 0; - }); - rowCameraSkip.appendChild(cameraSkipFramesLeft10); - - const cameraSkipFramesLeft1 = document.createElement('div'); - cameraSkipFramesLeft1.classList.add('drawcallsLimitButton'); - cameraSkipFramesLeft1.textContent = '<'; - cameraSkipFramesLeft1.addEventListener('click', () => { - cameraSkipFrames.value = Math.max(0, (parseInt(cameraSkipFrames.value, 10) || 0) - 1); - pc.ForwardRenderer.skipRenderAfter = parseInt(cameraSkipFrames.value, 10) || 0; - }); - rowCameraSkip.appendChild(cameraSkipFramesLeft1); - - cameraSkipFrames = document.createElement('input'); - cameraSkipFrames.classList.add('framesSkip'); - cameraSkipFrames.type = 'text'; - cameraSkipFrames.value = '0'; - rowCameraSkip.appendChild(cameraSkipFrames); - cameraSkipFrames.addEventListener('mousedown', (evt: MouseEvent) => { - evt.stopPropagation(); - }); - cameraSkipFrames.addEventListener( - 'change', - () => { - pc.ForwardRenderer.skipRenderAfter = parseInt(cameraSkipFrames.value, 10) || 0; - }, - false - ); - cameraSkipFrames.addEventListener('keydown', (evt: KeyboardEvent) => { - let inc = 0; - - if (evt.keyCode === 38) { - inc = evt.shiftKey ? 10 : 1; - } else if (evt.keyCode === 40) { - inc = evt.shiftKey ? -10 : -1; - } - - if (inc === 0) { - return; - } - - evt.preventDefault(); - evt.stopPropagation(); - - cameraSkipFrames.value = Math.max( - 0, - Math.min(Number.MAX_SAFE_INTEGER, (parseInt(cameraSkipFrames.value, 10) || 0) + inc) - ); - pc.ForwardRenderer.skipRenderAfter = parseInt(cameraSkipFrames.value, 10) || 0; - }); - - const cameraSkipFramesRight1 = document.createElement('div'); - cameraSkipFramesRight1.classList.add('drawcallsLimitButton'); - cameraSkipFramesRight1.textContent = '>'; - cameraSkipFramesRight1.addEventListener('click', () => { - cameraSkipFrames.value = Math.min(Number.MAX_SAFE_INTEGER, (parseInt(cameraSkipFrames.value, 10) || 0) + 1); - pc.ForwardRenderer.skipRenderAfter = parseInt(cameraSkipFrames.value, 10) || 0; - }); - rowCameraSkip.appendChild(cameraSkipFramesRight1); - - const cameraSkipFramesRight10 = document.createElement('div'); - cameraSkipFramesRight10.classList.add('drawcallsLimitButton'); - cameraSkipFramesRight10.textContent = '>>'; - cameraSkipFramesRight10.addEventListener('click', () => { - cameraSkipFrames.value = Math.min(Number.MAX_SAFE_INTEGER, (parseInt(cameraSkipFrames.value, 10) || 0) + 10); - pc.ForwardRenderer.skipRenderAfter = parseInt(cameraSkipFrames.value, 10) || 0; - }); - rowCameraSkip.appendChild(cameraSkipFramesRight10); - - const cameraAdd = function (id: string) { - if (cameraAddQueue) { - cameraAddQueue.push(id); - return; - } - - if (cameraIndex[id]) { - return; - } - - const entity = app.root.findByGuid(id); - if (!entity) { - return; - } - - const option = (cameraIndex[id] = document.createElement('option')); - option.value = id; - option.entity = entity; - option.textContent = entity.name; - cameras.appendChild(option); - }; - - const cameraRemove = function (id: string) { - if (!cameraIndex[id]) { - return; - } - - if (cameraIndex[id].selected) { - cameras.value = 'none'; - } - - cameras.removeChild(cameraIndex[id]); - delete cameraIndex[id]; - }; - - // the app may have changed scene since, so list the cameras it has now when the dropdown opens - cameras.addEventListener('mousedown', () => { - const live = new Set(app.root.findComponents('camera').map((camera) => camera.entity.getGuid())); - Object.keys(cameraIndex) - .filter((id) => !live.has(id)) - .forEach(cameraRemove); - live.forEach(cameraAdd); - }); - - editor.on('entities:add', (obj: Observer) => { - const id = obj.get('resource_id'); - - obj.on('components.camera:set', () => { - cameraAdd(id); - }); - obj.on('components.camera:unset', () => { - cameraRemove(id); - }); - obj.on('name:set', (value: string) => { - if (!cameraIndex[id]) { - return; - } - - cameraIndex[id].textContent = value; - }); - - if (obj.has('components.camera')) { - cameraAdd(id); - } - }); - - app.on('start', () => { - if (cameraAddQueue) { - const queue = cameraAddQueue; - cameraAddQueue = null; - - for (let i = 0; i < queue.length; i++) { - const id = queue[i]; - cameraAdd(id); - } - } - }); - - // update frame fields - editor.on('tools:render', () => { - if (!enabled) { - return; - } - - for (let i = 0; i < fields.length; i++) { - const field = fields[i]; - if (field.ignore) { - continue; - } - - const item = field as FieldItem; - const key0 = item.key[0]; - const key1 = item.key[1]; - - if (app.stats && key0 in app.stats && app.stats[key0] && key1 in app.stats[key0]) { - let value = app.stats[key0][key1]; - - if (item.format) { - value = item.format(value); - } - - item.field!.value = value; - } - } - }); -}); diff --git a/src/launch/tools/tools-overview.ts b/src/launch/tools/tools-overview.ts deleted file mode 100644 index 75a62ef39..000000000 --- a/src/launch/tools/tools-overview.ts +++ /dev/null @@ -1,173 +0,0 @@ -editor.once('load', () => { - // variables - const enabled = editor.call('tools:enabled'); - let events = []; - let eventsIndex = {}; - - // canvas - const canvas = document.createElement('canvas'); - canvas.classList.add('overview'); - editor.call('tools:root').appendChild(canvas); - - // context - const ctx = canvas.getContext('2d'); - ctx.font = '10px Arial'; - - const render = function () { - ctx.clearRect(0, 0, canvas.width, canvas.height); - - const now = editor.call('tools:time:now'); - const scrollTime = editor.call('tools:scroll:time'); - const capacity = editor.call('tools:time:capacity'); - ctx.textBaseline = 'alphabetic'; - - const startX = (scrollTime / now) * canvas.width; - const endX = (Math.min(now, scrollTime + capacity) / now) * canvas.width; - - // view rect - ctx.beginPath(); - ctx.rect(startX, 0, endX - startX, canvas.height); - ctx.fillStyle = '#303030'; - ctx.fill(); - // line bottom - ctx.beginPath(); - ctx.moveTo(startX, canvas.height - 0.5); - ctx.lineTo(endX, canvas.height - 0.5); - ctx.strokeStyle = '#2c2c2c'; - ctx.stroke(); - - // events - let x, x2; - for (let i = 0; i < events.length; i++) { - const e = events[i]; - x = (e.t / now) * canvas.width; - - if (e.t2 !== null) { - let t2 = e.t2; - if (e.t2 === -1) { - t2 = now; - } - - x2 = Math.max((t2 / now) * canvas.width, x + 1); - - ctx.beginPath(); - ctx.rect(x, Math.floor((canvas.height - 8) / 2), x2 - x, 8); - ctx.fillStyle = editor.call('tools:timeline:color', e.k); - ctx.fill(); - } else { - ctx.beginPath(); - ctx.moveTo(x, 1); - ctx.lineTo(x, canvas.height - 1); - ctx.strokeStyle = editor.call('tools:timeline:color', e.k); - ctx.stroke(); - } - } - - ctx.lineWidth = 3; - ctx.strokeStyle = '#000'; - - // start/end text - ctx.fillStyle = '#fff'; - // start time - ctx.textAlign = 'left'; - ctx.strokeText('00:00.0 FPS', 2.5, canvas.height - 2.5); - ctx.fillText('00:00.0 FPS', 2.5, canvas.height - 2.5); - // now time - ctx.textAlign = 'right'; - ctx.strokeText(editor.call('tools:time:toHuman', now, 1), canvas.width - 2.5, canvas.height - 2.5); - ctx.fillText(editor.call('tools:time:toHuman', now, 1), canvas.width - 2.5, canvas.height - 2.5); - - let startTextWidth = 0; - ctx.textBaseline = 'top'; - - let text, measures, offset; - - // view start - if (scrollTime > 0) { - text = editor.call('tools:time:toHuman', scrollTime, 1); - measures = ctx.measureText(text); - offset = 2.5; - if (startX + 2.5 + measures.width < endX - 2.5) { - startTextWidth = measures.width; - ctx.textAlign = 'left'; - } else { - offset = -2.5; - ctx.textAlign = 'right'; - } - ctx.strokeText(text, startX + offset, 0); - ctx.fillText(text, startX + offset, 0); - } - - // view end - if (scrollTime + capacity < now - 100) { - text = editor.call('tools:time:toHuman', Math.min(now, scrollTime + capacity), 1); - measures = ctx.measureText(text); - offset = 2.5; - if (endX - 2.5 - measures.width - startTextWidth > startX + 2.5) { - ctx.textAlign = 'right'; - offset = -2.5; - } else { - ctx.textAlign = 'left'; - } - ctx.strokeText(text, endX + offset, 0); - ctx.fillText(text, endX + offset, 0); - } - - ctx.lineWidth = 1; - }; - - // resize - editor.on('tools:resize', (width, height) => { - canvas.width = width - 300 - 32; - canvas.height = 24; - render(); - }); - canvas.width = editor.call('tools:size:width') - 300 - 32; - canvas.height = 24; - - editor.on('tools:clear', () => { - events = []; - eventsIndex = {}; - }); - - editor.on('tools:timeline:add', (item: { i: number; t: number; t2: number | null; k: string }) => { - let found = false; - - // check if can extend existing event - for (let i = 0; i < events.length; i++) { - const event = events[i]; - if ( - event.t2 !== null && - event.k === item.k && - event.t - 1 <= item.t && - (event.t2 === -1 || event.t2 + 1 >= item.t) - ) { - found = true; - event.t2 = item.t2; - eventsIndex[item.i] = event; - break; - } - } - - if (!found) { - const obj = { - i: item.i, - t: item.t, - t2: item.t2, - k: item.k - }; - events.push(obj); - eventsIndex[obj.i] = obj; - } - }); - - editor.on('tools:timeline:update', (item: { i: number; t2: number }) => { - if (!enabled || !eventsIndex[item.i]) { - return; - } - - eventsIndex[item.i].t2 = item.t2; - }); - - editor.on('tools:render', render); -}); diff --git a/src/launch/tools/tools-timeline.ts b/src/launch/tools/tools-timeline.ts deleted file mode 100644 index ee13bd26f..000000000 --- a/src/launch/tools/tools-timeline.ts +++ /dev/null @@ -1,397 +0,0 @@ -editor.once('load', () => { - // variables - let enabled = editor.call('tools:enabled'); - let counter = 0; - let scale = 0.2; - let events = []; - let cacheAssetLoading = {}; - let cacheShaderCompile = []; - let cacheShaderCompileEvents = []; - let cacheLightmapper = null; - let cacheLightmapperEvent = null; - const app = editor.call('viewport:app'); - if (!app) { - return; - } // webgl not available - - // canvas - const canvas = document.createElement('canvas'); - canvas.classList.add('timeline'); - editor.call('tools:root').appendChild(canvas); - - // context - const ctx = canvas.getContext('2d'); - - // colors for different kinds of events - const kindColors = { - '': '#ff0', - asset: '#6f6', - shader: '#f60', - update: '#06f', - render: '#07f', - physics: '#0ff', - lightmap: '#f6f' - }; - const kindColorsOverview = { - '': '#ff0', - asset: '#6f6', - shader: '#f60', - update: '#06f', - render: '#07f', - physics: '#0ff', - lightmap: '#f6f' - }; - - const render = function () { - let i; - let x; - - ctx.clearRect(0, 0, canvas.width, canvas.height); - - const barMargin = 1; - const barHeight = 8; - const stack = []; - const scaleMs = 1000 * scale; - const now = editor.call('tools:time:now'); - const scrollTime = editor.call('tools:scroll:time'); - const timeHover = editor.call('tools:time:hover'); - ctx.textBaseline = 'alphabetic'; - - // grid - const secondsX = Math.floor(canvas.width * scale); - ctx.strokeStyle = '#2c2c2c'; - ctx.fillStyle = '#989898'; - const offset = scaleMs - ((scrollTime * scale) % scaleMs) - scaleMs; - for (x = 0; x <= secondsX; x++) { - const barX = Math.floor(x * scaleMs + offset) + 0.5; - if (x > 0) { - ctx.beginPath(); - ctx.moveTo(barX, 0); - ctx.lineTo(barX, canvas.height); - ctx.stroke(); - } - - let s = Math.floor(x + scrollTime / 1000); - const m = Math.floor(s / 60); - s %= 60; - ctx.fillText(`${(m ? `${m}m ` : '') + s}s`, barX + 2.5, canvas.height - 2.5); - } - - // events - let e, - x2 = 0, - y; - x = 0; - for (i = 0; i < events.length; i++) { - e = events[i]; - x = Math.floor((e.t - scrollTime) * scale); - - if (x > canvas.width) { - break; - } - - // time - if (e.t2 !== null) { - if (isNaN(e.t2)) { - console.log(e); - continue; - } - // range - let t2 = e.t2 - scrollTime; - if (e.t2 === -1) { - t2 = now - scrollTime; - } - - x2 = Math.max(Math.floor(t2 * scale), x + 1); - - if (x2 < 0) { - continue; - } - - y = 0; - let foundY = false; - for (let n = 0; n < stack.length; n++) { - if (stack[n] < e.t) { - stack[n] = t2 + scrollTime; - y = n * (barHeight + barMargin); - foundY = true; - break; - } - } - if (!foundY) { - y = stack.length * (barHeight + barMargin); - stack.push(t2 + scrollTime); - } - - ctx.beginPath(); - ctx.rect(x + 0.5, y + 1, x2 - x + 0.5, barHeight); - ctx.fillStyle = kindColors[e.k] || '#fff'; - ctx.fill(); - } else { - if (x < 0) { - continue; - } - - // single event - ctx.beginPath(); - ctx.moveTo(x + 0.5, 1); - ctx.lineTo(x + 0.5, canvas.height - 1); - ctx.strokeStyle = kindColors[e.k] || '#fff'; - ctx.stroke(); - } - } - - ctx.lineWidth = 3; - ctx.strokeStyle = '#000'; - for (i = 0; i < events.length; i++) { - e = events[i]; - x = Math.floor((e.t - scrollTime) * scale); - - if (x > canvas.width) { - break; - } - - if (e.t2 !== null || x < 0) { - continue; - } - - // name - if (e.n) { - ctx.fillStyle = kindColors[e.k] || '#fff'; - ctx.strokeText(e.n, x + 2.5, canvas.height - 12.5); - ctx.strokeText(`${(e.t / 1000).toFixed(2)}s`, x + 2.5, canvas.height - 2.5); - ctx.fillText(e.n, x + 2.5, canvas.height - 12.5); - ctx.fillText(`${(e.t / 1000).toFixed(2)}s`, x + 2.5, canvas.height - 2.5); - } - } - ctx.lineWidth = 1; - - // now - ctx.beginPath(); - ctx.moveTo(Math.floor((now - scrollTime) * scale) + 0.5, 0); - ctx.lineTo(Math.floor((now - scrollTime) * scale) + 0.5, canvas.height); - ctx.strokeStyle = '#989898'; - ctx.stroke(); - - // hover - if (timeHover > 0) { - x = (timeHover - scrollTime) * scale; - ctx.beginPath(); - ctx.moveTo(Math.floor(x) + 0.5, 0); - ctx.lineTo(Math.floor(x) + 0.5, canvas.height); - ctx.strokeStyle = '#989898'; - ctx.stroke(); - - ctx.beginPath(); - ctx.lineWidth = 3; - ctx.strokeStyle = '#000'; - ctx.fillStyle = '#fff'; - ctx.strokeText(`${(timeHover / 1000).toFixed(1)}s`, Math.floor(x) + 2.5, canvas.height - 22.5); - ctx.fillText(`${(timeHover / 1000).toFixed(1)}s`, Math.floor(x) + 2.5, canvas.height - 22.5); - ctx.lineWidth = 1; - } - }; - - // resize - editor.on('tools:resize', (width: number, height: number) => { - canvas.width = width - 300 - 32; - canvas.height = 275; - scale = canvas.width / editor.call('tools:time:capacity'); - ctx.font = '10px Arial'; - render(); - }); - canvas.width = editor.call('tools:size:width') - 300 - 32; - canvas.height = 275; - ctx.font = '10px Arial'; - scale = canvas.width / editor.call('tools:time:capacity'); - - editor.on('tools:clear', () => { - events = []; - cacheAssetLoading = {}; - cacheShaderCompile = []; - cacheShaderCompileEvents = []; - }); - - editor.on('tools:state', (state) => { - enabled = state; - }); - - editor.method('tools:timeline:color', (kind: string) => { - return kindColorsOverview[kind] || '#fff'; - }); - - // add event to history - const addEvent = function (args: { time: number; time2?: number; name?: string; kind?: string }) { - if (!enabled) { - return; - } - - const e = { - i: ++counter, - t: args.time, - t2: args.time2 || null, - n: args.name || '', - k: args.kind || '' - }; - events.push(e); - editor.emit('tools:timeline:add', e); - return e; - }; - editor.method('tools:timeline:add', addEvent); - - editor.once('launcher:device:ready', () => { - // subscribe to app reload start - app.once('preload:start', () => { - if (!enabled) { - return; - } - - addEvent({ - time: editor.call('tools:time:now'), - name: 'preload' - }); - }); - - // subscribe to app start - app.once('start', () => { - if (!enabled) { - return; - } - - addEvent({ - time: editor.call('tools:time:now'), - name: 'start' - }); - }); - - // subscribe to asset loading start - app.assets.on('load:start', (asset) => { - if (!enabled) { - return; - } - - cacheAssetLoading[asset.id] = addEvent({ - time: editor.call('tools:time:now'), - time2: -1, - kind: 'asset' - }); - }); - - // subscribe to asset loading end - app.assets.on('load', (asset: pc.Asset) => { - if (!enabled || !cacheAssetLoading[asset.id]) { - return; - } - - cacheAssetLoading[asset.id].t2 = editor.call('tools:time:now'); - editor.emit('tools:timeline:update', cacheAssetLoading[asset.id]); - delete cacheAssetLoading[asset.id]; - }); - - const onShaderStart = function (evt: { timestamp: number; target: unknown }) { - if (!enabled) { - return; - } - - let time = evt.timestamp; - if (editor.call('tools:epoc')) { - time -= editor.call('tools:time:beginning'); - } - - const item = addEvent({ - time: time, - time2: -1, - kind: 'shader' - }); - - cacheShaderCompile.push(evt.target); - cacheShaderCompileEvents[cacheShaderCompile.length - 1] = item; - }; - - const onShaderEnd = function (evt: { timestamp: number; target: unknown }) { - if (!enabled) { - return; - } - - const ind = cacheShaderCompile.indexOf(evt.target); - if (ind === -1) { - return; - } - - let time = evt.timestamp; - if (editor.call('tools:epoc')) { - time -= editor.call('tools:time:beginning'); - } - - cacheShaderCompileEvents[ind].t2 = time; - editor.emit('tools:timeline:update', cacheShaderCompileEvents[ind]); - cacheShaderCompile.splice(ind, 1); - cacheShaderCompileEvents.splice(ind, 1); - }; - - const onLightmapperStart = function (evt: { timestamp: number; target: unknown }) { - if (!enabled) { - return; - } - - let time = evt.timestamp; - if (editor.call('tools:epoc')) { - time -= editor.call('tools:time:beginning'); - } - - const item = addEvent({ - time: time, - time2: -1, - kind: 'lightmap' - }); - - cacheLightmapper = evt.target; - cacheLightmapperEvent = item; - }; - - const onLightmapperEnd = function (evt: { timestamp: number; target: unknown }) { - if (!enabled) { - return; - } - - if (cacheLightmapper !== evt.target) { - return; - } - - let time = evt.timestamp; - if (editor.call('tools:epoc')) { - time -= editor.call('tools:time:beginning'); - } - - cacheLightmapperEvent.t2 = time; - editor.emit('tools:timeline:update', cacheLightmapperEvent); - cacheLightmapper = null; - }; - - // subscribe to shader compile and linking - app.graphicsDevice.on('shader:compile:start', onShaderStart); - app.graphicsDevice.on('shader:link:start', onShaderStart); - app.graphicsDevice.on('shader:compile:end', onShaderEnd); - app.graphicsDevice.on('shader:link:end', onShaderEnd); - - // subscribe to lightmapper baking - app.graphicsDevice.on('lightmapper:start', onLightmapperStart); - app.graphicsDevice.on('lightmapper:end', onLightmapperEnd); - }); - - // add performance.timing events if available - if (performance.timing) { - // dom interactive - addEvent({ - time: performance.timing.domInteractive - editor.call('tools:time:beginning'), - name: 'dom' - }); - // document load - addEvent({ - time: performance.timing.loadEventEnd - editor.call('tools:time:beginning'), - name: 'load' - }); - } - - editor.on('tools:render', render); -}); diff --git a/src/launch/tools/tools-toolbar.ts b/src/launch/tools/tools-toolbar.ts deleted file mode 100644 index 05a2c0566..000000000 --- a/src/launch/tools/tools-toolbar.ts +++ /dev/null @@ -1,26 +0,0 @@ -editor.once('load', () => { - // variables - const toolbar = document.createElement('div'); - toolbar.classList.add('toolbar'); - editor.call('tools:root').appendChild(toolbar); - - // button minimize/maximize - const btnMinimize = document.createElement('div'); - btnMinimize.innerHTML = ''; // down arrow icon (minimize) - btnMinimize.classList.add('button', 'minimize'); - toolbar.appendChild(btnMinimize); - - btnMinimize.addEventListener('click', (evt) => { - evt.stopPropagation(); - if (editor.call('tools:minimized')) { - editor.call('tools:maximize'); - } else { - editor.call('tools:minimize'); - } - }); - - // update icon when minimized state changes - editor.on('tools:minimized', (isMinimized) => { - btnMinimize.innerHTML = isMinimized ? '' : ''; // up arrow when minimized, down arrow when expanded - }); -}); diff --git a/src/launch/tools/tools.ts b/src/launch/tools/tools.ts deleted file mode 100644 index cdee81e44..000000000 --- a/src/launch/tools/tools.ts +++ /dev/null @@ -1,375 +0,0 @@ -let now = function () { - return performance.timing.navigationStart + performance.now(); -}; - -if (!performance || !performance.now || !performance.timing) { - now = Date.now; -} - -const start = now(); - -editor.once('load', () => { - // times - let timeBeginning = performance.timing ? performance.timing.responseEnd : start; - let timeNow = now() - timeBeginning; - let timeHover = 0; - - const epoc = !window.performance || !performance.now || !performance.timing; - editor.method('tools:epoc', () => { - return epoc; - }); - - editor.method('tools:time:now', () => { - return now() - timeBeginning; - }); - editor.method('tools:time:beginning', () => { - return timeBeginning; - }); - editor.method('tools:time:hover', () => { - return timeHover; - }); - - editor.method('tools:time:toHuman', (ms: number, precision?: number) => { - let s = ms / 1000; - const m = `00${Math.floor(s / 60)}`.slice(-2); - if (precision) { - s = `00.0${(s % 60).toFixed(precision)}`.slice(-4); - } else { - s = `00${Math.floor(s % 60)}`.slice(-2); - } - return `${m}:${s}`; - }); - - // root panel - const root = document.createElement('div'); - root.id = 'dev-tools'; - root.style.display = 'none'; - document.body.appendChild(root); - editor.method('tools:root', () => { - return root; - }); - - let enabled = false; - let minimized = false; - - if (location.search && location.search.indexOf('profile=true') !== -1) { - enabled = true; - } - - if (enabled) { - root.style.display = 'block'; - } - - // view - const scale = 0.2; // how many pixels in a ms - let capacity = 0; // how many ms can fit - const scroll = { - time: 0, // how many ms start from - auto: true, // auto scroll to the end - drag: { - x: 0, - time: 0, - bar: false, - barTime: 0, - barMove: false - } - }; - let resize = undefined; - - editor.method('tools:enabled', () => { - return enabled; - }); - - editor.method('tools:enable', () => { - if (enabled) { - return; - } - - enabled = true; - root.style.display = 'block'; - resize(); - editor.emit('tools:clear'); - editor.emit('tools:state', true); - - // updateInterval = setInterval(function() { - // update(); - // editor.emit('tools:render'); - // }, 1000 / 60); - }); - - editor.method('tools:disable', () => { - if (!enabled) { - return; - } - - enabled = false; - root.style.display = 'none'; - editor.emit('tools:clear'); - editor.emit('tools:state', false); - // clearInterval(updateInterval); - }); - - editor.method('tools:minimized', () => { - return minimized; - }); - - editor.method('tools:minimize', () => { - if (!enabled || minimized) { - return; - } - - minimized = true; - root.classList.add('minimized'); - editor.emit('tools:minimized', true); - }); - - editor.method('tools:maximize', () => { - if (!enabled || !minimized) { - return; - } - - minimized = false; - root.classList.remove('minimized'); - editor.emit('tools:minimized', false); - }); - - // methods to access view params - editor.method('tools:time:capacity', () => { - return capacity; - }); - editor.method('tools:scroll:time', () => { - return scroll.time; - }); - - // size - const left = 300; - const right = 0; - let width = 0; - let height = 0; - // resizing - resize = function (): void { - const rect = root.getBoundingClientRect(); - - if (width === rect.width && height === rect.height) { - return; - } - - width = rect.width; - height = rect.height; - capacity = Math.floor((width - left - right) / scale); - scroll.time = Math.max(0, Math.min(timeNow - capacity, Math.floor(scroll.time))); - - editor.emit('tools:resize', width, height); - }; - window.addEventListener('resize', resize, false); - window.addEventListener('orientationchange', resize, false); - setInterval(resize, 500); - resize(); - editor.method('tools:size:width', () => { - return width; - }); - editor.method('tools:size:height', () => { - return height; - }); - - editor.on('tools:clear', () => { - timeBeginning = now(); - timeNow = 0; - timeHover = 0; - scroll.time = 0; - scroll.auto = true; - }); - - const mouse = { - x: 0, - y: 0, - click: false, - down: false, - up: false, - hover: false - }; - - const flushMouse = function () { - if (mouse.up) { - mouse.up = false; - } - - if (mouse.click) { - mouse.click = false; - mouse.down = true; - } - }; - - const update = function () { - timeNow = now() - timeBeginning; - - if (scroll.auto) { - scroll.time = Math.max(0, timeNow - capacity); - } - - if (mouse.click) { - scroll.drag.x = mouse.x; - scroll.drag.time = scroll.time; - scroll.drag.bar = mouse.y < 23; - if (scroll.drag.bar) { - scroll.drag.barTime = (mouse.x / (width - 300)) * timeNow - scroll.time; - scroll.drag.barMove = scroll.drag.barTime >= 0 && scroll.drag.barTime <= capacity; - } - scroll.auto = false; - root.classList.add('dragging'); - editor.emit('tools:scroll:start'); - } else if (mouse.down) { - if (scroll.drag.bar) { - if (scroll.drag.barMove) { - scroll.time = (mouse.x / (width - 300)) * timeNow - scroll.drag.barTime; - } else { - scroll.time = (mouse.x / (width - 300)) * timeNow - capacity / 2; - } - } else { - scroll.time = scroll.drag.time + (scroll.drag.x - mouse.x) / scale; - } - scroll.time = Math.max(0, Math.min(timeNow - capacity, Math.floor(scroll.time))); - } else if (mouse.up) { - if (Math.abs(scroll.time + capacity - timeNow) < 32) { - scroll.auto = true; - } - - root.classList.remove('dragging'); - editor.emit('tools:scroll:end'); - } - - if (mouse.hover && !mouse.down) { - if (mouse.y < 23) { - timeHover = Math.floor((mouse.x / (width - 300)) * timeNow); - } else if (mouse.y < 174) { - timeHover = Math.floor(mouse.x / scale + scroll.time); - } else { - timeHover = 0; - } - } else { - timeHover = 0; - } - - flushMouse(); - }; - - root.addEventListener( - 'mousemove', - (evt: MouseEvent) => { - evt.stopPropagation(); - - const rect = root.getBoundingClientRect(); - mouse.x = evt.clientX - (rect.left + 300); - mouse.y = evt.clientY - rect.top; - mouse.hover = mouse.x > 0; - if (mouse.y < 23) { - timeHover = Math.floor((mouse.x / (width - 300)) * timeNow); - } else { - timeHover = Math.floor(mouse.x / scale + scroll.time); - } - }, - false - ); - - root.addEventListener( - 'mousedown', - (evt: MouseEvent) => { - evt.stopPropagation(); - evt.preventDefault(); - - if (evt.button !== 0 || mouse.click || mouse.down || !mouse.hover) { - return; - } - - mouse.click = true; - }, - false - ); - - root.addEventListener( - 'mouseup', - (evt: MouseEvent) => { - evt.stopPropagation(); - - if (evt.button !== 0 || !mouse.down) { - return; - } - - mouse.down = false; - mouse.up = true; - }, - false - ); - - root.addEventListener( - 'mouseleave', - (_evt: MouseEvent) => { - mouse.hover = false; - timeHover = 0; - if (!mouse.down) { - return; - } - - mouse.down = false; - mouse.up = true; - }, - false - ); - - root.addEventListener( - 'mousewheel', - (evt: WheelEvent) => { - evt.stopPropagation(); - - if (!mouse.hover) { - return; - } - - scroll.time = Math.max(0, Math.min(timeNow - capacity, Math.floor(scroll.time + evt.deltaX / scale))); - if (evt.deltaX < 0) { - scroll.auto = false; - } else if (Math.abs(scroll.time + capacity - timeNow) < 16) { - scroll.auto = true; - } - }, - false - ); - - // alt + t - window.addEventListener( - 'keydown', - (evt: KeyboardEvent) => { - if (evt.keyCode === 84 && evt.altKey) { - if (enabled) { - editor.call('tools:disable'); - } else { - editor.call('tools:enable'); - } - } - }, - false - ); - - const app = editor.call('viewport:app'); - if (!app) { - return; - } // webgl not available - - let frameLast = 0; - - const onFrame = function () { - requestAnimationFrame(onFrame); - - if (enabled) { - const now = Date.now(); - - if (now - frameLast >= 40) { - frameLast = now; - - update(); - editor.emit('tools:render'); - } - } - }; - requestAnimationFrame(onFrame); -}); diff --git a/src/launch/viewport/viewport.ts b/src/launch/viewport/viewport.ts index ed8abf731..6da891d29 100644 --- a/src/launch/viewport/viewport.ts +++ b/src/launch/viewport/viewport.ts @@ -373,10 +373,17 @@ editor.once('load', () => { const miniStats = new (pc.MiniStats ? pc.MiniStats : pcx.MiniStats)(app); } - if (queryParams.inspector) { + // the profiler is the inspector's Performance tab, recording from the first frame + const profile = queryParams.profile === 'true'; + if (queryParams.inspector || profile) { const [major, minor] = pc.version.split('.').map(Number); if (major > 2 || (major === 2 && minor >= 23)) { - new Inspector(app); + const inspector = new Inspector(app, { record: profile }); + + // the inspector has no option to open a tab yet + if (profile) { + (inspector as any)._setTab?.('perf'); + } } else { console.warn(`The Inspector requires Engine 2.23 or later (running ${pc.version})`); } diff --git a/test-suite/test/launch/runtime.test.ts b/test-suite/test/launch/runtime.test.ts index 7656b678a..683f25427 100644 --- a/test-suite/test/launch/runtime.test.ts +++ b/test-suite/test/launch/runtime.test.ts @@ -124,16 +124,11 @@ test.describe('runtime', () => { } }); - test('toggle dev tools', async ({ project, openLaunch }) => { + test('open profiler', async ({ project, openLaunch }) => { const launch = await openLaunch(project.sceneId, { profile: true }); - const tools = launch.locator('#dev-tools'); - await expect(tools).toBeVisible(); - - await launch.keyboard.press('Alt+T'); - await expect(tools).toBeHidden(); - - await launch.keyboard.press('Alt+T'); - await expect(tools).toBeVisible(); + // the inspector on its Performance tab, already recording + await expect(launch.locator('.pci-tab.pci-active')).toHaveText('Performance'); + await expect(launch.locator('.pci-record')).toHaveAttribute('aria-label', 'Stop'); }); });