spoint 0.1.0 → 0.1.11

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 (204) hide show
  1. package/README.md +134 -209
  2. package/SKILL.md +95 -0
  3. package/apps/environment/index.js +200 -1
  4. package/apps/environment/models/decorative/.gitkeep +0 -0
  5. package/apps/environment/models/hazards/.gitkeep +0 -0
  6. package/apps/environment/models/interactive/.gitkeep +0 -0
  7. package/apps/environment/models/structures/.gitkeep +0 -0
  8. package/apps/environment/smartObjects.js +114 -0
  9. package/apps/interactable/index.js +155 -0
  10. package/apps/physics-crate/index.js +15 -9
  11. package/apps/power-crate/index.js +18 -12
  12. package/apps/tps-game/$GDUPI.vrm +0 -0
  13. package/apps/tps-game/Cleetus.vrm +0 -0
  14. package/apps/tps-game/index.js +185 -27
  15. package/apps/world/index.js +68 -22
  16. package/bin/create-app.js +337 -0
  17. package/client/ARControls.js +301 -0
  18. package/client/LoadingManager.js +117 -0
  19. package/client/MobileControls.js +1122 -0
  20. package/client/anim-lib.glb +0 -0
  21. package/client/animation.js +306 -0
  22. package/client/app.js +1341 -65
  23. package/client/camera.js +191 -33
  24. package/client/createLoadingScreen.js +69 -0
  25. package/client/editor/bridge.js +113 -0
  26. package/client/editor/css/main.css +794 -0
  27. package/client/editor/images/rotate.svg +4 -0
  28. package/client/editor/images/scale.svg +4 -0
  29. package/client/editor/images/translate.svg +4 -0
  30. package/client/editor/index.html +103 -0
  31. package/client/editor/js/Command.js +41 -0
  32. package/client/editor/js/Config.js +81 -0
  33. package/client/editor/js/Editor.js +785 -0
  34. package/client/editor/js/EditorControls.js +438 -0
  35. package/client/editor/js/History.js +321 -0
  36. package/client/editor/js/Loader.js +987 -0
  37. package/client/editor/js/LoaderUtils.js +90 -0
  38. package/client/editor/js/Menubar.Add.js +510 -0
  39. package/client/editor/js/Menubar.Edit.js +145 -0
  40. package/client/editor/js/Menubar.File.js +466 -0
  41. package/client/editor/js/Menubar.Help.js +73 -0
  42. package/client/editor/js/Menubar.Status.js +51 -0
  43. package/client/editor/js/Menubar.View.js +183 -0
  44. package/client/editor/js/Menubar.js +27 -0
  45. package/client/editor/js/Player.js +53 -0
  46. package/client/editor/js/Resizer.js +58 -0
  47. package/client/editor/js/Script.js +503 -0
  48. package/client/editor/js/Selector.js +102 -0
  49. package/client/editor/js/Sidebar.Geometry.BoxGeometry.js +121 -0
  50. package/client/editor/js/Sidebar.Geometry.BufferGeometry.js +115 -0
  51. package/client/editor/js/Sidebar.Geometry.CapsuleGeometry.js +97 -0
  52. package/client/editor/js/Sidebar.Geometry.CircleGeometry.js +97 -0
  53. package/client/editor/js/Sidebar.Geometry.CylinderGeometry.js +121 -0
  54. package/client/editor/js/Sidebar.Geometry.DodecahedronGeometry.js +73 -0
  55. package/client/editor/js/Sidebar.Geometry.ExtrudeGeometry.js +196 -0
  56. package/client/editor/js/Sidebar.Geometry.IcosahedronGeometry.js +73 -0
  57. package/client/editor/js/Sidebar.Geometry.LatheGeometry.js +98 -0
  58. package/client/editor/js/Sidebar.Geometry.Modifiers.js +73 -0
  59. package/client/editor/js/Sidebar.Geometry.OctahedronGeometry.js +74 -0
  60. package/client/editor/js/Sidebar.Geometry.PlaneGeometry.js +97 -0
  61. package/client/editor/js/Sidebar.Geometry.RingGeometry.js +121 -0
  62. package/client/editor/js/Sidebar.Geometry.ShapeGeometry.js +76 -0
  63. package/client/editor/js/Sidebar.Geometry.SphereGeometry.js +133 -0
  64. package/client/editor/js/Sidebar.Geometry.TetrahedronGeometry.js +74 -0
  65. package/client/editor/js/Sidebar.Geometry.TorusGeometry.js +109 -0
  66. package/client/editor/js/Sidebar.Geometry.TorusKnotGeometry.js +121 -0
  67. package/client/editor/js/Sidebar.Geometry.TubeGeometry.js +135 -0
  68. package/client/editor/js/Sidebar.Geometry.js +332 -0
  69. package/client/editor/js/Sidebar.Material.BooleanProperty.js +60 -0
  70. package/client/editor/js/Sidebar.Material.ColorProperty.js +87 -0
  71. package/client/editor/js/Sidebar.Material.ConstantProperty.js +62 -0
  72. package/client/editor/js/Sidebar.Material.MapProperty.js +249 -0
  73. package/client/editor/js/Sidebar.Material.NumberProperty.js +60 -0
  74. package/client/editor/js/Sidebar.Material.Program.js +73 -0
  75. package/client/editor/js/Sidebar.Material.RangeValueProperty.js +63 -0
  76. package/client/editor/js/Sidebar.Material.js +751 -0
  77. package/client/editor/js/Sidebar.Object.Animation.js +102 -0
  78. package/client/editor/js/Sidebar.Object.js +898 -0
  79. package/client/editor/js/Sidebar.Project.App.js +165 -0
  80. package/client/editor/js/Sidebar.Project.Image.js +225 -0
  81. package/client/editor/js/Sidebar.Project.Materials.js +82 -0
  82. package/client/editor/js/Sidebar.Project.Renderer.js +144 -0
  83. package/client/editor/js/Sidebar.Project.Video.js +242 -0
  84. package/client/editor/js/Sidebar.Project.js +31 -0
  85. package/client/editor/js/Sidebar.Properties.js +73 -0
  86. package/client/editor/js/Sidebar.Scene.js +585 -0
  87. package/client/editor/js/Sidebar.Script.js +129 -0
  88. package/client/editor/js/Sidebar.Settings.History.js +146 -0
  89. package/client/editor/js/Sidebar.Settings.Shortcuts.js +175 -0
  90. package/client/editor/js/Sidebar.Settings.js +60 -0
  91. package/client/editor/js/Sidebar.js +41 -0
  92. package/client/editor/js/Storage.js +98 -0
  93. package/client/editor/js/Strings.js +2028 -0
  94. package/client/editor/js/Toolbar.js +84 -0
  95. package/client/editor/js/Viewport.Controls.js +92 -0
  96. package/client/editor/js/Viewport.Info.js +136 -0
  97. package/client/editor/js/Viewport.Pathtracer.js +91 -0
  98. package/client/editor/js/Viewport.ViewHelper.js +39 -0
  99. package/client/editor/js/Viewport.XR.js +222 -0
  100. package/client/editor/js/Viewport.js +900 -0
  101. package/client/editor/js/commands/AddObjectCommand.js +68 -0
  102. package/client/editor/js/commands/AddScriptCommand.js +75 -0
  103. package/client/editor/js/commands/Commands.js +23 -0
  104. package/client/editor/js/commands/MoveObjectCommand.js +111 -0
  105. package/client/editor/js/commands/MultiCmdsCommand.js +85 -0
  106. package/client/editor/js/commands/RemoveObjectCommand.js +88 -0
  107. package/client/editor/js/commands/RemoveScriptCommand.js +81 -0
  108. package/client/editor/js/commands/SetColorCommand.js +73 -0
  109. package/client/editor/js/commands/SetGeometryCommand.js +87 -0
  110. package/client/editor/js/commands/SetGeometryValueCommand.js +70 -0
  111. package/client/editor/js/commands/SetMaterialColorCommand.js +86 -0
  112. package/client/editor/js/commands/SetMaterialCommand.js +79 -0
  113. package/client/editor/js/commands/SetMaterialMapCommand.js +143 -0
  114. package/client/editor/js/commands/SetMaterialRangeCommand.js +91 -0
  115. package/client/editor/js/commands/SetMaterialValueCommand.js +90 -0
  116. package/client/editor/js/commands/SetMaterialVectorCommand.js +79 -0
  117. package/client/editor/js/commands/SetPositionCommand.js +84 -0
  118. package/client/editor/js/commands/SetRotationCommand.js +84 -0
  119. package/client/editor/js/commands/SetScaleCommand.js +84 -0
  120. package/client/editor/js/commands/SetSceneCommand.js +103 -0
  121. package/client/editor/js/commands/SetScriptValueCommand.js +80 -0
  122. package/client/editor/js/commands/SetShadowValueCommand.js +73 -0
  123. package/client/editor/js/commands/SetUuidCommand.js +70 -0
  124. package/client/editor/js/commands/SetValueCommand.js +75 -0
  125. package/client/editor/js/libs/acorn/acorn.js +3236 -0
  126. package/client/editor/js/libs/acorn/acorn_loose.js +1299 -0
  127. package/client/editor/js/libs/acorn/walk.js +344 -0
  128. package/client/editor/js/libs/app/index.html +57 -0
  129. package/client/editor/js/libs/app.js +251 -0
  130. package/client/editor/js/libs/codemirror/addon/dialog.css +32 -0
  131. package/client/editor/js/libs/codemirror/addon/dialog.js +163 -0
  132. package/client/editor/js/libs/codemirror/addon/show-hint.css +36 -0
  133. package/client/editor/js/libs/codemirror/addon/show-hint.js +529 -0
  134. package/client/editor/js/libs/codemirror/addon/tern.css +87 -0
  135. package/client/editor/js/libs/codemirror/addon/tern.js +750 -0
  136. package/client/editor/js/libs/codemirror/codemirror.css +344 -0
  137. package/client/editor/js/libs/codemirror/codemirror.js +9849 -0
  138. package/client/editor/js/libs/codemirror/mode/glsl.js +233 -0
  139. package/client/editor/js/libs/codemirror/mode/javascript.js +959 -0
  140. package/client/editor/js/libs/codemirror/theme/monokai.css +41 -0
  141. package/client/editor/js/libs/esprima.js +6401 -0
  142. package/client/editor/js/libs/jsonlint.js +453 -0
  143. package/client/editor/js/libs/signals.min.js +14 -0
  144. package/client/editor/js/libs/tern-threejs/threejs.js +5031 -0
  145. package/client/editor/js/libs/ternjs/comment.js +87 -0
  146. package/client/editor/js/libs/ternjs/def.js +588 -0
  147. package/client/editor/js/libs/ternjs/doc_comment.js +401 -0
  148. package/client/editor/js/libs/ternjs/infer.js +1635 -0
  149. package/client/editor/js/libs/ternjs/polyfill.js +80 -0
  150. package/client/editor/js/libs/ternjs/signal.js +26 -0
  151. package/client/editor/js/libs/ternjs/tern.js +993 -0
  152. package/client/editor/js/libs/ui.js +1346 -0
  153. package/client/editor/js/libs/ui.three.js +855 -0
  154. package/client/facial-animation.js +455 -0
  155. package/client/index.html +7 -4
  156. package/client/loading.css +147 -0
  157. package/client/loading.html +25 -0
  158. package/client/style.css +251 -0
  159. package/package.json +7 -3
  160. package/server.js +9 -1
  161. package/src/apps/AppContext.js +1 -1
  162. package/src/apps/AppLoader.js +50 -37
  163. package/src/apps/AppRuntime.js +32 -8
  164. package/src/client/InputHandler.js +233 -0
  165. package/src/client/JitterBuffer.js +207 -0
  166. package/src/client/KalmanFilter.js +125 -0
  167. package/src/client/MessageHandler.js +101 -0
  168. package/src/client/PhysicsNetworkClient.js +141 -68
  169. package/src/client/ReconnectManager.js +62 -0
  170. package/src/client/SmoothInterpolation.js +127 -0
  171. package/src/client/SnapshotProcessor.js +144 -0
  172. package/src/connection/ConnectionManager.js +21 -3
  173. package/src/connection/SessionStore.js +13 -3
  174. package/src/index.client.js +4 -6
  175. package/src/netcode/EventLog.js +29 -15
  176. package/src/netcode/LagCompensator.js +25 -26
  177. package/src/netcode/NetworkState.js +4 -1
  178. package/src/netcode/PhysicsIntegration.js +20 -6
  179. package/src/netcode/PlayerManager.js +10 -2
  180. package/src/netcode/SnapshotEncoder.js +66 -19
  181. package/src/netcode/TickSystem.js +13 -4
  182. package/src/physics/World.js +66 -13
  183. package/src/protocol/msgpack.js +90 -63
  184. package/src/sdk/ReloadHandlers.js +12 -2
  185. package/src/sdk/ReloadManager.js +5 -0
  186. package/src/sdk/ServerHandlers.js +50 -11
  187. package/src/sdk/StaticHandler.js +22 -6
  188. package/src/sdk/TickHandler.js +101 -34
  189. package/src/sdk/scaffold.js +31 -0
  190. package/src/sdk/server.js +59 -33
  191. package/src/shared/movement.js +2 -1
  192. package/src/spatial/Octree.js +5 -0
  193. package/apps/interactive-door/index.js +0 -33
  194. package/apps/patrol-npc/index.js +0 -37
  195. package/src/connection/QualityMonitor.js +0 -46
  196. package/src/debug/StateInspector.js +0 -42
  197. package/src/index.js +0 -1
  198. package/src/index.server.js +0 -27
  199. package/src/protocol/Codec.js +0 -60
  200. package/src/protocol/SequenceTracker.js +0 -71
  201. package/src/sdk/ClientMessageHandler.js +0 -80
  202. package/src/sdk/client.js +0 -122
  203. package/world/kaira.glb +0 -0
  204. package/world/schwust.glb +0 -0
@@ -0,0 +1,855 @@
1
+ import * as THREE from 'three';
2
+
3
+ import { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js';
4
+ import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';
5
+ import { TGALoader } from 'three/addons/loaders/TGALoader.js';
6
+ import { FullScreenQuad } from 'three/addons/postprocessing/Pass.js';
7
+
8
+ import { UISpan, UIDiv, UIRow, UIButton, UICheckbox, UIText, UINumber } from './ui.js';
9
+ import { MoveObjectCommand } from '../commands/MoveObjectCommand.js';
10
+
11
+ const cache = new Map();
12
+
13
+ class UITexture extends UISpan {
14
+
15
+ constructor( editor ) {
16
+
17
+ super();
18
+
19
+ const scope = this;
20
+
21
+ const form = document.createElement( 'form' );
22
+
23
+ const input = document.createElement( 'input' );
24
+ input.type = 'file';
25
+ input.addEventListener( 'change', function ( event ) {
26
+
27
+ loadFile( event.target.files[ 0 ] );
28
+
29
+ } );
30
+ form.appendChild( input );
31
+
32
+ const canvas = document.createElement( 'canvas' );
33
+ canvas.width = 32;
34
+ canvas.height = 16;
35
+ canvas.style.cursor = 'pointer';
36
+ canvas.style.marginRight = '5px';
37
+ canvas.style.border = '1px solid #888';
38
+ canvas.addEventListener( 'click', function () {
39
+
40
+ input.click();
41
+
42
+ } );
43
+ canvas.addEventListener( 'drop', function ( event ) {
44
+
45
+ event.preventDefault();
46
+ event.stopPropagation();
47
+ loadFile( event.dataTransfer.files[ 0 ] );
48
+
49
+ } );
50
+ this.dom.appendChild( canvas );
51
+
52
+ function loadFile( file ) {
53
+
54
+ const extension = file.name.split( '.' ).pop().toLowerCase();
55
+ const reader = new FileReader();
56
+
57
+ const hash = `${file.lastModified}_${file.size}_${file.name}`;
58
+
59
+ if ( cache.has( hash ) ) {
60
+
61
+ const texture = cache.get( hash );
62
+
63
+ scope.setValue( texture );
64
+
65
+ if ( scope.onChangeCallback ) scope.onChangeCallback( texture );
66
+
67
+ } else if ( extension === 'hdr' || extension === 'pic' ) {
68
+
69
+ reader.addEventListener( 'load', function ( event ) {
70
+
71
+ // assuming RGBE/Radiance HDR image format
72
+
73
+ const loader = new RGBELoader();
74
+ loader.load( event.target.result, function ( hdrTexture ) {
75
+
76
+ hdrTexture.sourceFile = file.name;
77
+
78
+ cache.set( hash, hdrTexture );
79
+
80
+ scope.setValue( hdrTexture );
81
+
82
+ if ( scope.onChangeCallback ) scope.onChangeCallback( hdrTexture );
83
+
84
+ } );
85
+
86
+ } );
87
+
88
+ reader.readAsDataURL( file );
89
+
90
+ } else if ( extension === 'tga' ) {
91
+
92
+ reader.addEventListener( 'load', function ( event ) {
93
+
94
+ const loader = new TGALoader();
95
+ loader.load( event.target.result, function ( texture ) {
96
+
97
+ texture.colorSpace = THREE.SRGBColorSpace;
98
+ texture.sourceFile = file.name;
99
+
100
+ cache.set( hash, texture );
101
+
102
+ scope.setValue( texture );
103
+
104
+ if ( scope.onChangeCallback ) scope.onChangeCallback( texture );
105
+
106
+
107
+ } );
108
+
109
+ }, false );
110
+
111
+ reader.readAsDataURL( file );
112
+
113
+ } else if ( extension === 'ktx2' ) {
114
+
115
+ reader.addEventListener( 'load', function ( event ) {
116
+
117
+ const arrayBuffer = event.target.result;
118
+ const blobURL = URL.createObjectURL( new Blob( [ arrayBuffer ] ) );
119
+ const ktx2Loader = new KTX2Loader();
120
+ ktx2Loader.setTranscoderPath( '../../examples/jsm/libs/basis/' );
121
+ editor.signals.rendererDetectKTX2Support.dispatch( ktx2Loader );
122
+
123
+ ktx2Loader.load( blobURL, function ( texture ) {
124
+
125
+ texture.colorSpace = THREE.SRGBColorSpace;
126
+ texture.sourceFile = file.name;
127
+ texture.needsUpdate = true;
128
+
129
+ cache.set( hash, texture );
130
+
131
+ scope.setValue( texture );
132
+
133
+ if ( scope.onChangeCallback ) scope.onChangeCallback( texture );
134
+ ktx2Loader.dispose();
135
+
136
+ } );
137
+
138
+ } );
139
+
140
+ reader.readAsArrayBuffer( file );
141
+
142
+ } else if ( file.type.match( 'image.*' ) ) {
143
+
144
+ reader.addEventListener( 'load', function ( event ) {
145
+
146
+ const image = document.createElement( 'img' );
147
+ image.addEventListener( 'load', function () {
148
+
149
+ const texture = new THREE.Texture( this );
150
+ texture.sourceFile = file.name;
151
+ texture.needsUpdate = true;
152
+
153
+ cache.set( hash, texture );
154
+
155
+ scope.setValue( texture );
156
+
157
+ if ( scope.onChangeCallback ) scope.onChangeCallback( texture );
158
+
159
+ }, false );
160
+
161
+ image.src = event.target.result;
162
+
163
+ }, false );
164
+
165
+ reader.readAsDataURL( file );
166
+
167
+ }
168
+
169
+ form.reset();
170
+
171
+ }
172
+
173
+ this.texture = null;
174
+ this.onChangeCallback = null;
175
+
176
+ }
177
+
178
+ getValue() {
179
+
180
+ return this.texture;
181
+
182
+ }
183
+
184
+ setValue( texture ) {
185
+
186
+ const canvas = this.dom.children[ 0 ];
187
+ const context = canvas.getContext( '2d' );
188
+
189
+ // Seems like context can be null if the canvas is not visible
190
+ if ( context ) {
191
+
192
+ // Always clear the context before set new texture, because new texture may has transparency
193
+ context.clearRect( 0, 0, canvas.width, canvas.height );
194
+
195
+ }
196
+
197
+ if ( texture !== null ) {
198
+
199
+ const image = texture.image;
200
+
201
+ if ( image !== undefined && image !== null && image.width > 0 ) {
202
+
203
+ canvas.title = texture.sourceFile;
204
+ const scale = canvas.width / image.width;
205
+
206
+ if ( texture.isDataTexture || texture.isCompressedTexture ) {
207
+
208
+ const canvas2 = renderToCanvas( texture );
209
+ context.drawImage( canvas2, 0, 0, image.width * scale, image.height * scale );
210
+
211
+ } else {
212
+
213
+ context.drawImage( image, 0, 0, image.width * scale, image.height * scale );
214
+
215
+ }
216
+
217
+ } else {
218
+
219
+ canvas.title = texture.sourceFile + ' (error)';
220
+
221
+ }
222
+
223
+ } else {
224
+
225
+ canvas.title = 'empty';
226
+
227
+ }
228
+
229
+ this.texture = texture;
230
+
231
+ }
232
+
233
+ setColorSpace( colorSpace ) {
234
+
235
+ const texture = this.getValue();
236
+
237
+ if ( texture !== null ) {
238
+
239
+ texture.colorSpace = colorSpace;
240
+
241
+ }
242
+
243
+ return this;
244
+
245
+ }
246
+
247
+ onChange( callback ) {
248
+
249
+ this.onChangeCallback = callback;
250
+
251
+ return this;
252
+
253
+ }
254
+
255
+ }
256
+
257
+ class UIOutliner extends UIDiv {
258
+
259
+ constructor( editor ) {
260
+
261
+ super();
262
+
263
+ this.dom.className = 'Outliner';
264
+ this.dom.tabIndex = 0; // keyup event is ignored without setting tabIndex
265
+
266
+ const scope = this;
267
+
268
+ // hack
269
+ this.scene = editor.scene;
270
+
271
+ // Prevent native scroll behavior
272
+ this.dom.addEventListener( 'keydown', function ( event ) {
273
+
274
+ switch ( event.code ) {
275
+
276
+ case 'ArrowUp':
277
+ case 'ArrowDown':
278
+ event.preventDefault();
279
+ event.stopPropagation();
280
+ break;
281
+
282
+ }
283
+
284
+ } );
285
+
286
+ // Keybindings to support arrow navigation
287
+ this.dom.addEventListener( 'keyup', function ( event ) {
288
+
289
+ switch ( event.code ) {
290
+
291
+ case 'ArrowUp':
292
+ scope.selectIndex( scope.selectedIndex - 1 );
293
+ break;
294
+ case 'ArrowDown':
295
+ scope.selectIndex( scope.selectedIndex + 1 );
296
+ break;
297
+
298
+ }
299
+
300
+ } );
301
+
302
+ this.editor = editor;
303
+
304
+ this.options = [];
305
+ this.selectedIndex = - 1;
306
+ this.selectedValue = null;
307
+
308
+ }
309
+
310
+ selectIndex( index ) {
311
+
312
+ if ( index >= 0 && index < this.options.length ) {
313
+
314
+ this.setValue( this.options[ index ].value );
315
+
316
+ const changeEvent = new Event( 'change', { bubbles: true, cancelable: true } );
317
+ this.dom.dispatchEvent( changeEvent );
318
+
319
+ }
320
+
321
+ }
322
+
323
+ setOptions( options ) {
324
+
325
+ const scope = this;
326
+
327
+ while ( scope.dom.children.length > 0 ) {
328
+
329
+ scope.dom.removeChild( scope.dom.firstChild );
330
+
331
+ }
332
+
333
+ function onClick() {
334
+
335
+ scope.setValue( this.value );
336
+
337
+ const changeEvent = new Event( 'change', { bubbles: true, cancelable: true } );
338
+ scope.dom.dispatchEvent( changeEvent );
339
+
340
+ }
341
+
342
+ // Drag
343
+
344
+ let currentDrag;
345
+
346
+ function onDrag() {
347
+
348
+ currentDrag = this;
349
+
350
+ }
351
+
352
+ function onDragStart( event ) {
353
+
354
+ event.dataTransfer.setData( 'text', 'foo' );
355
+
356
+ }
357
+
358
+ function onDragOver( event ) {
359
+
360
+ if ( this === currentDrag ) return;
361
+
362
+ const area = event.offsetY / this.clientHeight;
363
+
364
+ if ( area < 0.25 ) {
365
+
366
+ this.className = 'option dragTop';
367
+
368
+ } else if ( area > 0.75 ) {
369
+
370
+ this.className = 'option dragBottom';
371
+
372
+ } else {
373
+
374
+ this.className = 'option drag';
375
+
376
+ }
377
+
378
+ }
379
+
380
+ function onDragLeave() {
381
+
382
+ if ( this === currentDrag ) return;
383
+
384
+ this.className = 'option';
385
+
386
+ }
387
+
388
+ function onDrop( event ) {
389
+
390
+ if ( this === currentDrag || currentDrag === undefined ) return;
391
+
392
+ this.className = 'option';
393
+
394
+ const scene = scope.scene;
395
+ const object = scene.getObjectById( currentDrag.value );
396
+
397
+ const area = event.offsetY / this.clientHeight;
398
+
399
+ if ( area < 0.25 ) {
400
+
401
+ const nextObject = scene.getObjectById( this.value );
402
+ moveObject( object, nextObject.parent, nextObject );
403
+
404
+ } else if ( area > 0.75 ) {
405
+
406
+ let nextObject, parent;
407
+
408
+ if ( this.nextSibling !== null ) {
409
+
410
+ nextObject = scene.getObjectById( this.nextSibling.value );
411
+ parent = nextObject.parent;
412
+
413
+ } else {
414
+
415
+ // end of list (no next object)
416
+
417
+ nextObject = null;
418
+ parent = scene.getObjectById( this.value ).parent;
419
+
420
+ }
421
+
422
+ moveObject( object, parent, nextObject );
423
+
424
+ } else {
425
+
426
+ const parentObject = scene.getObjectById( this.value );
427
+ moveObject( object, parentObject );
428
+
429
+ }
430
+
431
+ }
432
+
433
+ function moveObject( object, newParent, nextObject ) {
434
+
435
+ if ( nextObject === null ) nextObject = undefined;
436
+
437
+ let newParentIsChild = false;
438
+
439
+ object.traverse( function ( child ) {
440
+
441
+ if ( child === newParent ) newParentIsChild = true;
442
+
443
+ } );
444
+
445
+ if ( newParentIsChild ) return;
446
+
447
+ const editor = scope.editor;
448
+ editor.execute( new MoveObjectCommand( editor, object, newParent, nextObject ) );
449
+
450
+ const changeEvent = new Event( 'change', { bubbles: true, cancelable: true } );
451
+ scope.dom.dispatchEvent( changeEvent );
452
+
453
+ }
454
+
455
+ //
456
+
457
+ scope.options = [];
458
+
459
+ for ( let i = 0; i < options.length; i ++ ) {
460
+
461
+ const div = options[ i ];
462
+ div.className = 'option';
463
+ scope.dom.appendChild( div );
464
+
465
+ scope.options.push( div );
466
+
467
+ div.addEventListener( 'click', onClick );
468
+
469
+ if ( div.draggable === true ) {
470
+
471
+ div.addEventListener( 'drag', onDrag );
472
+ div.addEventListener( 'dragstart', onDragStart ); // Firefox needs this
473
+
474
+ div.addEventListener( 'dragover', onDragOver );
475
+ div.addEventListener( 'dragleave', onDragLeave );
476
+ div.addEventListener( 'drop', onDrop );
477
+
478
+ }
479
+
480
+
481
+ }
482
+
483
+ return scope;
484
+
485
+ }
486
+
487
+ getValue() {
488
+
489
+ return this.selectedValue;
490
+
491
+ }
492
+
493
+ setValue( value ) {
494
+
495
+ for ( let i = 0; i < this.options.length; i ++ ) {
496
+
497
+ const element = this.options[ i ];
498
+
499
+ if ( element.value === value ) {
500
+
501
+ element.classList.add( 'active' );
502
+
503
+ // scroll into view
504
+
505
+ const y = element.offsetTop - this.dom.offsetTop;
506
+ const bottomY = y + element.offsetHeight;
507
+ const minScroll = bottomY - this.dom.offsetHeight;
508
+
509
+ if ( this.dom.scrollTop > y ) {
510
+
511
+ this.dom.scrollTop = y;
512
+
513
+ } else if ( this.dom.scrollTop < minScroll ) {
514
+
515
+ this.dom.scrollTop = minScroll;
516
+
517
+ }
518
+
519
+ this.selectedIndex = i;
520
+
521
+ } else {
522
+
523
+ element.classList.remove( 'active' );
524
+
525
+ }
526
+
527
+ }
528
+
529
+ this.selectedValue = value;
530
+
531
+ return this;
532
+
533
+ }
534
+
535
+ }
536
+
537
+ class UIPoints extends UISpan {
538
+
539
+ constructor() {
540
+
541
+ super();
542
+
543
+ this.dom.style.display = 'inline-block';
544
+
545
+ this.pointsList = new UIDiv();
546
+ this.add( this.pointsList );
547
+
548
+ this.pointsUI = [];
549
+ this.lastPointIdx = 0;
550
+ this.onChangeCallback = null;
551
+
552
+ this.update = () => { // bind lexical this
553
+
554
+ if ( this.onChangeCallback !== null ) {
555
+
556
+ this.onChangeCallback();
557
+
558
+ }
559
+
560
+ };
561
+
562
+ }
563
+
564
+ onChange( callback ) {
565
+
566
+ this.onChangeCallback = callback;
567
+
568
+ return this;
569
+
570
+ }
571
+
572
+ clear() {
573
+
574
+ for ( let i = this.pointsUI.length - 1; i >= 0; -- i ) {
575
+
576
+ this.deletePointRow( i, false );
577
+
578
+ }
579
+
580
+ this.lastPointIdx = 0;
581
+
582
+ }
583
+
584
+ deletePointRow( idx, needsUpdate = true ) {
585
+
586
+ if ( ! this.pointsUI[ idx ] ) return;
587
+
588
+ this.pointsList.remove( this.pointsUI[ idx ].row );
589
+
590
+ this.pointsUI.splice( idx, 1 );
591
+
592
+ if ( needsUpdate === true ) {
593
+
594
+ this.update();
595
+
596
+ }
597
+
598
+ this.lastPointIdx --;
599
+
600
+ }
601
+
602
+ }
603
+
604
+ class UIPoints2 extends UIPoints {
605
+
606
+ constructor() {
607
+
608
+ super();
609
+
610
+ const row = new UIRow();
611
+ this.add( row );
612
+
613
+ const addPointButton = new UIButton( '+' );
614
+ addPointButton.onClick( () => {
615
+
616
+ if ( this.pointsUI.length === 0 ) {
617
+
618
+ this.pointsList.add( this.createPointRow( 0, 0 ) );
619
+
620
+ } else {
621
+
622
+ const point = this.pointsUI[ this.pointsUI.length - 1 ];
623
+
624
+ this.pointsList.add( this.createPointRow( point.x.getValue(), point.y.getValue() ) );
625
+
626
+ }
627
+
628
+ this.update();
629
+
630
+ } );
631
+ row.add( addPointButton );
632
+
633
+ }
634
+
635
+ getValue() {
636
+
637
+ const points = [];
638
+
639
+ let count = 0;
640
+
641
+ for ( let i = 0; i < this.pointsUI.length; i ++ ) {
642
+
643
+ const pointUI = this.pointsUI[ i ];
644
+
645
+ if ( ! pointUI ) continue;
646
+
647
+ points.push( new THREE.Vector2( pointUI.x.getValue(), pointUI.y.getValue() ) );
648
+ ++ count;
649
+ pointUI.lbl.setValue( count );
650
+
651
+ }
652
+
653
+ return points;
654
+
655
+ }
656
+
657
+ setValue( points, needsUpdate = true ) {
658
+
659
+ this.clear();
660
+
661
+ for ( let i = 0; i < points.length; i ++ ) {
662
+
663
+ const point = points[ i ];
664
+ this.pointsList.add( this.createPointRow( point.x, point.y ) );
665
+
666
+ }
667
+
668
+ if ( needsUpdate === true ) this.update();
669
+
670
+ return this;
671
+
672
+ }
673
+
674
+ createPointRow( x, y ) {
675
+
676
+ const pointRow = new UIDiv();
677
+ const lbl = new UIText( this.lastPointIdx + 1 ).setWidth( '20px' );
678
+ const txtX = new UINumber( x ).setWidth( '30px' ).onChange( this.update );
679
+ const txtY = new UINumber( y ).setWidth( '30px' ).onChange( this.update );
680
+
681
+ const scope = this;
682
+ const btn = new UIButton( '-' ).onClick( function () {
683
+
684
+ if ( scope.isEditing ) return;
685
+
686
+ const idx = scope.pointsList.getIndexOfChild( pointRow );
687
+ scope.deletePointRow( idx );
688
+
689
+ } );
690
+
691
+ this.pointsUI.push( { row: pointRow, lbl: lbl, x: txtX, y: txtY } );
692
+ ++ this.lastPointIdx;
693
+ pointRow.add( lbl, txtX, txtY, btn );
694
+
695
+ return pointRow;
696
+
697
+ }
698
+
699
+ }
700
+
701
+ class UIPoints3 extends UIPoints {
702
+
703
+ constructor() {
704
+
705
+ super();
706
+
707
+ const row = new UIRow();
708
+ this.add( row );
709
+
710
+ const addPointButton = new UIButton( '+' );
711
+ addPointButton.onClick( () => {
712
+
713
+ if ( this.pointsUI.length === 0 ) {
714
+
715
+ this.pointsList.add( this.createPointRow( 0, 0, 0 ) );
716
+
717
+ } else {
718
+
719
+ const point = this.pointsUI[ this.pointsUI.length - 1 ];
720
+
721
+ this.pointsList.add( this.createPointRow( point.x.getValue(), point.y.getValue(), point.z.getValue() ) );
722
+
723
+ }
724
+
725
+ this.update();
726
+
727
+ } );
728
+ row.add( addPointButton );
729
+
730
+ }
731
+
732
+ getValue() {
733
+
734
+ const points = [];
735
+ let count = 0;
736
+
737
+ for ( let i = 0; i < this.pointsUI.length; i ++ ) {
738
+
739
+ const pointUI = this.pointsUI[ i ];
740
+
741
+ if ( ! pointUI ) continue;
742
+
743
+ points.push( new THREE.Vector3( pointUI.x.getValue(), pointUI.y.getValue(), pointUI.z.getValue() ) );
744
+ ++ count;
745
+ pointUI.lbl.setValue( count );
746
+
747
+ }
748
+
749
+ return points;
750
+
751
+ }
752
+
753
+ setValue( points, needsUpdate = true ) {
754
+
755
+ this.clear();
756
+
757
+ for ( let i = 0; i < points.length; i ++ ) {
758
+
759
+ const point = points[ i ];
760
+ this.pointsList.add( this.createPointRow( point.x, point.y, point.z ) );
761
+
762
+ }
763
+
764
+ if ( needsUpdate === true ) this.update();
765
+
766
+ return this;
767
+
768
+ }
769
+
770
+ createPointRow( x, y, z ) {
771
+
772
+ const pointRow = new UIDiv();
773
+ const lbl = new UIText( this.lastPointIdx + 1 ).setWidth( '20px' );
774
+ const txtX = new UINumber( x ).setWidth( '30px' ).onChange( this.update );
775
+ const txtY = new UINumber( y ).setWidth( '30px' ).onChange( this.update );
776
+ const txtZ = new UINumber( z ).setWidth( '30px' ).onChange( this.update );
777
+
778
+ const scope = this;
779
+ const btn = new UIButton( '-' ).onClick( function () {
780
+
781
+ if ( scope.isEditing ) return;
782
+
783
+ const idx = scope.pointsList.getIndexOfChild( pointRow );
784
+ scope.deletePointRow( idx );
785
+
786
+ } );
787
+
788
+ this.pointsUI.push( { row: pointRow, lbl: lbl, x: txtX, y: txtY, z: txtZ } );
789
+ ++ this.lastPointIdx;
790
+ pointRow.add( lbl, txtX, txtY, txtZ, btn );
791
+
792
+ return pointRow;
793
+
794
+ }
795
+
796
+ }
797
+
798
+ class UIBoolean extends UISpan {
799
+
800
+ constructor( boolean, text ) {
801
+
802
+ super();
803
+
804
+ this.setMarginRight( '4px' );
805
+
806
+ this.checkbox = new UICheckbox( boolean );
807
+ this.text = new UIText( text ).setMarginLeft( '3px' );
808
+
809
+ this.add( this.checkbox );
810
+ this.add( this.text );
811
+
812
+ }
813
+
814
+ getValue() {
815
+
816
+ return this.checkbox.getValue();
817
+
818
+ }
819
+
820
+ setValue( value ) {
821
+
822
+ return this.checkbox.setValue( value );
823
+
824
+ }
825
+
826
+ }
827
+
828
+ let renderer, fsQuad;
829
+
830
+ function renderToCanvas( texture ) {
831
+
832
+ if ( renderer === undefined ) {
833
+
834
+ renderer = new THREE.WebGLRenderer();
835
+
836
+ }
837
+
838
+ if ( fsQuad === undefined ) {
839
+
840
+ fsQuad = new FullScreenQuad( new THREE.MeshBasicMaterial() );
841
+
842
+ }
843
+
844
+ const image = texture.image;
845
+
846
+ renderer.setSize( image.width, image.height, false );
847
+
848
+ fsQuad.material.map = texture;
849
+ fsQuad.render( renderer );
850
+
851
+ return renderer.domElement;
852
+
853
+ }
854
+
855
+ export { UITexture, UIOutliner, UIPoints, UIPoints2, UIPoints3, UIBoolean };