diamon-engine 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -365,28 +365,28 @@ class f extends a {
365
365
  maxDistance;
366
366
  azimuth;
367
367
  polar;
368
+ cameraDirty = !0;
368
369
  constructor(t = {}) {
369
370
  super(), this.target.copy(t.target ?? new i.Vector3()), this.distance = t.distance ?? 9, this.minDistance = t.minDistance ?? 4, this.maxDistance = t.maxDistance ?? 18, this.azimuth = t.azimuth ?? Math.PI * 0.25, this.polar = t.polar ?? Math.PI * 0.32;
370
371
  }
371
372
  onUpdate() {
372
373
  const t = this.scene, e = this.engine?.input;
373
- if (!t || !e)
374
- return;
375
- e.isMouseDown(0) && (this.azimuth -= e.pointerDelta.x * 6e-3, this.polar = i.MathUtils.clamp(
374
+ if (!t || !e || (e.isMouseDown(0) && e.pointerDelta.lengthSq() > 0 && (this.azimuth -= e.pointerDelta.x * 6e-3, this.polar = i.MathUtils.clamp(
376
375
  this.polar - e.pointerDelta.y * 6e-3,
377
376
  0.18,
378
377
  Math.PI * 0.48
379
- )), e.wheelDelta !== 0 && (this.distance = i.MathUtils.clamp(
378
+ ), this.cameraDirty = !0), e.wheelDelta !== 0 && (this.distance = i.MathUtils.clamp(
380
379
  this.distance + e.wheelDelta * 0.01,
381
380
  this.minDistance,
382
381
  this.maxDistance
383
- ));
382
+ ), this.cameraDirty = !0), !this.cameraDirty))
383
+ return;
384
384
  const s = Math.sin(this.polar) * this.distance;
385
385
  t.camera.position.set(
386
386
  this.target.x + Math.cos(this.azimuth) * s,
387
387
  this.target.y + Math.cos(this.polar) * this.distance,
388
388
  this.target.z + Math.sin(this.azimuth) * s
389
- ), t.camera.lookAt(this.target);
389
+ ), t.camera.lookAt(this.target), this.cameraDirty = !1;
390
390
  }
391
391
  }
392
392
  export {
@@ -1,12 +1,12 @@
1
- import * as a from "three";
2
- import { C as f } from "./OrbitCameraController-COklTntj.js";
3
- class y {
1
+ import * as n from "three";
2
+ import { C as f } from "./OrbitCameraController-CrUu0k53.js";
3
+ class w {
4
4
  constructor(e) {
5
- this.canvas = e, window.addEventListener("keydown", this.handleKeyDown), window.addEventListener("keyup", this.handleKeyUp), e.addEventListener("pointermove", this.handlePointerMove), e.addEventListener("pointerdown", this.handlePointerDown), e.addEventListener("pointerup", this.handlePointerUp), e.addEventListener("pointercancel", this.handlePointerUp), e.addEventListener("wheel", this.handleWheel, { passive: !1 });
5
+ this.canvas = e, this.refreshCanvasRect(), window.addEventListener("keydown", this.handleKeyDown), window.addEventListener("keyup", this.handleKeyUp), window.addEventListener("resize", this.handleWindowResize), e.addEventListener("pointermove", this.handlePointerMove), e.addEventListener("pointerdown", this.handlePointerDown), e.addEventListener("pointerup", this.handlePointerUp), e.addEventListener("pointercancel", this.handlePointerUp), e.addEventListener("wheel", this.handleWheel, { passive: !1 });
6
6
  }
7
7
  canvas;
8
- pointer = new a.Vector2();
9
- pointerDelta = new a.Vector2();
8
+ pointer = new n.Vector2();
9
+ pointerDelta = new n.Vector2();
10
10
  wheelDelta = 0;
11
11
  downKeys = /* @__PURE__ */ new Set();
12
12
  pressedKeys = /* @__PURE__ */ new Set();
@@ -14,6 +14,8 @@ class y {
14
14
  downButtons = /* @__PURE__ */ new Set();
15
15
  pressedButtons = /* @__PURE__ */ new Set();
16
16
  releasedButtons = /* @__PURE__ */ new Set();
17
+ canvasLeft = 0;
18
+ canvasTop = 0;
17
19
  isKeyDown(e) {
18
20
  return this.downKeys.has(this.normalizeKey(e));
19
21
  }
@@ -42,21 +44,27 @@ class y {
42
44
  this.downKeys.delete(t), this.releasedKeys.add(t);
43
45
  };
44
46
  handlePointerMove = (e) => {
45
- const t = this.pointerToCanvas(e);
46
- this.pointerDelta.set(t.x - this.pointer.x, t.y - this.pointer.y), this.pointer.copy(t);
47
+ const t = this.pointer.x, s = this.pointer.y;
48
+ this.setPointerFromEvent(e), this.pointerDelta.x += this.pointer.x - t, this.pointerDelta.y += this.pointer.y - s;
47
49
  };
48
50
  handlePointerDown = (e) => {
49
- this.canvas.focus(), this.canvas.setPointerCapture(e.pointerId), this.pointer.copy(this.pointerToCanvas(e)), this.downButtons.add(e.button), this.pressedButtons.add(e.button);
51
+ this.refreshCanvasRect(), this.canvas.focus(), this.canvas.setPointerCapture(e.pointerId), this.setPointerFromEvent(e), this.pointerDelta.set(0, 0), this.downButtons.add(e.button), this.pressedButtons.add(e.button);
50
52
  };
51
53
  handlePointerUp = (e) => {
52
- this.pointer.copy(this.pointerToCanvas(e)), this.downButtons.delete(e.button), this.releasedButtons.add(e.button);
54
+ this.setPointerFromEvent(e), this.downButtons.delete(e.button), this.releasedButtons.add(e.button);
53
55
  };
54
56
  handleWheel = (e) => {
55
57
  e.preventDefault(), this.wheelDelta += e.deltaY;
56
58
  };
57
- pointerToCanvas(e) {
58
- const t = this.canvas.getBoundingClientRect();
59
- return new a.Vector2(e.clientX - t.left, e.clientY - t.top);
59
+ handleWindowResize = () => {
60
+ this.refreshCanvasRect();
61
+ };
62
+ refreshCanvasRect() {
63
+ const e = this.canvas.getBoundingClientRect();
64
+ this.canvasLeft = e.left, this.canvasTop = e.top;
65
+ }
66
+ setPointerFromEvent(e) {
67
+ this.pointer.set(e.clientX - this.canvasLeft, e.clientY - this.canvasTop);
60
68
  }
61
69
  getKeyAliases(e) {
62
70
  return [e.code, e.key].filter(Boolean).map((t) => this.normalizeKey(t));
@@ -65,15 +73,21 @@ class y {
65
73
  return e.length === 1 ? e.toLowerCase() : e;
66
74
  }
67
75
  }
68
- class S {
76
+ class v {
69
77
  constructor(e) {
70
- this.options = e, this.options.canvas.tabIndex = 0, this.input = new y(this.options.canvas), this.renderer = new a.WebGLRenderer({
78
+ this.options = e, this.options.canvas.tabIndex = 0, this.input = new w(this.options.canvas), this.captureCanvasSize(), typeof ResizeObserver < "u" && (this.resizeObserver = new ResizeObserver((t) => {
79
+ const s = t[t.length - 1];
80
+ if (!s)
81
+ return;
82
+ const i = Math.max(1, Math.floor(s.contentRect.width)), a = Math.max(1, Math.floor(s.contentRect.height));
83
+ i === this.canvasWidth && a === this.canvasHeight || (this.canvasWidth = i, this.canvasHeight = a, this.resizeDirty = !0);
84
+ }), this.resizeObserver.observe(this.options.canvas)), window.addEventListener("resize", this.handleWindowResize), this.renderer = new n.WebGLRenderer({
71
85
  canvas: this.options.canvas,
72
86
  antialias: !0,
73
87
  alpha: !1,
74
88
  preserveDrawingBuffer: this.options.preserveDrawingBuffer ?? !1,
75
89
  powerPreference: "high-performance"
76
- }), this.renderer.setClearColor(new a.Color(e.background ?? "#07100f"), 1), this.configureShadows(e.shadowQuality ?? "off"), this.renderer.outputColorSpace = a.SRGBColorSpace;
90
+ }), this.renderer.setClearColor(new n.Color(e.background ?? "#07100f"), 1), this.configureShadows(e.shadowQuality ?? "off"), this.renderer.outputColorSpace = n.SRGBColorSpace;
77
91
  }
78
92
  options;
79
93
  renderer;
@@ -107,6 +121,12 @@ class S {
107
121
  resizeDirty = !0;
108
122
  slowQualitySamples = 0;
109
123
  fastQualitySamples = 0;
124
+ canvasWidth = 1;
125
+ canvasHeight = 1;
126
+ resizeObserver;
127
+ handleWindowResize = () => {
128
+ this.resizeDirty = !0;
129
+ };
110
130
  setScene(e) {
111
131
  this.activeScene?.stopInternal(), this.activeScene = e, e.startInternal(this), this.resize(), this.renderOnce();
112
132
  }
@@ -121,17 +141,17 @@ class S {
121
141
  }
122
142
  sampleFrame() {
123
143
  this.renderOnce();
124
- const e = this.renderer.getContext(), t = e.drawingBufferWidth, s = e.drawingBufferHeight, i = Math.max(1, Math.min(t, 96)), h = Math.max(1, Math.min(s, 64)), n = Math.floor((t - i) / 2), u = Math.floor((s - h) / 2), r = new Uint8Array(i * h * 4);
125
- e.readPixels(n, u, i, h, e.RGBA, e.UNSIGNED_BYTE, r);
126
- let m = 0;
127
- for (let o = 0; o < r.length; o += 4) {
128
- const l = r[o], d = r[o + 1], c = r[o + 2];
129
- (Math.max(l, d, c) - Math.min(l, d, c) > 12 || l + d + c > 60) && (m += 1);
144
+ const e = this.renderer.getContext(), t = e.drawingBufferWidth, s = e.drawingBufferHeight, i = Math.max(1, Math.min(t, 96)), a = Math.max(1, Math.min(s, 64)), u = Math.floor((t - i) / 2), m = Math.floor((s - a) / 2), r = new Uint8Array(i * a * 4);
145
+ e.readPixels(u, m, i, a, e.RGBA, e.UNSIGNED_BYTE, r);
146
+ let p = 0;
147
+ for (let h = 0; h < r.length; h += 4) {
148
+ const o = r[h], l = r[h + 1], d = r[h + 2];
149
+ (Math.max(o, l, d) - Math.min(o, l, d) > 12 || o + l + d > 60) && (p += 1);
130
150
  }
131
151
  return {
132
152
  width: t,
133
153
  height: s,
134
- coloredRatio: m / (r.length / 4)
154
+ coloredRatio: p / (r.length / 4)
135
155
  };
136
156
  }
137
157
  tick = (e) => {
@@ -145,10 +165,15 @@ class S {
145
165
  this.stats.frameTimeMs = Math.round(i * 10) / 10, this.updateFrameTimeAverage(i), this.updateFps(t), this.updateRenderStats(), this.input.endFrame(), this.animationFrame = requestAnimationFrame(this.tick);
146
166
  };
147
167
  resize() {
148
- const e = this.options.canvas.getBoundingClientRect(), t = Math.max(1, Math.floor(e.width)), s = Math.max(1, Math.floor(e.height)), i = this.options.maxPixelRatio ?? 2, h = this.options.minPixelRatio ?? 0.6, n = Math.round(
149
- Math.max(h, Math.min(window.devicePixelRatio || 1, i) * this.qualityScale) * 100
168
+ this.resizeDirty && !this.resizeObserver && this.captureCanvasSize();
169
+ const e = this.canvasWidth, t = this.canvasHeight, s = this.options.maxPixelRatio ?? 2, i = this.options.minPixelRatio ?? 0.6, a = Math.round(
170
+ Math.max(i, Math.min(window.devicePixelRatio || 1, s) * this.qualityScale) * 100
150
171
  ) / 100;
151
- this.stats.width = t, this.stats.height = s, this.stats.pixelRatio = n, this.stats.qualityScale = Math.round(this.qualityScale * 100) / 100, !(!this.resizeDirty && t === this.lastResizeWidth && s === this.lastResizeHeight && n === this.lastPixelRatio) && (this.resizeDirty = !1, this.lastResizeWidth = t, this.lastResizeHeight = s, this.lastPixelRatio = n, this.renderer.setPixelRatio(n), this.renderer.setSize(t, s, !1), this.activeScene && (this.activeScene.camera.aspect = t / s, this.activeScene.camera.updateProjectionMatrix()));
172
+ this.stats.width = e, this.stats.height = t, this.stats.pixelRatio = a, this.stats.qualityScale = Math.round(this.qualityScale * 100) / 100, !(!this.resizeDirty && e === this.lastResizeWidth && t === this.lastResizeHeight && a === this.lastPixelRatio) && (this.resizeDirty = !1, this.lastResizeWidth = e, this.lastResizeHeight = t, this.lastPixelRatio = a, this.renderer.setPixelRatio(a), this.renderer.setSize(e, t, !1), this.activeScene && (this.activeScene.camera.aspect = e / t, this.activeScene.camera.updateProjectionMatrix()));
173
+ }
174
+ captureCanvasSize() {
175
+ const e = this.options.canvas.getBoundingClientRect();
176
+ this.canvasWidth = Math.max(1, Math.floor(e.width)), this.canvasHeight = Math.max(1, Math.floor(e.height));
152
177
  }
153
178
  updateFrameTimeAverage(e) {
154
179
  this.frameTimeAverageMs = this.frameTimeAverageMs === 0 ? e : this.frameTimeAverageMs * 0.88 + e * 0.12, this.stats.frameTimeAverageMs = Math.round(this.frameTimeAverageMs * 10) / 10;
@@ -172,7 +197,7 @@ class S {
172
197
  this.fastQualitySamples >= 4 && this.qualityScale < 1 && (this.qualityScale = Math.min(1, this.qualityScale + 0.04), this.resizeDirty = !0, this.fastQualitySamples = 0);
173
198
  }
174
199
  configureShadows(e) {
175
- this.renderer.shadowMap.enabled = e !== "off", this.renderer.shadowMap.enabled && (this.renderer.shadowMap.type = e === "high" ? a.PCFSoftShadowMap : a.PCFShadowMap);
200
+ this.renderer.shadowMap.enabled = e !== "off", this.renderer.shadowMap.enabled && (this.renderer.shadowMap.type = e === "high" ? n.PCFSoftShadowMap : n.PCFShadowMap);
176
201
  }
177
202
  }
178
203
  class g extends f {
@@ -187,7 +212,7 @@ class g extends f {
187
212
  }
188
213
  }
189
214
  export {
190
- S as E,
191
- y as I,
215
+ v as E,
216
+ w as I,
192
217
  g as S
193
218
  };
@@ -1,5 +1,5 @@
1
- import { C as t, E as n, L as s, M as o, O as r, a as D, S as i } from "./OrbitCameraController-COklTntj.js";
2
- import { E as p, I as C, S as E } from "./Spin3D-BW0UYD9X.js";
1
+ import { C as t, E as n, L as s, M as o, O as r, a as D, S as i } from "./OrbitCameraController-CrUu0k53.js";
2
+ import { E as p, I as C, S as E } from "./Spin3D-CKrkOLkJ.js";
3
3
  export {
4
4
  t as Component3D,
5
5
  p as Engine3D,
@@ -1,5 +1,5 @@
1
- import { C as t, E as n, L as s, M as o, O as r, a as D, S as i } from "./OrbitCameraController-COklTntj.js";
2
- import { E as p, I as C, S as E } from "./Spin3D-BW0UYD9X.js";
1
+ import { C as t, E as n, L as s, M as o, O as r, a as D, S as i } from "./OrbitCameraController-CrUu0k53.js";
2
+ import { E as p, I as C, S as E } from "./Spin3D-CKrkOLkJ.js";
3
3
  export {
4
4
  t as Component3D,
5
5
  p as Engine3D,
@@ -15,6 +15,7 @@ export declare class OrbitCameraController extends Component3D {
15
15
  maxDistance: number;
16
16
  azimuth: number;
17
17
  polar: number;
18
+ private cameraDirty;
18
19
  constructor(options?: OrbitCameraControllerOptions);
19
20
  onUpdate(): void;
20
21
  }
@@ -45,6 +45,10 @@ export declare class Engine3D {
45
45
  private resizeDirty;
46
46
  private slowQualitySamples;
47
47
  private fastQualitySamples;
48
+ private canvasWidth;
49
+ private canvasHeight;
50
+ private readonly resizeObserver?;
51
+ private readonly handleWindowResize;
48
52
  constructor(options: Engine3DOptions);
49
53
  setScene(scene: Scene3D): void;
50
54
  start(): void;
@@ -57,6 +61,7 @@ export declare class Engine3D {
57
61
  };
58
62
  private readonly tick;
59
63
  private resize;
64
+ private captureCanvasSize;
60
65
  private updateFrameTimeAverage;
61
66
  private updateFps;
62
67
  private updateRenderStats;
@@ -10,6 +10,8 @@ export declare class Input3D {
10
10
  private readonly downButtons;
11
11
  private readonly pressedButtons;
12
12
  private readonly releasedButtons;
13
+ private canvasLeft;
14
+ private canvasTop;
13
15
  constructor(canvas: HTMLCanvasElement);
14
16
  isKeyDown(key: string): boolean;
15
17
  wasKeyPressed(key: string): boolean;
@@ -23,7 +25,9 @@ export declare class Input3D {
23
25
  private readonly handlePointerDown;
24
26
  private readonly handlePointerUp;
25
27
  private readonly handleWheel;
26
- private pointerToCanvas;
28
+ private readonly handleWindowResize;
29
+ private refreshCanvasRect;
30
+ private setPointerFromEvent;
27
31
  private getKeyAliases;
28
32
  private normalizeKey;
29
33
  }
@@ -1,36 +1,36 @@
1
1
  import * as l from "three";
2
- import { GLTFLoader as L } from "three/examples/jsm/loaders/GLTFLoader.js";
3
- import { E as m, S as A, O as y, M as $, a as P, L as R, C as E } from "./OrbitCameraController-COklTntj.js";
4
- const U = {
2
+ import { GLTFLoader as T } from "three/examples/jsm/loaders/GLTFLoader.js";
3
+ import { E as m, S as O, O as y, M as C, a as U, L as x, C as P } from "./OrbitCameraController-CrUu0k53.js";
4
+ const E = {
5
5
  box: "#1ec7a6",
6
6
  sphere: "#f5c95f",
7
7
  cylinder: "#4ba3ff",
8
8
  cone: "#ef6f50",
9
9
  torus: "#d989ff"
10
- }, M = {
10
+ }, $ = {
11
11
  box: "Cube",
12
12
  sphere: "Sphere",
13
13
  cylinder: "Cylinder",
14
14
  cone: "Cone",
15
15
  torus: "Torus"
16
- }, T = {
16
+ }, A = {
17
17
  box: { kind: "box", width: 1, height: 1, depth: 1 },
18
18
  sphere: { kind: "sphere", radius: 0.62 },
19
19
  cylinder: { kind: "cylinder", radius: 0.52, height: 1.15 },
20
20
  cone: { kind: "cone", radius: 0.6, height: 1.25 },
21
21
  torus: { kind: "torus", radius: 0.62, tube: 0.18 }
22
- }, D = 700, H = 2500, F = 12e4, _ = 8e3, B = 5e9, j = 0.07;
23
- function te(r) {
22
+ }, D = 700, H = 2500, _ = 12e4, F = 8e3, N = 5e9, j = 0.07, B = 1e3;
23
+ function se(r) {
24
24
  return new G(r);
25
25
  }
26
26
  class G {
27
27
  constructor(e) {
28
- this.ui = e, this.scene.threeScene.background = new l.Color("#07100f"), this.scene.threeScene.fog = new l.Fog("#07100f", 32, 90), this.scene.add(q()), this.scene.add(z()), this.scene.add(W()), this.scene.add(K()), this.scene.add(V());
28
+ this.ui = e, this.scene.threeScene.background = new l.Color("#07100f"), this.scene.threeScene.fog = new l.Fog("#07100f", 32, 90), this.scene.add(W()), this.scene.add(q()), this.scene.add(K()), this.scene.add(V()), this.scene.add(X());
29
29
  const t = new m("Workbench Runtime");
30
- t.addComponent(new N(() => this.updateRuntimeUi(), 0.25)), this.scene.add(t), this.addPrimitive("box"), this.addPrimitive("sphere"), this.addPrimitive("cylinder"), this.commitHistory("初始场景"), this.bindCanvasPicking(), this.refreshUi(), this.log("引擎编辑器已启动");
30
+ t.addComponent(new z(() => this.updateRuntimeUi(), 0.25)), this.scene.add(t), this.addPrimitive("box"), this.addPrimitive("sphere"), this.addPrimitive("cylinder"), this.commitHistory("初始场景"), this.bindCanvasPicking(), this.bindSceneTreeSelection(), this.bindPrefabList(), this.refreshUi(), this.log("引擎编辑器已启动");
31
31
  }
32
32
  ui;
33
- scene = new A("Engine Workbench");
33
+ scene = new O("Engine Workbench");
34
34
  objects = /* @__PURE__ */ new Map();
35
35
  resources = /* @__PURE__ */ new Map();
36
36
  prefabs = /* @__PURE__ */ new Map();
@@ -40,16 +40,22 @@ class G {
40
40
  clipboard = [];
41
41
  raycaster = new l.Raycaster();
42
42
  pointer = new l.Vector2();
43
- gltfLoader = new L();
43
+ gltfLoader = new T();
44
44
  objectSerial = 0;
45
45
  resourceSerial = 0;
46
46
  prefabSerial = 0;
47
47
  groupSerial = 0;
48
48
  lastStressResult = "未测试";
49
49
  restoring = !1;
50
+ logicalCountsDirty = !0;
51
+ logicalObjectCountCache = 0;
52
+ logicalVisibleObjectCountCache = 0;
53
+ lastMemorySampleMs = 0;
54
+ memoryTextCache = "未知";
55
+ uiTextCache = /* @__PURE__ */ new Map();
50
56
  addPrimitive(e) {
51
57
  const t = this.createPrimitiveRecord(e);
52
- return this.selectOnly(t.id), this.commitHistory(`添加 ${M[e]}`), this.refreshUi(), t.entity;
58
+ return this.selectOnly(t.id), this.commitHistory(`添加 ${$[e]}`), this.refreshUi(), t.entity;
53
59
  }
54
60
  copySelection() {
55
61
  this.clipboard.length = 0;
@@ -161,40 +167,40 @@ class G {
161
167
  const t = performance.now();
162
168
  this.selectedIds.clear();
163
169
  const s = Math.ceil(Math.sqrt(e));
164
- for (let o = 0; o < e; o += 1) {
165
- const i = this.createPrimitiveRecord("box", {
170
+ for (let n = 0; n < e; n += 1) {
171
+ const o = this.createPrimitiveRecord("box", {
166
172
  name: `Stress Cube ${this.objectSerial + 1}`,
167
- color: o % 2 === 0 ? "#1ec7a6" : "#4ba3ff",
173
+ color: n % 2 === 0 ? "#1ec7a6" : "#4ba3ff",
168
174
  position: [
169
- o % s * 0.78 - s * 0.39,
175
+ n % s * 0.78 - s * 0.39,
170
176
  0.45,
171
- Math.floor(o / s) * 0.78 + 5
177
+ Math.floor(n / s) * 0.78 + 5
172
178
  ],
173
179
  layer: 2,
174
180
  group: "Stress Objects"
175
181
  });
176
- o < 20 && this.selectedIds.add(i.id);
182
+ n < 20 && this.selectedIds.add(o.id);
177
183
  }
178
- const n = Math.round(performance.now() - t);
179
- this.lastStressResult = `新增 ${e} 个对象,用时 ${n}ms`, this.commitHistory("大量对象压力测试"), this.refreshUi(), this.log(this.lastStressResult);
184
+ const i = Math.round(performance.now() - t);
185
+ this.lastStressResult = `新增 ${e} 个对象,用时 ${i}ms`, this.commitHistory("大量对象压力测试"), this.refreshUi(), this.log(this.lastStressResult);
180
186
  }
181
187
  addInstancedStressObjects(e) {
182
188
  const t = performance.now(), s = new m(`Instanced Stress ${e}`);
183
189
  s.tag = "workbench-object";
184
- const n = new l.BoxGeometry(0.42, 0.42, 0.42), o = new l.MeshStandardMaterial({
190
+ const i = new l.BoxGeometry(0.42, 0.42, 0.42), n = new l.MeshStandardMaterial({
185
191
  color: "#1ec7a6",
186
192
  roughness: 0.65,
187
193
  metalness: 0.08
188
- }), i = new l.InstancedMesh(n, o, e);
189
- i.castShadow = !1, i.receiveShadow = !1;
190
- const c = new l.Matrix4(), a = Math.ceil(Math.sqrt(e));
194
+ }), o = new l.InstancedMesh(i, n, e);
195
+ o.castShadow = !1, o.receiveShadow = !1;
196
+ const a = new l.Matrix4(), c = Math.ceil(Math.sqrt(e));
191
197
  for (let f = 0; f < e; f += 1) {
192
- const g = f % a * 0.55 - a * 0.275, S = Math.floor(f / a) * 0.55 + 16;
193
- c.makeTranslation(g, 0.35, S), i.setMatrixAt(f, c);
198
+ const g = f % c * 0.55 - c * 0.275, S = Math.floor(f / c) * 0.55 + 16;
199
+ a.makeTranslation(g, 0.35, S), o.setMatrixAt(f, a);
194
200
  }
195
- i.instanceMatrix.needsUpdate = !0, i.userData.workbenchId = `object-${this.objectSerial + 1}`, s.addComponent(new y(i, { disposeOnDestroy: !0 }));
196
- const d = this.nextObjectId(), u = {
197
- id: d,
201
+ o.instanceMatrix.needsUpdate = !0, o.userData.workbenchId = `object-${this.objectSerial + 1}`, s.addComponent(new y(o, { disposeOnDestroy: !0 }));
202
+ const h = this.nextObjectId(), u = {
203
+ id: h,
198
204
  entity: s,
199
205
  kind: "instanced",
200
206
  primitiveKind: "box",
@@ -205,26 +211,26 @@ class G {
205
211
  locked: !1,
206
212
  visible: !0
207
213
  };
208
- i.userData.workbenchId = d, this.scene.add(s), this.objects.set(d, u), this.selectOnly(d);
214
+ o.userData.workbenchId = h, this.scene.add(s), this.objects.set(h, u), this.invalidateLogicalCounts(), this.selectOnly(h);
209
215
  const v = Math.round(performance.now() - t);
210
216
  this.lastStressResult = `实例化 ${e} 个对象,用时 ${v}ms`, this.commitHistory("实例化压力测试"), this.refreshUi(), this.log(this.lastStressResult);
211
217
  }
212
218
  addMegaInstancedStressObjects(e) {
213
219
  const t = performance.now(), s = this.getMegaStressRecord();
214
220
  if (s) {
215
- const n = (s.instancedCount ?? 0) + e;
216
- this.updateMegaStressRecord(s, n, t, "合并极限压力层", "极限实例化累计");
221
+ const i = (s.instancedCount ?? 0) + e;
222
+ this.updateMegaStressRecord(s, i, t, "合并极限压力层", "极限实例化累计");
217
223
  return;
218
224
  }
219
225
  this.createMegaStressRecord(e, t, "500万对象极限压力测试", "极限实例化");
220
226
  }
221
227
  setMegaInstancedStressObjects(e) {
222
- const t = performance.now(), s = Y(e), n = `设置${s}极限压力层`, o = `${s}目标`, i = this.getMegaStressRecord();
223
- if (i) {
224
- this.updateMegaStressRecord(i, e, t, n, o);
228
+ const t = performance.now(), s = Z(e), i = `设置${s}极限压力层`, n = `${s}目标`, o = this.getMegaStressRecord();
229
+ if (o) {
230
+ this.updateMegaStressRecord(o, e, t, i, n);
225
231
  return;
226
232
  }
227
- this.createMegaStressRecord(e, t, n, o);
233
+ this.createMegaStressRecord(e, t, i, n);
228
234
  }
229
235
  importAssets(e) {
230
236
  const t = Array.from(e);
@@ -248,38 +254,38 @@ class G {
248
254
  };
249
255
  }
250
256
  createPrimitiveRecord(e, t = {}) {
251
- const s = this.nextObjectId(), n = this.objectSerial, o = new m(t.name ?? `${M[e]} ${n}`);
252
- o.tag = "workbench-object";
253
- const i = t.position ?? [
254
- -3 + n % 6 * 1.15,
257
+ const s = this.nextObjectId(), i = this.objectSerial, n = new m(t.name ?? `${$[e]} ${i}`);
258
+ n.tag = "workbench-object";
259
+ const o = t.position ?? [
260
+ -3 + i % 6 * 1.15,
255
261
  0.62,
256
- Math.floor(n / 6) * 1.15
262
+ Math.floor(i / 6) * 1.15
257
263
  ];
258
- o.position.set(i[0], i[1], i[2]), t.rotation && o.rotation.set(t.rotation[0], t.rotation[1], t.rotation[2]), t.scale && o.scale.set(t.scale[0], t.scale[1], t.scale[2]);
259
- const c = t.color ?? U[e];
260
- o.addComponent(
261
- new $({
262
- ...T[e],
263
- color: c,
264
+ n.position.set(o[0], o[1], o[2]), t.rotation && n.rotation.set(t.rotation[0], t.rotation[1], t.rotation[2]), t.scale && n.scale.set(t.scale[0], t.scale[1], t.scale[2]);
265
+ const a = t.color ?? E[e];
266
+ n.addComponent(
267
+ new C({
268
+ ...A[e],
269
+ color: a,
264
270
  segments: 24,
265
271
  metalness: 0.14,
266
272
  roughness: 0.5
267
273
  })
268
- ), o.object.traverse((d) => {
269
- d.userData.workbenchId = s;
274
+ ), n.object.traverse((h) => {
275
+ h.userData.workbenchId = s;
270
276
  });
271
- const a = {
277
+ const c = {
272
278
  id: s,
273
- entity: o,
279
+ entity: n,
274
280
  kind: "primitive",
275
281
  primitiveKind: e,
276
- color: c,
282
+ color: a,
277
283
  layer: t.layer ?? 0,
278
284
  group: t.group ?? "",
279
285
  locked: t.locked ?? !1,
280
286
  visible: t.visible ?? !0
281
287
  };
282
- return o.enabled = a.visible, o.object.visible = a.visible, this.scene.add(o), this.objects.set(s, a), a;
288
+ return n.enabled = c.visible, n.object.visible = c.visible, this.scene.add(n), this.objects.set(s, c), this.invalidateLogicalCounts(), c;
283
289
  }
284
290
  createRecordFromSerialized(e) {
285
291
  return e.kind === "mega-instanced" ? this.createMegaInstancedRecordFromSerialized(e) : e.kind === "instanced" ? this.createInstancedRecordFromSerialized(e) : e.kind === "model" ? this.createModelPlaceholder(e) : this.createPrimitiveRecord(e.primitiveKind ?? "box", e);
@@ -308,27 +314,27 @@ class G {
308
314
  }
309
315
  registerAsset(e) {
310
316
  this.resourceSerial += 1;
311
- const t = `asset-${this.resourceSerial}`, s = J(e.name), n = URL.createObjectURL(e), o = {
317
+ const t = `asset-${this.resourceSerial}`, s = J(e.name), i = URL.createObjectURL(e), n = {
312
318
  id: t,
313
319
  kind: s,
314
320
  name: e.name,
315
321
  size: e.size,
316
- url: n
322
+ url: i
317
323
  };
318
- this.resources.set(t, o), this.log(`导入资源:${e.name}`), s === "model" && this.gltfLoader.load(
319
- n,
320
- (i) => {
321
- const c = new m(e.name.replace(/\.[^.]+$/, ""));
322
- c.tag = "workbench-object", c.position.set(0, 0, 3 + this.objects.size * 0.45), i.scene.traverse((u) => {
324
+ this.resources.set(t, n), this.log(`导入资源:${e.name}`), s === "model" && this.gltfLoader.load(
325
+ i,
326
+ (o) => {
327
+ const a = new m(e.name.replace(/\.[^.]+$/, ""));
328
+ a.tag = "workbench-object", a.position.set(0, 0, 3 + this.objects.size * 0.45), o.scene.traverse((u) => {
323
329
  u.userData.workbenchId = t, u instanceof l.Mesh && (u.castShadow = !0, u.receiveShadow = !0);
324
- }), c.addComponent(new y(i.scene));
325
- const a = this.nextObjectId();
326
- i.scene.traverse((u) => {
327
- u.userData.workbenchId = a;
330
+ }), a.addComponent(new y(o.scene));
331
+ const c = this.nextObjectId();
332
+ o.scene.traverse((u) => {
333
+ u.userData.workbenchId = c;
328
334
  });
329
- const d = {
330
- id: a,
331
- entity: c,
335
+ const h = {
336
+ id: c,
337
+ entity: a,
332
338
  kind: "model",
333
339
  resourceId: t,
334
340
  color: "#ffffff",
@@ -337,20 +343,20 @@ class G {
337
343
  locked: !1,
338
344
  visible: !0
339
345
  };
340
- this.scene.add(c), this.objects.set(a, d), this.selectOnly(a), this.commitHistory("导入模型"), this.refreshUi(), this.log(`模型已加入场景:${e.name}`);
346
+ this.scene.add(a), this.objects.set(c, h), this.invalidateLogicalCounts(), this.selectOnly(c), this.commitHistory("导入模型"), this.refreshUi(), this.log(`模型已加入场景:${e.name}`);
341
347
  },
342
348
  void 0,
343
- (i) => this.log(`模型加载失败:${i instanceof Error ? i.message : String(i)}`)
349
+ (o) => this.log(`模型加载失败:${o instanceof Error ? o.message : String(o)}`)
344
350
  );
345
351
  }
346
- createMegaStressRecord(e, t, s, n) {
347
- const o = this.nextObjectId(), i = new m(`Mega Instance Stress ${e}`);
348
- i.tag = "workbench-object";
349
- const c = this.createMegaStressPoints(e, o);
350
- i.addComponent(new y(c, { disposeOnDestroy: !0 }));
351
- const a = {
352
- id: o,
353
- entity: i,
352
+ createMegaStressRecord(e, t, s, i) {
353
+ const n = this.nextObjectId(), o = new m(`Mega Instance Stress ${e}`);
354
+ o.tag = "workbench-object";
355
+ const a = this.createMegaStressPoints(e, n);
356
+ o.addComponent(new y(a, { disposeOnDestroy: !0 }));
357
+ const c = {
358
+ id: n,
359
+ entity: o,
354
360
  kind: "mega-instanced",
355
361
  primitiveKind: "box",
356
362
  instancedCount: e,
@@ -360,33 +366,33 @@ class G {
360
366
  locked: !1,
361
367
  visible: !0
362
368
  };
363
- return this.scene.add(i), this.objects.set(o, a), this.selectOnly(o), this.finishMegaStressUpdate(a, t, s, n), a;
369
+ return this.scene.add(o), this.objects.set(n, c), this.invalidateLogicalCounts(), this.selectOnly(n), this.finishMegaStressUpdate(c, t, s, i), c;
364
370
  }
365
- updateMegaStressRecord(e, t, s, n, o) {
366
- const i = this.createMegaStressPoints(t, e.id);
367
- e.entity.getComponent(y)?.replaceObject(i), e.instancedCount = t, e.entity.name = `Mega Instance Stress ${t}`, e.entity.object.name = e.entity.name, this.selectOnly(e.id), this.finishMegaStressUpdate(e, s, n, o);
371
+ updateMegaStressRecord(e, t, s, i, n) {
372
+ const o = this.createMegaStressPoints(t, e.id);
373
+ e.entity.getComponent(y)?.replaceObject(o), e.instancedCount = t, e.entity.name = `Mega Instance Stress ${t}`, e.entity.object.name = e.entity.name, this.invalidateLogicalCounts(), this.selectOnly(e.id), this.finishMegaStressUpdate(e, s, i, n);
368
374
  }
369
- finishMegaStressUpdate(e, t, s, n) {
370
- const o = e.instancedCount ?? 0, i = C(o), c = Math.round(performance.now() - t);
371
- this.lastStressResult = `${n} ${o} 个对象,渲染代表点 ${i},用时 ${c}ms`, this.commitHistory(s), this.refreshUi(), this.log(this.lastStressResult);
375
+ finishMegaStressUpdate(e, t, s, i) {
376
+ const n = e.instancedCount ?? 0, o = k(n), a = Math.round(performance.now() - t);
377
+ this.lastStressResult = `${i} ${n} 个对象,渲染代表点 ${o},用时 ${a}ms`, this.commitHistory(s), this.refreshUi(), this.log(this.lastStressResult);
372
378
  }
373
379
  createMegaStressPoints(e, t) {
374
- const s = C(e), n = new Float32Array(s * 3), o = H, i = Math.ceil(e / o), c = (o - 1) * j, a = (i - 1) * j;
380
+ const s = k(e), i = new Float32Array(s * 3), n = H, o = Math.ceil(e / n), a = (n - 1) * j, c = (o - 1) * j;
375
381
  for (let g = 0; g < s; g += 1) {
376
- const S = g * 3, k = Math.min(e - 1, Math.floor(g / s * e)), I = k % o, O = Math.floor(k / o);
377
- n[S] = I * j - c * 0.5, n[S + 1] = 0.32 + g * 17 % 11 * 0.01, n[S + 2] = O * j + 8;
382
+ const S = g * 3, M = Math.min(e - 1, Math.floor(g / s * e)), I = M % n, L = Math.floor(M / n);
383
+ i[S] = I * j - a * 0.5, i[S + 1] = 0.32 + g * 17 % 11 * 0.01, i[S + 2] = L * j + 8;
378
384
  }
379
- const d = new l.BufferGeometry(), u = new l.BufferAttribute(n, 3);
380
- u.setUsage(l.StaticDrawUsage), d.setAttribute("position", u), d.boundingSphere = new l.Sphere(
381
- new l.Vector3(0, 0.4, 8 + a * 0.5),
382
- Math.sqrt((c * 0.5) ** 2 + (a * 0.5) ** 2 + 2)
385
+ const h = new l.BufferGeometry(), u = new l.BufferAttribute(i, 3);
386
+ u.setUsage(l.StaticDrawUsage), h.setAttribute("position", u), h.boundingSphere = new l.Sphere(
387
+ new l.Vector3(0, 0.4, 8 + c * 0.5),
388
+ Math.sqrt((a * 0.5) ** 2 + (c * 0.5) ** 2 + 2)
383
389
  );
384
390
  const v = new l.PointsMaterial({
385
391
  color: "#75f0c8",
386
392
  size: 0.055,
387
393
  sizeAttenuation: !0,
388
394
  depthWrite: !1
389
- }), f = new l.Points(d, v);
395
+ }), f = new l.Points(h, v);
390
396
  return f.frustumCulled = !1, f.userData.workbenchId = t, f;
391
397
  }
392
398
  selectOnly(e) {
@@ -402,7 +408,7 @@ class G {
402
408
  return this.getSelectedRecords()[0];
403
409
  }
404
410
  removeRecord(e) {
405
- this.scene.remove(e.entity), this.objects.delete(e.id);
411
+ this.scene.remove(e.entity), this.objects.delete(e.id), this.invalidateLogicalCounts();
406
412
  }
407
413
  commitHistory(e) {
408
414
  this.restoring || (this.undoStack.push(this.makeSnapshot()), this.undoStack.length > 60 && this.undoStack.shift(), this.redoStack.length = 0, e && this.log(e));
@@ -435,14 +441,14 @@ class G {
435
441
  });
436
442
  for (const t of e.objects ?? []) {
437
443
  const s = this.createRecordFromSerialized(t);
438
- t.id && t.id !== s.id && (this.objects.delete(s.id), s.id = t.id, s.entity.object.traverse((n) => {
439
- n.userData.workbenchId = s.id;
444
+ t.id && t.id !== s.id && (this.objects.delete(s.id), s.id = t.id, s.entity.object.traverse((i) => {
445
+ i.userData.workbenchId = s.id;
440
446
  }), this.objects.set(s.id, s));
441
447
  }
442
448
  this.restoring = !1, this.refreshUi();
443
449
  }
444
450
  serializeObject(e, t) {
445
- const s = e.entity, n = {
451
+ const s = e.entity, i = {
446
452
  name: s.name,
447
453
  kind: e.kind,
448
454
  primitiveKind: e.primitiveKind,
@@ -457,38 +463,52 @@ class G {
457
463
  rotation: [s.rotation.x, s.rotation.y, s.rotation.z],
458
464
  scale: [s.scale.x, s.scale.y, s.scale.z]
459
465
  };
460
- return t && (n.id = e.id), n;
466
+ return t && (i.id = e.id), i;
461
467
  }
462
468
  refreshUi() {
463
469
  this.renderSceneTree(), this.renderResourceList(), this.renderPrefabList(), this.renderPropertyPanel(), this.updateRuntimeUi();
464
470
  }
465
471
  updateRuntimeUi() {
466
- const e = this.scene.engine?.stats, t = this.primarySelection(), s = this.logicalObjectCount(), n = this.logicalVisibleObjectCount(), o = Z(), i = this.detectSlowSystem();
467
- this.ui.objects.textContent = `${s}`, this.ui.visible.textContent = `${n}`, this.ui.drawCalls.textContent = `${e?.drawCalls ?? 0}`, this.ui.triangles.textContent = `${e?.triangles ?? 0}`, this.ui.fps.textContent = `${e?.fps ?? 0}`, this.ui.frame.textContent = `${e?.frameTimeMs ?? 0}ms`, this.ui.geometries.textContent = `${e?.geometries ?? 0}`, this.ui.textures.textContent = `${e?.textures ?? 0}`, this.ui.assets.textContent = `${this.resources.size}`, this.ui.memory.textContent = o, this.ui.quality.textContent = `${Math.round((e?.qualityScale ?? 1) * 100)}%`, this.ui.slowSystem.textContent = i, this.ui.state.textContent = `编辑器运行中 · ${this.lastStressResult}`, this.ui.selected.textContent = t ? t.entity.name : `${this.selectedIds.size} 个对象`;
472
+ const e = this.scene.engine?.stats, t = this.primarySelection(), s = this.logicalObjectCount(), i = this.logicalVisibleObjectCount(), n = this.getMemoryText(), o = this.detectSlowSystem();
473
+ this.setUiText(this.ui.objects, `${s}`), this.setUiText(this.ui.visible, `${i}`), this.setUiText(this.ui.drawCalls, `${e?.drawCalls ?? 0}`), this.setUiText(this.ui.triangles, `${e?.triangles ?? 0}`), this.setUiText(this.ui.fps, `${e?.fps ?? 0}`), this.setUiText(this.ui.frame, `${e?.frameTimeMs ?? 0}ms`), this.setUiText(this.ui.geometries, `${e?.geometries ?? 0}`), this.setUiText(this.ui.textures, `${e?.textures ?? 0}`), this.setUiText(this.ui.assets, `${this.resources.size}`), this.setUiText(this.ui.memory, n), this.setUiText(this.ui.quality, `${Math.round((e?.qualityScale ?? 1) * 100)}%`), this.setUiText(this.ui.slowSystem, o), this.setUiText(this.ui.state, `编辑器运行中 · ${this.lastStressResult}`), this.setUiText(this.ui.selected, t ? t.entity.name : `${this.selectedIds.size} 个对象`);
474
+ }
475
+ setUiText(e, t) {
476
+ this.uiTextCache.get(e) !== t && (e.textContent = t, this.uiTextCache.set(e, t));
477
+ }
478
+ getMemoryText() {
479
+ const e = performance.now();
480
+ return e - this.lastMemorySampleMs < B ? this.memoryTextCache : (this.lastMemorySampleMs = e, this.memoryTextCache = Q(), this.memoryTextCache);
468
481
  }
469
482
  renderSceneTree() {
470
- const e = Array.from(this.objects.values()), t = e.filter((i) => this.selectedIds.has(i.id)), s = e.filter((i) => !this.selectedIds.has(i.id)), n = [...t, ...s].slice(0, D), o = n.map((i) => {
471
- const c = this.selectedIds.has(i.id) ? " is-selected" : "", a = i.visible ? "" : " is-hidden", d = i.group ? ` · ${i.group}` : "";
472
- return `<div class="tree-row${c}${a}" data-id="${i.id}">
473
- <span class="tree-name">${w(i.entity.name)}</span>
474
- <span class="tree-meta">L${i.layer}${d}</span>
483
+ const e = [], t = [];
484
+ for (const o of this.objects.values())
485
+ this.selectedIds.has(o.id) ? e.push(o) : t.push(o);
486
+ const s = e.length + t.length, i = [...e, ...t].slice(0, D), n = i.map((o) => {
487
+ const a = this.selectedIds.has(o.id) ? " is-selected" : "", c = o.visible ? "" : " is-hidden", h = o.group ? ` · ${o.group}` : "";
488
+ return `<div class="tree-row${a}${c}" data-id="${o.id}">
489
+ <span class="tree-name">${w(o.entity.name)}</span>
490
+ <span class="tree-meta">L${o.layer}${h}</span>
475
491
  </div>`;
476
492
  });
477
- e.length > n.length && o.push(`<div class="tree-row">
478
- <span class="tree-name">已省略 ${e.length - n.length} 个编辑对象</span>
479
- <span class="tree-meta">场景总数 ${e.length},逻辑对象 ${this.logicalObjectCount()}</span>
480
- </div>`), this.ui.sceneTree.innerHTML = o.join("") || '<div class="tree-row">空场景</div>';
481
- for (const i of Array.from(this.ui.sceneTree.querySelectorAll(".tree-row[data-id]")))
482
- i.addEventListener("click", (c) => {
483
- const a = i.dataset.id;
484
- a && (c.shiftKey || c.metaKey ? this.selectedIds.has(a) ? this.selectedIds.delete(a) : this.selectedIds.add(a) : this.selectOnly(a), this.refreshUi());
485
- });
493
+ s > i.length && n.push(`<div class="tree-row">
494
+ <span class="tree-name">已省略 ${s - i.length} 个编辑对象</span>
495
+ <span class="tree-meta">场景总数 ${s},逻辑对象 ${this.logicalObjectCount()}</span>
496
+ </div>`), this.ui.sceneTree.innerHTML = n.join("") || '<div class="tree-row">空场景</div>';
497
+ }
498
+ bindSceneTreeSelection() {
499
+ this.ui.sceneTree.addEventListener("click", (e) => {
500
+ const t = e.target;
501
+ if (!(t instanceof HTMLElement))
502
+ return;
503
+ const s = t.closest(".tree-row[data-id]"), i = s?.dataset.id;
504
+ !s || !this.ui.sceneTree.contains(s) || !i || (e.shiftKey || e.metaKey ? this.selectedIds.has(i) ? this.selectedIds.delete(i) : this.selectedIds.add(i) : this.selectOnly(i), this.refreshUi());
505
+ });
486
506
  }
487
507
  renderResourceList() {
488
508
  const e = Array.from(this.resources.values()).map(
489
509
  (t) => `<div class="resource-row">
490
510
  <span class="resource-name">${w(t.name)}</span>
491
- <span class="resource-kind">${t.kind} · ${x(t.size)}</span>
511
+ <span class="resource-kind">${t.kind} · ${R(t.size)}</span>
492
512
  </div>`
493
513
  );
494
514
  this.ui.resourceList.innerHTML = e.join("") || '<div class="resource-row">暂无资源</div>';
@@ -501,22 +521,29 @@ class G {
501
521
  </button>`
502
522
  );
503
523
  this.ui.prefabList.innerHTML = e.join("") || '<div class="resource-row">暂无预制体</div>';
504
- for (const t of Array.from(this.ui.prefabList.querySelectorAll("[data-prefab]")))
505
- t.addEventListener("click", () => {
506
- const s = this.prefabs.get(t.dataset.prefab ?? "");
507
- if (s) {
508
- this.selectedIds.clear();
509
- for (const n of s.objects) {
510
- const o = this.createRecordFromSerialized({
511
- ...n,
512
- name: `${n.name} Instance`,
513
- position: [n.position[0] + 1, n.position[1], n.position[2] + 1]
514
- });
515
- this.selectedIds.add(o.id);
516
- }
517
- this.commitHistory(`实例化预制体 ${s.name}`), this.refreshUi();
524
+ }
525
+ bindPrefabList() {
526
+ this.ui.prefabList.addEventListener("click", (e) => {
527
+ const t = e.target;
528
+ if (!(t instanceof HTMLElement))
529
+ return;
530
+ const s = t.closest("[data-prefab]");
531
+ if (!s || !this.ui.prefabList.contains(s))
532
+ return;
533
+ const i = this.prefabs.get(s.dataset.prefab ?? "");
534
+ if (i) {
535
+ this.selectedIds.clear();
536
+ for (const n of i.objects) {
537
+ const o = this.createRecordFromSerialized({
538
+ ...n,
539
+ name: `${n.name} Instance`,
540
+ position: [n.position[0] + 1, n.position[1], n.position[2] + 1]
541
+ });
542
+ this.selectedIds.add(o.id);
518
543
  }
519
- });
544
+ this.commitHistory(`实例化预制体 ${i.name}`), this.refreshUi();
545
+ }
546
+ });
520
547
  }
521
548
  renderPropertyPanel() {
522
549
  const e = this.primarySelection();
@@ -527,19 +554,19 @@ class G {
527
554
  const t = e.entity;
528
555
  this.ui.propertyPanel.innerHTML = `
529
556
  <div class="property-grid">
530
- ${h("名称", "name", t.name, "text", "full")}
531
- ${h("X", "px", b(t.position.x))}
532
- ${h("Y", "py", b(t.position.y))}
533
- ${h("Z", "pz", b(t.position.z))}
534
- ${h("旋转X", "rx", b(t.rotation.x))}
535
- ${h("旋转Y", "ry", b(t.rotation.y))}
536
- ${h("旋转Z", "rz", b(t.rotation.z))}
537
- ${h("缩放X", "sx", b(t.scale.x))}
538
- ${h("缩放Y", "sy", b(t.scale.y))}
539
- ${h("缩放Z", "sz", b(t.scale.z))}
540
- ${h("颜色", "color", e.color, "color")}
541
- ${h("图层", "layer", `${e.layer}`, "number")}
542
- ${h("分组", "group", e.group, "text")}
557
+ ${d("名称", "name", t.name, "text", "full")}
558
+ ${d("X", "px", b(t.position.x))}
559
+ ${d("Y", "py", b(t.position.y))}
560
+ ${d("Z", "pz", b(t.position.z))}
561
+ ${d("旋转X", "rx", b(t.rotation.x))}
562
+ ${d("旋转Y", "ry", b(t.rotation.y))}
563
+ ${d("旋转Z", "rz", b(t.rotation.z))}
564
+ ${d("缩放X", "sx", b(t.scale.x))}
565
+ ${d("缩放Y", "sy", b(t.scale.y))}
566
+ ${d("缩放Z", "sz", b(t.scale.z))}
567
+ ${d("颜色", "color", e.color, "color")}
568
+ ${d("图层", "layer", `${e.layer}`, "number")}
569
+ ${d("分组", "group", e.group, "text")}
543
570
  <div class="property-field">
544
571
  <label>显示</label>
545
572
  <input id="prop-visible" type="checkbox" ${e.visible ? "checked" : ""} />
@@ -564,8 +591,8 @@ class G {
564
591
  this.log("对象已锁定,不能修改");
565
592
  return;
566
593
  }
567
- const t = (n) => this.ui.propertyPanel.querySelector(`#prop-${n}`)?.value ?? "", s = (n) => this.ui.propertyPanel.querySelector(`#prop-${n}`)?.checked ?? !1;
568
- e.entity.name = t("name") || e.entity.name, e.entity.object.name = e.entity.name, e.entity.position.set(p(t("px")), p(t("py")), p(t("pz"))), e.entity.rotation.set(p(t("rx")), p(t("ry")), p(t("rz"))), e.entity.scale.set(p(t("sx"), 1), p(t("sy"), 1), p(t("sz"), 1)), e.color = t("color") || e.color, e.layer = Math.max(0, Math.floor(p(t("layer")))), e.group = t("group"), e.visible = s("visible"), e.locked = s("locked"), e.entity.enabled = e.visible, e.entity.object.visible = e.visible, e.entity.getComponent($)?.setColor(e.color), this.commitHistory("修改对象属性"), this.refreshUi();
594
+ const t = (i) => this.ui.propertyPanel.querySelector(`#prop-${i}`)?.value ?? "", s = (i) => this.ui.propertyPanel.querySelector(`#prop-${i}`)?.checked ?? !1;
595
+ e.entity.name = t("name") || e.entity.name, e.entity.object.name = e.entity.name, e.entity.position.set(p(t("px")), p(t("py")), p(t("pz"))), e.entity.rotation.set(p(t("rx")), p(t("ry")), p(t("rz"))), e.entity.scale.set(p(t("sx"), 1), p(t("sy"), 1), p(t("sz"), 1)), e.color = t("color") || e.color, e.layer = Math.max(0, Math.floor(p(t("layer")))), e.group = t("group"), e.visible = s("visible"), e.locked = s("locked"), e.entity.enabled = e.visible, e.entity.object.visible = e.visible, e.entity.getComponent(C)?.setColor(e.color), this.invalidateLogicalCounts(), this.commitHistory("修改对象属性"), this.refreshUi();
569
596
  }
570
597
  focusObject(e) {
571
598
  const t = this.scene.camera, s = e.entity.position;
@@ -579,8 +606,8 @@ class G {
579
606
  return;
580
607
  const s = e.getBoundingClientRect();
581
608
  this.pointer.x = (t.clientX - s.left) / s.width * 2 - 1, this.pointer.y = -((t.clientY - s.top) / s.height * 2 - 1), this.raycaster.setFromCamera(this.pointer, this.scene.camera);
582
- const i = this.raycaster.intersectObjects(this.scene.threeScene.children, !0).find((c) => !!c.object.userData.workbenchId)?.object.userData.workbenchId;
583
- i && this.objects.has(i) && (this.selectOnly(i), this.refreshUi());
609
+ const o = this.raycaster.intersectObjects(this.scene.threeScene.children, !0).find((a) => !!a.object.userData.workbenchId)?.object.userData.workbenchId;
610
+ o && this.objects.has(o) && (this.selectOnly(o), this.refreshUi());
584
611
  });
585
612
  }, 0);
586
613
  }
@@ -589,20 +616,27 @@ class G {
589
616
  return e ? e.frameTimeMs > 33 ? "帧耗时过高" : e.updatableEntities > 1e3 ? "逐帧对象过多" : e.drawCalls > 900 ? "Draw Call 过高" : e.triangles > 15e5 ? "三角面过高" : e.qualityScale < 0.95 ? "已自动降画质" : "无" : "无";
590
617
  }
591
618
  logicalObjectCount() {
592
- let e = 0;
593
- for (const t of this.objects.values())
594
- e += t.instancedCount ?? 1;
595
- return e;
619
+ return this.refreshLogicalCountCache(), this.logicalObjectCountCache;
596
620
  }
597
621
  logicalVisibleObjectCount() {
598
- let e = 0;
599
- for (const t of this.objects.values())
600
- t.visible && (e += t.instancedCount ?? 1);
601
- return e;
622
+ return this.refreshLogicalCountCache(), this.logicalVisibleObjectCountCache;
623
+ }
624
+ invalidateLogicalCounts() {
625
+ this.logicalCountsDirty = !0;
626
+ }
627
+ refreshLogicalCountCache() {
628
+ if (!this.logicalCountsDirty)
629
+ return;
630
+ let e = 0, t = 0;
631
+ for (const s of this.objects.values()) {
632
+ const i = s.instancedCount ?? 1;
633
+ e += i, s.visible && (t += i);
634
+ }
635
+ this.logicalObjectCountCache = e, this.logicalVisibleObjectCountCache = t, this.logicalCountsDirty = !1;
602
636
  }
603
637
  downloadText(e, t, s) {
604
- const n = URL.createObjectURL(new Blob([t], { type: s })), o = document.createElement("a");
605
- o.href = n, o.download = e, document.body.append(o), o.click(), o.remove(), URL.revokeObjectURL(n);
638
+ const i = URL.createObjectURL(new Blob([t], { type: s })), n = document.createElement("a");
639
+ n.href = i, n.download = e, document.body.append(n), n.click(), n.remove(), URL.revokeObjectURL(i);
606
640
  }
607
641
  log(e) {
608
642
  const t = document.createElement("div");
@@ -610,7 +644,7 @@ class G {
610
644
  this.ui.logList.lastElementChild?.remove();
611
645
  }
612
646
  }
613
- class N extends E {
647
+ class z extends P {
614
648
  constructor(e, t) {
615
649
  super(), this.onFrame = e, this.intervalSeconds = t;
616
650
  }
@@ -621,10 +655,10 @@ class N extends E {
621
655
  this.elapsed += e, !(this.elapsed < this.intervalSeconds) && (this.elapsed = 0, this.onFrame());
622
656
  }
623
657
  }
624
- function q() {
658
+ function W() {
625
659
  const r = new m("Editor Camera");
626
660
  return r.addComponent(
627
- new P({
661
+ new U({
628
662
  target: new l.Vector3(0, 0.7, 0),
629
663
  distance: 10,
630
664
  azimuth: Math.PI * 0.24,
@@ -632,18 +666,18 @@ function q() {
632
666
  })
633
667
  ), r;
634
668
  }
635
- function z() {
669
+ function q() {
636
670
  const r = new m("Ambient Light");
637
- return r.addComponent(new R({ kind: "ambient", color: "#d7f8ee", intensity: 0.78 })), r;
671
+ return r.addComponent(new x({ kind: "ambient", color: "#d7f8ee", intensity: 0.78 })), r;
638
672
  }
639
- function W() {
673
+ function K() {
640
674
  const r = new m("Directional Light");
641
- return r.position.set(4, 7, 5), r.addComponent(new R({ kind: "directional", color: "#fff4d2", intensity: 2.75 })), r;
675
+ return r.position.set(4, 7, 5), r.addComponent(new x({ kind: "directional", color: "#fff4d2", intensity: 2.75 })), r;
642
676
  }
643
- function K() {
677
+ function V() {
644
678
  const r = new m("Workbench Grid");
645
679
  return r.position.set(0, -0.05, 0), r.rotation.x = -Math.PI / 2, r.addComponent(
646
- new $({
680
+ new C({
647
681
  kind: "plane",
648
682
  width: 32,
649
683
  depth: 32,
@@ -652,13 +686,13 @@ function K() {
652
686
  receiveShadow: !0,
653
687
  castShadow: !1
654
688
  })
655
- ), r.addComponent(new y(X())), r;
689
+ ), r.addComponent(new y(Y())), r;
656
690
  }
657
- function V() {
691
+ function X() {
658
692
  const r = new m("World Axis");
659
693
  return r.addComponent(new y(new l.AxesHelper(3))), r;
660
694
  }
661
- function X() {
695
+ function Y() {
662
696
  const r = new l.GridHelper(32, 32, "#1ec7a6", "#31403a"), e = r.material;
663
697
  return Array.isArray(e) || (e.transparent = !0, e.opacity = 0.42), r.position.y = 0.02, r;
664
698
  }
@@ -666,8 +700,8 @@ function J(r) {
666
700
  const e = r.split(".").pop()?.toLowerCase() ?? "";
667
701
  return ["glb", "gltf"].includes(e) ? "model" : ["png", "jpg", "jpeg", "webp", "ktx2"].includes(e) ? "texture" : ["mp3", "wav", "ogg", "m4a"].includes(e) ? "audio" : ["mat", "json"].includes(e) ? "material" : "unknown";
668
702
  }
669
- function h(r, e, t, s = "number", n = "") {
670
- return `<div class="property-field ${n}">
703
+ function d(r, e, t, s = "number", i = "") {
704
+ return `<div class="property-field ${i}">
671
705
  <label for="prop-${e}">${r}</label>
672
706
  <input id="prop-${e}" type="${s}" value="${w(String(t))}" />
673
707
  </div>`;
@@ -679,10 +713,10 @@ function p(r, e = 0) {
679
713
  const t = Number(r);
680
714
  return Number.isFinite(t) ? t : e;
681
715
  }
682
- function C(r) {
683
- return r >= B ? Math.min(r, _) : Math.min(r, F);
716
+ function k(r) {
717
+ return r >= N ? Math.min(r, F) : Math.min(r, _);
684
718
  }
685
- function Y(r) {
719
+ function Z(r) {
686
720
  return r >= 1e8 && r % 1e8 === 0 ? `${r / 1e8}亿` : `${r}`;
687
721
  }
688
722
  function w(r) {
@@ -701,13 +735,13 @@ function w(r) {
701
735
  }
702
736
  });
703
737
  }
704
- function x(r) {
738
+ function R(r) {
705
739
  return r < 1024 ? `${r}B` : r < 1024 * 1024 ? `${Math.round(r / 1024)}KB` : `${Math.round(r / (1024 * 1024) * 10) / 10}MB`;
706
740
  }
707
- function Z() {
741
+ function Q() {
708
742
  const e = performance.memory?.usedJSHeapSize;
709
- return typeof e == "number" ? x(e) : "未知";
743
+ return typeof e == "number" ? R(e) : "未知";
710
744
  }
711
745
  export {
712
- te as createEngineWorkbench
746
+ se as createEngineWorkbench
713
747
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "diamon-engine",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Diamon 3D engine runtime and editor workbench.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",