@woosh/meep-engine 3.0.0 → 3.0.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.
Files changed (122) hide show
  1. package/editor/particles/rebuildParticleEmitter.js +8 -26
  2. package/editor/process/symbolic/CameraSymbolicDisplay.js +146 -146
  3. package/editor/tools/SelectionTool.js +1 -2
  4. package/editor/tools/TransformToolV2.js +2 -3
  5. package/editor/tools/v2/BlenderCameraOrientationGizmo.js +501 -501
  6. package/editor/tools/v2/TransformControls.js +1 -1
  7. package/package.json +95 -96
  8. package/src/core/geom/3d/mat4/m4_look_at.d.ts +25 -0
  9. package/src/core/geom/3d/mat4/m4_look_at.d.ts.map +1 -0
  10. package/src/core/geom/3d/mat4/m4_look_at.js +96 -0
  11. package/src/core/geom/3d/mat4/m4_make_rotation_x.d.ts +18 -0
  12. package/src/core/geom/3d/mat4/m4_make_rotation_x.d.ts.map +1 -0
  13. package/src/core/geom/3d/mat4/m4_make_rotation_x.js +47 -0
  14. package/src/core/geom/3d/mat4/m4_make_rotation_y.d.ts +18 -0
  15. package/src/core/geom/3d/mat4/m4_make_rotation_y.d.ts.map +1 -0
  16. package/src/core/geom/3d/mat4/m4_make_rotation_y.js +47 -0
  17. package/src/core/geom/3d/mat4/m4_make_rotation_z.d.ts +18 -0
  18. package/src/core/geom/3d/mat4/m4_make_rotation_z.d.ts.map +1 -0
  19. package/src/core/geom/3d/mat4/m4_make_rotation_z.js +47 -0
  20. package/src/core/geom/3d/mat4/m4_perspective.d.ts +25 -0
  21. package/src/core/geom/3d/mat4/m4_perspective.d.ts.map +1 -0
  22. package/src/core/geom/3d/mat4/m4_perspective.js +66 -0
  23. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts.map +1 -1
  24. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +2045 -2052
  25. package/src/engine/ecs/gui/hud/testHudEdgeStick.js +2 -2
  26. package/src/engine/ecs/terrain/ecs/TerrainSystem.d.ts.map +1 -1
  27. package/src/engine/ecs/terrain/ecs/TerrainSystem.js +14 -27
  28. package/src/engine/ecs/terrain/util/loadVisibleTerrainTiles.d.ts.map +1 -1
  29. package/src/engine/ecs/terrain/util/loadVisibleTerrainTiles.js +129 -126
  30. package/src/engine/graphics/ecs/camera/Camera.d.ts +36 -48
  31. package/src/engine/graphics/ecs/camera/Camera.d.ts.map +1 -1
  32. package/src/engine/graphics/ecs/camera/Camera.js +165 -303
  33. package/src/engine/graphics/ecs/camera/camera_active_frustum.d.ts +14 -0
  34. package/src/engine/graphics/ecs/camera/camera_active_frustum.d.ts.map +1 -0
  35. package/src/engine/graphics/ecs/camera/camera_active_frustum.js +25 -0
  36. package/src/engine/graphics/ecs/camera/camera_find_active.d.ts +16 -0
  37. package/src/engine/graphics/ecs/camera/camera_find_active.d.ts.map +1 -0
  38. package/src/engine/graphics/ecs/camera/camera_find_active.js +28 -0
  39. package/src/engine/graphics/ecs/camera/camera_traverse_active.d.ts +12 -0
  40. package/src/engine/graphics/ecs/camera/camera_traverse_active.d.ts.map +1 -0
  41. package/src/engine/graphics/ecs/camera/camera_traverse_active.js +18 -0
  42. package/src/engine/graphics/ecs/camera/pp/PerfectPanner.js +170 -170
  43. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts +5 -1
  44. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts.map +1 -1
  45. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.js +296 -281
  46. package/src/engine/graphics/ecs/render_layers_compute_depth_range.d.ts +1 -1
  47. package/src/engine/graphics/ecs/render_layers_compute_depth_range.js +1 -1
  48. package/src/engine/graphics/geometry/AttributeData.d.ts +52 -0
  49. package/src/engine/graphics/geometry/AttributeData.d.ts.map +1 -0
  50. package/src/engine/graphics/geometry/AttributeData.js +84 -0
  51. package/src/engine/graphics/particles/particular/engine/ParticularEngine.d.ts +1 -14
  52. package/src/engine/graphics/particles/particular/engine/ParticularEngine.d.ts.map +1 -1
  53. package/src/engine/graphics/particles/particular/engine/ParticularEngine.js +229 -253
  54. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts +25 -12
  55. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts.map +1 -1
  56. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js +1149 -1194
  57. package/src/engine/graphics/particles/particular/engine/emitter/ParticlePool.d.ts +4 -8
  58. package/src/engine/graphics/particles/particular/engine/emitter/ParticlePool.d.ts.map +1 -1
  59. package/src/engine/graphics/particles/particular/engine/emitter/ParticlePool.js +472 -540
  60. package/src/engine/graphics/particles/particular/engine/shader/ShaderManager.d.ts +19 -90
  61. package/src/engine/graphics/particles/particular/engine/shader/ShaderManager.d.ts.map +1 -1
  62. package/src/engine/graphics/particles/particular/engine/shader/ShaderManager.js +135 -514
  63. package/src/engine/graphics3/CameraSystem3.d.ts.map +1 -1
  64. package/src/engine/graphics3/CameraSystem3.js +10 -1
  65. package/src/engine/graphics3/GraphicsEngine3.d.ts +3 -3
  66. package/src/engine/graphics3/GraphicsEngine3.js +3 -3
  67. package/src/engine/graphics3/ParticleEmitterSystem3.d.ts +11 -0
  68. package/src/engine/graphics3/ParticleEmitterSystem3.d.ts.map +1 -1
  69. package/src/engine/graphics3/ParticleEmitterSystem3.js +289 -265
  70. package/src/engine/graphics3/ShadeCameraAdapter.d.ts +3 -3
  71. package/src/engine/graphics3/ShadeCameraAdapter.js +3 -3
  72. package/src/engine/graphics3/camera_sync_from_transform.d.ts +2 -2
  73. package/src/engine/graphics3/camera_sync_from_transform.js +2 -2
  74. package/src/engine/graphics3/shade_camera_projection_ray.js +2 -2
  75. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  76. package/src/shade/renderer/camera/Camera.d.ts +3 -5
  77. package/src/shade/renderer/camera/Camera.d.ts.map +1 -1
  78. package/src/shade/renderer/camera/Camera.js +281 -280
  79. package/src/shade/renderer/camera/GPUCameraContext.js +233 -233
  80. package/src/shade/renderer/loader/usd/parse_usda.js +1 -1
  81. package/src/shade/renderer/loader/usd/usd_build_scene.d.ts.map +1 -1
  82. package/src/shade/renderer/loader/usd/usd_build_scene.js +658 -652
  83. package/src/shade/renderer/loader/usd/usd_compose_transform.d.ts.map +1 -1
  84. package/src/shade/renderer/loader/usd/usd_compose_transform.js +58 -23
  85. package/src/shade/renderer/particles/prototypeParticleSystem.js +450 -443
  86. package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.d.ts.map +1 -1
  87. package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.js +7 -3
  88. package/src/view/minimap/dom/MinimapCameraView.d.ts +2 -2
  89. package/src/view/minimap/dom/MinimapCameraView.js +206 -206
  90. package/src/engine/graphics/ecs/camera/CameraSystem.d.ts +0 -74
  91. package/src/engine/graphics/ecs/camera/CameraSystem.d.ts.map +0 -1
  92. package/src/engine/graphics/ecs/camera/CameraSystem.js +0 -331
  93. package/src/engine/graphics/ecs/camera/auto_set_camera_clipping_planes.d.ts +0 -10
  94. package/src/engine/graphics/ecs/camera/auto_set_camera_clipping_planes.d.ts.map +0 -1
  95. package/src/engine/graphics/ecs/camera/auto_set_camera_clipping_planes.js +0 -105
  96. package/src/engine/graphics/ecs/camera/build_three_camera_object.d.ts +0 -7
  97. package/src/engine/graphics/ecs/camera/build_three_camera_object.d.ts.map +0 -1
  98. package/src/engine/graphics/ecs/camera/build_three_camera_object.js +0 -29
  99. package/src/engine/graphics/ecs/camera/frustum_from_camera.d.ts +0 -8
  100. package/src/engine/graphics/ecs/camera/frustum_from_camera.d.ts.map +0 -1
  101. package/src/engine/graphics/ecs/camera/frustum_from_camera.js +0 -20
  102. package/src/engine/graphics/ecs/camera/set_camera_aspect_ratio.d.ts +0 -9
  103. package/src/engine/graphics/ecs/camera/set_camera_aspect_ratio.d.ts.map +0 -1
  104. package/src/engine/graphics/ecs/camera/set_camera_aspect_ratio.js +0 -46
  105. package/src/engine/graphics/ecs/camera/unprojectPoint.d.ts +0 -9
  106. package/src/engine/graphics/ecs/camera/unprojectPoint.d.ts.map +0 -1
  107. package/src/engine/graphics/ecs/camera/unprojectPoint.js +0 -14
  108. package/src/engine/graphics/ecs/camera/update_camera_transform.d.ts +0 -6
  109. package/src/engine/graphics/ecs/camera/update_camera_transform.d.ts.map +0 -1
  110. package/src/engine/graphics/ecs/camera/update_camera_transform.js +0 -17
  111. package/src/engine/graphics/particles/ecs/ParticleEmitterSystem.d.ts +0 -67
  112. package/src/engine/graphics/particles/ecs/ParticleEmitterSystem.d.ts.map +0 -1
  113. package/src/engine/graphics/particles/ecs/ParticleEmitterSystem.js +0 -291
  114. package/src/engine/graphics/particles/particular/engine/renderers/billboard/ParticleBillboardMaterial.d.ts +0 -11
  115. package/src/engine/graphics/particles/particular/engine/renderers/billboard/ParticleBillboardMaterial.d.ts.map +0 -1
  116. package/src/engine/graphics/particles/particular/engine/renderers/billboard/ParticleBillboardMaterial.js +0 -497
  117. package/src/engine/graphics/particles/particular/engine/shader/MaterialRecord.d.ts +0 -40
  118. package/src/engine/graphics/particles/particular/engine/shader/MaterialRecord.d.ts.map +0 -1
  119. package/src/engine/graphics/particles/particular/engine/shader/MaterialRecord.js +0 -47
  120. package/src/engine/graphics/texture/sampler/writeSampler2DDataToDataTexture.d.ts +0 -7
  121. package/src/engine/graphics/texture/sampler/writeSampler2DDataToDataTexture.d.ts.map +0 -1
  122. package/src/engine/graphics/texture/sampler/writeSampler2DDataToDataTexture.js +0 -40
@@ -1,501 +1,501 @@
1
- import { mat4 } from "gl-matrix";
2
- import { Color } from "../../../src/core/color/Color.js";
3
- import Signal from "../../../src/core/events/signal/Signal.js";
4
- import { m4_compose } from "../../../src/core/geom/3d/mat4/m4_compose.js";
5
- import Quaternion from "../../../src/core/geom/Quaternion.js";
6
- import { v2_distance } from "../../../src/core/geom/vec2/v2_distance.js";
7
- import Vector2 from "../../../src/core/geom/Vector2.js";
8
- import Vector3 from "../../../src/core/geom/Vector3.js";
9
- import { clamp01 } from "../../../src/core/math/clamp01.js";
10
- import { inverseLerp } from "../../../src/core/math/inverseLerp.js";
11
- import { lerp } from "../../../src/core/math/lerp.js";
12
- import {
13
- quaternion_invert_orientation
14
- } from "../../../src/engine/graphics/ecs/camera/quaternion_invert_orientation.js";
15
- import { readPositionFromMouseEvent } from "../../../src/engine/input/devices/PointerDevice.js";
16
- import { CanvasView } from "../../../src/view/elements/CanvasView.js";
17
-
18
- const scratch_color = new Color();
19
- const scratch_quat = new Quaternion();
20
- const scratch_m4 = new Float32Array(16);
21
-
22
- class DirectionStyle {
23
- near = {
24
- fill: new Color(1, 0, 0),
25
- stroke_width: 0,
26
- stroke_color: new Color(0, 0, 0)
27
- };
28
- far = {
29
- fill: new Color(1, 0, 0),
30
- stroke_width: 0,
31
- stroke_color: new Color(0, 0, 0)
32
- };
33
-
34
- fromJSON({
35
- near_fill = '#FF0000',
36
- near_stroke_width = 0,
37
- near_stroke_color = '#000000',
38
- far_fill = '#FF0000',
39
- far_stroke_width = 0,
40
- far_stroke_color = '#000000'
41
- }) {
42
-
43
- this.near.fill.parse(near_fill);
44
- this.near.stroke_width = near_stroke_width;
45
- this.near.stroke_color.parse(near_stroke_color);
46
-
47
- this.far.fill.parse(far_fill);
48
- this.far.stroke_width = far_stroke_width;
49
- this.far.stroke_color.parse(far_stroke_color);
50
- }
51
-
52
- static fromJSON(j) {
53
- const r = new DirectionStyle();
54
-
55
- r.fromJSON(j);
56
-
57
- return r;
58
- }
59
- }
60
-
61
- function apply_hierarchical_options_from_json(source, target) {
62
- for (const prop_name in source) {
63
- if (!target.hasOwnProperty(prop_name)) {
64
- console.warn(`Property '${prop_name}' doesn't exist, valid properties are : ${Object.keys(target)}`);
65
- continue;
66
- }
67
-
68
- const existing_target_value = target[prop_name];
69
- const source_value = source[prop_name];
70
-
71
- if (typeof existing_target_value === "object") {
72
- if (typeof existing_target_value.fromJSON === "function") {
73
- existing_target_value.fromJSON(source_value);
74
- } else {
75
- apply_hierarchical_options_from_json(source_value, existing_target_value);
76
- }
77
- } else {
78
- target[prop_name] = source_value;
79
- }
80
-
81
-
82
- }
83
- }
84
-
85
-
86
- /**
87
- * Modelled on https://github.com/jrj2211/three-orientation-gizmo/blob/master/src/OrientationGizmo.js
88
- */
89
- export class BlenderCameraOrientationGizmo extends CanvasView {
90
- /**
91
- *
92
- * @type {Quaternion}
93
- */
94
- orientation = null;
95
-
96
- /**
97
- *
98
- * @type {Vector3|null}
99
- */
100
- input_pointer_position = null;
101
-
102
- selectedAxis = null;
103
-
104
- /**
105
- *
106
- */
107
- constructor(options = {}) {
108
- super();
109
-
110
- this.options = {
111
- size: 100,
112
- padding: 8,
113
- bubbleSizePrimary: 10,
114
- bubbleSizeSecondary: 8,
115
- showSecondary: true,
116
- lineWidth: 2,
117
- fontSize: "11px",
118
- fontFamily: "arial",
119
- fontWeight: "bold",
120
- fontColor: "rgba(0,0,0,0.8)",
121
- fontYAdjust: 1,
122
- selectionFontColor: "#FFFFFF",
123
- invertOrientation: true,
124
- axisStyles: {
125
- px: DirectionStyle.fromJSON({
126
- near_fill: "#FF3653",
127
- far_fill: "#9D3B4A"
128
- }),
129
- py: DirectionStyle.fromJSON({
130
- near_fill: "#8ADB00",
131
- far_fill: "#648C23"
132
- }),
133
- pz: DirectionStyle.fromJSON({
134
- near_fill: "#2C8FFF",
135
- far_fill: "#36679D"
136
- }),
137
- nx: DirectionStyle.fromJSON({
138
- near_stroke_color: "#FF3653",
139
- near_stroke_width: 1,
140
- near_fill: "#6E3D44",
141
- far_stroke_color: "#9D3B4A",
142
- far_stroke_width: 1,
143
- far_fill: 'rgba(0,0,0,0)'
144
- }),
145
- ny: DirectionStyle.fromJSON({
146
- near_stroke_color: "#8ADB00",
147
- near_stroke_width: 1,
148
- near_fill: "#526532",
149
- far_stroke_color: "#648C23",
150
- far_stroke_width: 1,
151
- far_fill: 'rgba(0,0,0,0)'
152
- }),
153
- nz: DirectionStyle.fromJSON({
154
- near_stroke_color: "#2C8FFF",
155
- near_stroke_width: 1,
156
- near_fill: "#3B536E",
157
- far_stroke_color: "#36679D",
158
- far_stroke_width: 1,
159
- far_fill: 'rgba(0,0,0,0)'
160
- })
161
- }
162
- };
163
-
164
- // read options
165
- apply_hierarchical_options_from_json(options, this.options);
166
-
167
- // Generate list of axes
168
- this.bubbles = [
169
- {
170
- axis: "x",
171
- direction: new Vector3(1, 0, 0),
172
- size: this.options.bubbleSizePrimary,
173
- style: this.options.axisStyles.px,
174
- line: this.options.lineWidth,
175
- label: "X",
176
- primary: true
177
- },
178
- {
179
- axis: "y",
180
- direction: new Vector3(0, 1, 0),
181
- size: this.options.bubbleSizePrimary,
182
- style: this.options.axisStyles.py,
183
- line: this.options.lineWidth,
184
- label: "Y",
185
- primary: true
186
- },
187
- {
188
- axis: "z",
189
- direction: new Vector3(0, 0, 1),
190
- size: this.options.bubbleSizePrimary,
191
- style: this.options.axisStyles.pz,
192
- line: this.options.lineWidth,
193
- label: "Z",
194
- primary: true
195
- },
196
- {
197
- axis: "-x",
198
- direction: new Vector3(-1, 0, 0),
199
- size: this.options.bubbleSizeSecondary,
200
- style: this.options.axisStyles.nx,
201
- label: "-X",
202
- labelHideUnselected: true,
203
- primary: false
204
- },
205
- {
206
- axis: "-y",
207
- direction: new Vector3(0, -1, 0),
208
- size: this.options.bubbleSizeSecondary,
209
- style: this.options.axisStyles.ny,
210
- label: "-Y",
211
- labelHideUnselected: true,
212
- primary: false
213
- },
214
- {
215
- axis: "-z",
216
- direction: new Vector3(0, 0, -1),
217
- size: this.options.bubbleSizeSecondary,
218
- style: this.options.axisStyles.nz,
219
- label: "-Z",
220
- labelHideUnselected: true,
221
- primary: false
222
- },
223
- ];
224
-
225
- this.center = new Vector3(this.options.size / 2, this.options.size / 2, 0);
226
- this.size.setScalar(this.options.size);
227
-
228
- this.onMouseMove = this.onMouseMove.bind(this);
229
- this.onMouseOut = this.onMouseOut.bind(this);
230
- this.onMouseClick = this.onMouseClick.bind(this);
231
-
232
- /**
233
- *
234
- * Invoked when axis is clicked
235
- * @type {Signal<string,Vector3>}
236
- */
237
- this.on.axisSelected = new Signal();
238
-
239
- /**
240
- *
241
- * @type {boolean}
242
- * @private
243
- */
244
- this.__needs_update = true;
245
- }
246
-
247
- link() {
248
- super.link();
249
-
250
- const el = this.el;
251
-
252
- el.addEventListener('mousemove', this.onMouseMove);
253
- el.addEventListener('mouseout', this.onMouseOut);
254
- el.addEventListener('click', this.onMouseClick);
255
- }
256
-
257
- unlink() {
258
- const el = this.el;
259
-
260
- el.removeEventListener('mousemove', this.onMouseMove);
261
- el.removeEventListener('mouseout', this.onMouseOut);
262
- el.removeEventListener('click', this.onMouseClick);
263
-
264
- super.unlink();
265
- }
266
-
267
- /**
268
- *
269
- * @param {MouseEvent} evt
270
- */
271
- onMouseMove(evt) {
272
- this._setPointerPositionFromEvent(evt);
273
- this.__try_update();
274
- }
275
-
276
- /**
277
- *
278
- * @param {MouseEvent} evt
279
- * @private
280
- */
281
- _setPointerPositionFromEvent(evt) {
282
- const v2 = new Vector2();
283
-
284
- readPositionFromMouseEvent(v2, evt);
285
-
286
- const position_changed = (this.input_pointer_position === null || this.input_pointer_position.x !== v2.x || this.input_pointer_position.y !== v2.y);
287
-
288
- this.input_pointer_position = new Vector3(v2.x, v2.y, 0);
289
-
290
-
291
- if (position_changed) {
292
- this.__needs_update = true;
293
- }
294
-
295
- return position_changed;
296
- }
297
-
298
- /**
299
- *
300
- * @param {MouseEvent} evt
301
- */
302
- onMouseOut(evt) {
303
- this.input_pointer_position = null;
304
- this.__needs_update = true;
305
- this.__try_update();
306
- }
307
-
308
- /**
309
- *
310
- * @param {MouseEvent} evt
311
- */
312
- onMouseClick(evt) {
313
-
314
- this._setPointerPositionFromEvent(evt);
315
-
316
- this.__try_update();
317
-
318
- if (this.selectedAxis !== null) {
319
-
320
- if (this.on.axisSelected.hasHandlers()) {
321
- // axis selection will be handled, stop propagation
322
- evt.stopPropagation();
323
- }
324
-
325
- this.on.axisSelected.send2(
326
- this.selectedAxis.axis,
327
- this.selectedAxis.direction.clone()
328
- );
329
- }
330
- }
331
-
332
- drawCircle(p, radius = 10, fill_color = "#FF0000", stroke_width = 0, stroke_color = "#FFFFFF") {
333
- const ctx = this.context2d;
334
-
335
- ctx.beginPath();
336
- ctx.arc(p.x, p.y, radius, 0, 2 * Math.PI, false);
337
- ctx.fillStyle = fill_color;
338
- ctx.fill();
339
-
340
- if (stroke_width > 0) {
341
- ctx.lineWidth = stroke_width;
342
- ctx.strokeStyle = stroke_color;
343
- ctx.stroke();
344
- }
345
-
346
- ctx.closePath();
347
- }
348
-
349
- drawLine(p1, p2, width = 1, color = "#FF0000") {
350
- const ctx = this.context2d;
351
-
352
- ctx.beginPath();
353
- ctx.moveTo(p1.x, p1.y);
354
- ctx.lineTo(p2.x, p2.y);
355
- ctx.lineWidth = width;
356
- ctx.strokeStyle = color;
357
- ctx.stroke();
358
- ctx.closePath();
359
- }
360
-
361
- __try_update() {
362
- if (!this.__needs_update) {
363
- return;
364
- }
365
- this.update();
366
- }
367
-
368
- update() {
369
- // reset flag
370
- this.__needs_update = false;
371
-
372
- this.clear();
373
-
374
- // Calculate the rotation matrix from the camera
375
- const rotation_matrix = scratch_m4;
376
- let rotation = this.orientation;
377
-
378
- if (rotation === null) {
379
- // not connected
380
- return;
381
- }
382
-
383
- if (this.options.invertOrientation) {
384
- const q = scratch_quat;
385
-
386
- quaternion_invert_orientation(q, rotation);
387
-
388
- rotation = q;
389
- }
390
-
391
- m4_compose(rotation_matrix, Vector3.zero, rotation, Vector3.one);
392
- mat4.invert(rotation_matrix, rotation_matrix);
393
-
394
- for (const bubble of this.bubbles) {
395
- const direction = bubble.direction.clone();
396
- direction.applyMatrix4(rotation_matrix);
397
-
398
- bubble.position = this.getBubblePosition(direction);
399
- }
400
-
401
- // Generate a list of layers to draw
402
- const layers = [];
403
-
404
- for (const bubble of this.bubbles) {
405
- // Check if the name starts with a negative and dont add it to the layer list if secondary axis is turned off
406
- const is_secondary = bubble.axis[0] !== "-";
407
- if (this.options.showSecondary === true || is_secondary) {
408
- layers.push(bubble);
409
- }
410
- }
411
-
412
- // Sort the layers where the +Z position is last so its drawn on top of anything below it
413
- layers.sort((a, b) => (a.position.z > b.position.z) ? 1 : -1);
414
-
415
- // If the mouse is over the gizmo, find the closest axis and highlight it
416
- this.selectedAxis = null;
417
-
418
- if (this.input_pointer_position) {
419
- let closestDist = Infinity;
420
- let closestZ = -Infinity;
421
-
422
- // Loop through each layer
423
- for (let bubble of layers) {
424
- const distance = v2_distance(this.input_pointer_position.x, this.input_pointer_position.y, bubble.position.x, bubble.position.y);
425
-
426
- // Only select the axis if its closer to the mouse than the previous or if its within its bubble circle
427
- if (
428
- distance < closestDist
429
- && closestZ < bubble.position.z
430
- && distance <= bubble.size
431
- ) {
432
-
433
- closestDist = distance;
434
- closestZ = bubble.position.z;
435
- this.selectedAxis = bubble;
436
-
437
- }
438
- }
439
- }
440
-
441
- // Draw the layers
442
- this.drawLayers(layers);
443
- }
444
-
445
- /**
446
- *
447
- * @param {{style:DirectionStyle, position:Vector3, size:number,line:boolean, label?:string,labelHideUnselected?:boolean}[]} layers
448
- */
449
- drawLayers(layers) {
450
- // For each layer, draw the bubble
451
- for (let bubble of layers) {
452
-
453
- // Find the color
454
- const is_selected = this.selectedAxis === bubble;
455
-
456
- const closeness = clamp01(inverseLerp(-1, 0.8, bubble.position.z));
457
-
458
- const style = bubble.style;
459
-
460
- scratch_color.lerpColors(style.far.fill, style.near.fill, closeness);
461
- const fill_color = scratch_color.toCssRGBAString();
462
-
463
- scratch_color.lerpColors(style.far.stroke_color, style.near.stroke_color, closeness);
464
- const stroke_color = scratch_color.toCssRGBAString();
465
-
466
- const stroke_width = lerp(style.far.stroke_width, style.near.stroke_width, closeness);
467
-
468
- // Draw the circle for the bubbble
469
- this.drawCircle(bubble.position, bubble.size, fill_color, stroke_width, stroke_color);
470
-
471
- // Draw the line that connects it to the center if enabled
472
- if (bubble.line) {
473
- this.drawLine(this.center, bubble.position, bubble.line, fill_color);
474
- }
475
-
476
- // Write the axis label (X,Y,Z) if provided
477
- if (bubble.label && (is_selected || (bubble.labelHideUnselected !== true))) {
478
- const ctx = this.context2d;
479
-
480
- ctx.font = [this.options.fontWeight, this.options.fontSize, this.options.fontFamily].join(" ");
481
- ctx.fillStyle = is_selected ? this.options.selectionFontColor : this.options.fontColor;
482
- ctx.textBaseline = 'middle';
483
- ctx.textAlign = 'center';
484
- ctx.fillText(bubble.label, bubble.position.x, bubble.position.y + this.options.fontYAdjust);
485
- }
486
- }
487
- }
488
-
489
- /**
490
- *
491
- * @param {Vector3} position
492
- * @returns {Vector3}
493
- */
494
- getBubblePosition(position) {
495
- return new Vector3(
496
- (position.x * (this.center.x - (this.options.bubbleSizePrimary / 2) - this.options.padding)) + this.center.x,
497
- this.center.y - (position.y * (this.center.y - (this.options.bubbleSizePrimary / 2) - this.options.padding)),
498
- position.z
499
- );
500
- }
501
- }
1
+ import { Color } from "../../../src/core/color/Color.js";
2
+ import Signal from "../../../src/core/events/signal/Signal.js";
3
+ import { m4_compose } from "../../../src/core/geom/3d/mat4/m4_compose.js";
4
+ import { m4_invert } from "../../../src/core/geom/3d/mat4/m4_invert.js";
5
+ import Quaternion from "../../../src/core/geom/Quaternion.js";
6
+ import { v2_distance } from "../../../src/core/geom/vec2/v2_distance.js";
7
+ import Vector2 from "../../../src/core/geom/Vector2.js";
8
+ import Vector3 from "../../../src/core/geom/Vector3.js";
9
+ import { clamp01 } from "../../../src/core/math/clamp01.js";
10
+ import { inverseLerp } from "../../../src/core/math/inverseLerp.js";
11
+ import { lerp } from "../../../src/core/math/lerp.js";
12
+ import {
13
+ quaternion_invert_orientation
14
+ } from "../../../src/engine/graphics/ecs/camera/quaternion_invert_orientation.js";
15
+ import { readPositionFromMouseEvent } from "../../../src/engine/input/devices/PointerDevice.js";
16
+ import { CanvasView } from "../../../src/view/elements/CanvasView.js";
17
+
18
+ const scratch_color = new Color();
19
+ const scratch_quat = new Quaternion();
20
+ const scratch_m4 = new Float32Array(16);
21
+
22
+ class DirectionStyle {
23
+ near = {
24
+ fill: new Color(1, 0, 0),
25
+ stroke_width: 0,
26
+ stroke_color: new Color(0, 0, 0)
27
+ };
28
+ far = {
29
+ fill: new Color(1, 0, 0),
30
+ stroke_width: 0,
31
+ stroke_color: new Color(0, 0, 0)
32
+ };
33
+
34
+ fromJSON({
35
+ near_fill = '#FF0000',
36
+ near_stroke_width = 0,
37
+ near_stroke_color = '#000000',
38
+ far_fill = '#FF0000',
39
+ far_stroke_width = 0,
40
+ far_stroke_color = '#000000'
41
+ }) {
42
+
43
+ this.near.fill.parse(near_fill);
44
+ this.near.stroke_width = near_stroke_width;
45
+ this.near.stroke_color.parse(near_stroke_color);
46
+
47
+ this.far.fill.parse(far_fill);
48
+ this.far.stroke_width = far_stroke_width;
49
+ this.far.stroke_color.parse(far_stroke_color);
50
+ }
51
+
52
+ static fromJSON(j) {
53
+ const r = new DirectionStyle();
54
+
55
+ r.fromJSON(j);
56
+
57
+ return r;
58
+ }
59
+ }
60
+
61
+ function apply_hierarchical_options_from_json(source, target) {
62
+ for (const prop_name in source) {
63
+ if (!target.hasOwnProperty(prop_name)) {
64
+ console.warn(`Property '${prop_name}' doesn't exist, valid properties are : ${Object.keys(target)}`);
65
+ continue;
66
+ }
67
+
68
+ const existing_target_value = target[prop_name];
69
+ const source_value = source[prop_name];
70
+
71
+ if (typeof existing_target_value === "object") {
72
+ if (typeof existing_target_value.fromJSON === "function") {
73
+ existing_target_value.fromJSON(source_value);
74
+ } else {
75
+ apply_hierarchical_options_from_json(source_value, existing_target_value);
76
+ }
77
+ } else {
78
+ target[prop_name] = source_value;
79
+ }
80
+
81
+
82
+ }
83
+ }
84
+
85
+
86
+ /**
87
+ * Modelled on https://github.com/jrj2211/three-orientation-gizmo/blob/master/src/OrientationGizmo.js
88
+ */
89
+ export class BlenderCameraOrientationGizmo extends CanvasView {
90
+ /**
91
+ *
92
+ * @type {Quaternion}
93
+ */
94
+ orientation = null;
95
+
96
+ /**
97
+ *
98
+ * @type {Vector3|null}
99
+ */
100
+ input_pointer_position = null;
101
+
102
+ selectedAxis = null;
103
+
104
+ /**
105
+ *
106
+ */
107
+ constructor(options = {}) {
108
+ super();
109
+
110
+ this.options = {
111
+ size: 100,
112
+ padding: 8,
113
+ bubbleSizePrimary: 10,
114
+ bubbleSizeSecondary: 8,
115
+ showSecondary: true,
116
+ lineWidth: 2,
117
+ fontSize: "11px",
118
+ fontFamily: "arial",
119
+ fontWeight: "bold",
120
+ fontColor: "rgba(0,0,0,0.8)",
121
+ fontYAdjust: 1,
122
+ selectionFontColor: "#FFFFFF",
123
+ invertOrientation: true,
124
+ axisStyles: {
125
+ px: DirectionStyle.fromJSON({
126
+ near_fill: "#FF3653",
127
+ far_fill: "#9D3B4A"
128
+ }),
129
+ py: DirectionStyle.fromJSON({
130
+ near_fill: "#8ADB00",
131
+ far_fill: "#648C23"
132
+ }),
133
+ pz: DirectionStyle.fromJSON({
134
+ near_fill: "#2C8FFF",
135
+ far_fill: "#36679D"
136
+ }),
137
+ nx: DirectionStyle.fromJSON({
138
+ near_stroke_color: "#FF3653",
139
+ near_stroke_width: 1,
140
+ near_fill: "#6E3D44",
141
+ far_stroke_color: "#9D3B4A",
142
+ far_stroke_width: 1,
143
+ far_fill: 'rgba(0,0,0,0)'
144
+ }),
145
+ ny: DirectionStyle.fromJSON({
146
+ near_stroke_color: "#8ADB00",
147
+ near_stroke_width: 1,
148
+ near_fill: "#526532",
149
+ far_stroke_color: "#648C23",
150
+ far_stroke_width: 1,
151
+ far_fill: 'rgba(0,0,0,0)'
152
+ }),
153
+ nz: DirectionStyle.fromJSON({
154
+ near_stroke_color: "#2C8FFF",
155
+ near_stroke_width: 1,
156
+ near_fill: "#3B536E",
157
+ far_stroke_color: "#36679D",
158
+ far_stroke_width: 1,
159
+ far_fill: 'rgba(0,0,0,0)'
160
+ })
161
+ }
162
+ };
163
+
164
+ // read options
165
+ apply_hierarchical_options_from_json(options, this.options);
166
+
167
+ // Generate list of axes
168
+ this.bubbles = [
169
+ {
170
+ axis: "x",
171
+ direction: new Vector3(1, 0, 0),
172
+ size: this.options.bubbleSizePrimary,
173
+ style: this.options.axisStyles.px,
174
+ line: this.options.lineWidth,
175
+ label: "X",
176
+ primary: true
177
+ },
178
+ {
179
+ axis: "y",
180
+ direction: new Vector3(0, 1, 0),
181
+ size: this.options.bubbleSizePrimary,
182
+ style: this.options.axisStyles.py,
183
+ line: this.options.lineWidth,
184
+ label: "Y",
185
+ primary: true
186
+ },
187
+ {
188
+ axis: "z",
189
+ direction: new Vector3(0, 0, 1),
190
+ size: this.options.bubbleSizePrimary,
191
+ style: this.options.axisStyles.pz,
192
+ line: this.options.lineWidth,
193
+ label: "Z",
194
+ primary: true
195
+ },
196
+ {
197
+ axis: "-x",
198
+ direction: new Vector3(-1, 0, 0),
199
+ size: this.options.bubbleSizeSecondary,
200
+ style: this.options.axisStyles.nx,
201
+ label: "-X",
202
+ labelHideUnselected: true,
203
+ primary: false
204
+ },
205
+ {
206
+ axis: "-y",
207
+ direction: new Vector3(0, -1, 0),
208
+ size: this.options.bubbleSizeSecondary,
209
+ style: this.options.axisStyles.ny,
210
+ label: "-Y",
211
+ labelHideUnselected: true,
212
+ primary: false
213
+ },
214
+ {
215
+ axis: "-z",
216
+ direction: new Vector3(0, 0, -1),
217
+ size: this.options.bubbleSizeSecondary,
218
+ style: this.options.axisStyles.nz,
219
+ label: "-Z",
220
+ labelHideUnselected: true,
221
+ primary: false
222
+ },
223
+ ];
224
+
225
+ this.center = new Vector3(this.options.size / 2, this.options.size / 2, 0);
226
+ this.size.setScalar(this.options.size);
227
+
228
+ this.onMouseMove = this.onMouseMove.bind(this);
229
+ this.onMouseOut = this.onMouseOut.bind(this);
230
+ this.onMouseClick = this.onMouseClick.bind(this);
231
+
232
+ /**
233
+ *
234
+ * Invoked when axis is clicked
235
+ * @type {Signal<string,Vector3>}
236
+ */
237
+ this.on.axisSelected = new Signal();
238
+
239
+ /**
240
+ *
241
+ * @type {boolean}
242
+ * @private
243
+ */
244
+ this.__needs_update = true;
245
+ }
246
+
247
+ link() {
248
+ super.link();
249
+
250
+ const el = this.el;
251
+
252
+ el.addEventListener('mousemove', this.onMouseMove);
253
+ el.addEventListener('mouseout', this.onMouseOut);
254
+ el.addEventListener('click', this.onMouseClick);
255
+ }
256
+
257
+ unlink() {
258
+ const el = this.el;
259
+
260
+ el.removeEventListener('mousemove', this.onMouseMove);
261
+ el.removeEventListener('mouseout', this.onMouseOut);
262
+ el.removeEventListener('click', this.onMouseClick);
263
+
264
+ super.unlink();
265
+ }
266
+
267
+ /**
268
+ *
269
+ * @param {MouseEvent} evt
270
+ */
271
+ onMouseMove(evt) {
272
+ this._setPointerPositionFromEvent(evt);
273
+ this.__try_update();
274
+ }
275
+
276
+ /**
277
+ *
278
+ * @param {MouseEvent} evt
279
+ * @private
280
+ */
281
+ _setPointerPositionFromEvent(evt) {
282
+ const v2 = new Vector2();
283
+
284
+ readPositionFromMouseEvent(v2, evt);
285
+
286
+ const position_changed = (this.input_pointer_position === null || this.input_pointer_position.x !== v2.x || this.input_pointer_position.y !== v2.y);
287
+
288
+ this.input_pointer_position = new Vector3(v2.x, v2.y, 0);
289
+
290
+
291
+ if (position_changed) {
292
+ this.__needs_update = true;
293
+ }
294
+
295
+ return position_changed;
296
+ }
297
+
298
+ /**
299
+ *
300
+ * @param {MouseEvent} evt
301
+ */
302
+ onMouseOut(evt) {
303
+ this.input_pointer_position = null;
304
+ this.__needs_update = true;
305
+ this.__try_update();
306
+ }
307
+
308
+ /**
309
+ *
310
+ * @param {MouseEvent} evt
311
+ */
312
+ onMouseClick(evt) {
313
+
314
+ this._setPointerPositionFromEvent(evt);
315
+
316
+ this.__try_update();
317
+
318
+ if (this.selectedAxis !== null) {
319
+
320
+ if (this.on.axisSelected.hasHandlers()) {
321
+ // axis selection will be handled, stop propagation
322
+ evt.stopPropagation();
323
+ }
324
+
325
+ this.on.axisSelected.send2(
326
+ this.selectedAxis.axis,
327
+ this.selectedAxis.direction.clone()
328
+ );
329
+ }
330
+ }
331
+
332
+ drawCircle(p, radius = 10, fill_color = "#FF0000", stroke_width = 0, stroke_color = "#FFFFFF") {
333
+ const ctx = this.context2d;
334
+
335
+ ctx.beginPath();
336
+ ctx.arc(p.x, p.y, radius, 0, 2 * Math.PI, false);
337
+ ctx.fillStyle = fill_color;
338
+ ctx.fill();
339
+
340
+ if (stroke_width > 0) {
341
+ ctx.lineWidth = stroke_width;
342
+ ctx.strokeStyle = stroke_color;
343
+ ctx.stroke();
344
+ }
345
+
346
+ ctx.closePath();
347
+ }
348
+
349
+ drawLine(p1, p2, width = 1, color = "#FF0000") {
350
+ const ctx = this.context2d;
351
+
352
+ ctx.beginPath();
353
+ ctx.moveTo(p1.x, p1.y);
354
+ ctx.lineTo(p2.x, p2.y);
355
+ ctx.lineWidth = width;
356
+ ctx.strokeStyle = color;
357
+ ctx.stroke();
358
+ ctx.closePath();
359
+ }
360
+
361
+ __try_update() {
362
+ if (!this.__needs_update) {
363
+ return;
364
+ }
365
+ this.update();
366
+ }
367
+
368
+ update() {
369
+ // reset flag
370
+ this.__needs_update = false;
371
+
372
+ this.clear();
373
+
374
+ // Calculate the rotation matrix from the camera
375
+ const rotation_matrix = scratch_m4;
376
+ let rotation = this.orientation;
377
+
378
+ if (rotation === null) {
379
+ // not connected
380
+ return;
381
+ }
382
+
383
+ if (this.options.invertOrientation) {
384
+ const q = scratch_quat;
385
+
386
+ quaternion_invert_orientation(q, rotation);
387
+
388
+ rotation = q;
389
+ }
390
+
391
+ m4_compose(rotation_matrix, Vector3.zero, rotation, Vector3.one);
392
+ m4_invert(rotation_matrix, rotation_matrix);
393
+
394
+ for (const bubble of this.bubbles) {
395
+ const direction = bubble.direction.clone();
396
+ direction.applyMatrix4(rotation_matrix);
397
+
398
+ bubble.position = this.getBubblePosition(direction);
399
+ }
400
+
401
+ // Generate a list of layers to draw
402
+ const layers = [];
403
+
404
+ for (const bubble of this.bubbles) {
405
+ // Check if the name starts with a negative and dont add it to the layer list if secondary axis is turned off
406
+ const is_secondary = bubble.axis[0] !== "-";
407
+ if (this.options.showSecondary === true || is_secondary) {
408
+ layers.push(bubble);
409
+ }
410
+ }
411
+
412
+ // Sort the layers where the +Z position is last so its drawn on top of anything below it
413
+ layers.sort((a, b) => (a.position.z > b.position.z) ? 1 : -1);
414
+
415
+ // If the mouse is over the gizmo, find the closest axis and highlight it
416
+ this.selectedAxis = null;
417
+
418
+ if (this.input_pointer_position) {
419
+ let closestDist = Infinity;
420
+ let closestZ = -Infinity;
421
+
422
+ // Loop through each layer
423
+ for (let bubble of layers) {
424
+ const distance = v2_distance(this.input_pointer_position.x, this.input_pointer_position.y, bubble.position.x, bubble.position.y);
425
+
426
+ // Only select the axis if its closer to the mouse than the previous or if its within its bubble circle
427
+ if (
428
+ distance < closestDist
429
+ && closestZ < bubble.position.z
430
+ && distance <= bubble.size
431
+ ) {
432
+
433
+ closestDist = distance;
434
+ closestZ = bubble.position.z;
435
+ this.selectedAxis = bubble;
436
+
437
+ }
438
+ }
439
+ }
440
+
441
+ // Draw the layers
442
+ this.drawLayers(layers);
443
+ }
444
+
445
+ /**
446
+ *
447
+ * @param {{style:DirectionStyle, position:Vector3, size:number,line:boolean, label?:string,labelHideUnselected?:boolean}[]} layers
448
+ */
449
+ drawLayers(layers) {
450
+ // For each layer, draw the bubble
451
+ for (let bubble of layers) {
452
+
453
+ // Find the color
454
+ const is_selected = this.selectedAxis === bubble;
455
+
456
+ const closeness = clamp01(inverseLerp(-1, 0.8, bubble.position.z));
457
+
458
+ const style = bubble.style;
459
+
460
+ scratch_color.lerpColors(style.far.fill, style.near.fill, closeness);
461
+ const fill_color = scratch_color.toCssRGBAString();
462
+
463
+ scratch_color.lerpColors(style.far.stroke_color, style.near.stroke_color, closeness);
464
+ const stroke_color = scratch_color.toCssRGBAString();
465
+
466
+ const stroke_width = lerp(style.far.stroke_width, style.near.stroke_width, closeness);
467
+
468
+ // Draw the circle for the bubbble
469
+ this.drawCircle(bubble.position, bubble.size, fill_color, stroke_width, stroke_color);
470
+
471
+ // Draw the line that connects it to the center if enabled
472
+ if (bubble.line) {
473
+ this.drawLine(this.center, bubble.position, bubble.line, fill_color);
474
+ }
475
+
476
+ // Write the axis label (X,Y,Z) if provided
477
+ if (bubble.label && (is_selected || (bubble.labelHideUnselected !== true))) {
478
+ const ctx = this.context2d;
479
+
480
+ ctx.font = [this.options.fontWeight, this.options.fontSize, this.options.fontFamily].join(" ");
481
+ ctx.fillStyle = is_selected ? this.options.selectionFontColor : this.options.fontColor;
482
+ ctx.textBaseline = 'middle';
483
+ ctx.textAlign = 'center';
484
+ ctx.fillText(bubble.label, bubble.position.x, bubble.position.y + this.options.fontYAdjust);
485
+ }
486
+ }
487
+ }
488
+
489
+ /**
490
+ *
491
+ * @param {Vector3} position
492
+ * @returns {Vector3}
493
+ */
494
+ getBubblePosition(position) {
495
+ return new Vector3(
496
+ (position.x * (this.center.x - (this.options.bubbleSizePrimary / 2) - this.options.padding)) + this.center.x,
497
+ this.center.y - (position.y * (this.center.y - (this.options.bubbleSizePrimary / 2) - this.options.padding)),
498
+ position.z
499
+ );
500
+ }
501
+ }