zincjs 1.3.0 → 1.4.0-beta.0

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.
@@ -0,0 +1,378 @@
1
+ const THREE = require('three');
2
+ const updateMorphColorAttribute = require("../utilities").updateMorphColorAttribute;
3
+ const toBufferGeometry = require('../utilities').toBufferGeometry;
4
+
5
+ /**
6
+ * Provides an object which stores meshes at different levels based
7
+ * on specified distance.
8
+ * This object is ued by zincObject to provide mesh at different LODs.
9
+ * A layer is displayed when the distance from the camera is greater
10
+ * than its specified distance and closest compared to other layers.
11
+ * This is intended to be an internal object used only by Zinc Object.
12
+ *
13
+ * This object assumes the centroid and bounding box are consistent between
14
+ * different level of layers.
15
+ *
16
+ * @class
17
+ * @author Alan Wu
18
+ * @return {LOD}
19
+ */
20
+ const LOD = function (parent) {
21
+ this.levels = [];
22
+ this._currentLevel = 0;
23
+ this._renderOrder = 1;
24
+ this._material = undefined;
25
+ this._secondaryMaterial = undefined;
26
+ this._loader = undefined;
27
+ //The owning Zinc Object
28
+ this._parent = parent;
29
+
30
+
31
+ /*
32
+ * Add a level of LOD at the specified distance
33
+ */
34
+ this.addLevel = (object, distanceIn) => {
35
+ if (object) {
36
+ const distance = Math.abs(distanceIn);
37
+ let l;
38
+ for (l = 0; l < this.levels.length; l++) {
39
+ if (distance < this.levels[l].distance) {
40
+ break;
41
+ }
42
+ }
43
+ const levelObject = {
44
+ distance: distance,
45
+ morph: object,
46
+ loaded: true,
47
+ loading: false,
48
+ url: "",
49
+ };
50
+ this.levels.splice(l, 0, levelObject);
51
+ object.renderOrder = this._renderOrder;
52
+ //this.add( object );
53
+ }
54
+ }
55
+
56
+ /*
57
+ * This is called once an ondemand level is loaded
58
+ */
59
+ this.levelLoaded = (object, distanceIn) => {
60
+ if (object) {
61
+ const distance = Math.abs(distanceIn);
62
+ let l;
63
+ for (l = 0; l < this.levels.length; l++) {
64
+ if (distance === this.levels[l].distance) {
65
+ this._parent.group.add(object);
66
+ this.levels[l].morph = object;
67
+ this.levels[l].loaded = true;
68
+ this.levels[l].loading = false;
69
+ break;
70
+ }
71
+ }
72
+ }
73
+ }
74
+
75
+ this.addLevelFromURL = (loader, level, url, preload) => {
76
+ this._loader = loader;
77
+ const distance = this.calculateDistance(level);
78
+ const levelObject = {
79
+ distance: distance,
80
+ morph: undefined,
81
+ loaded: false,
82
+ loading: false,
83
+ url: url,
84
+ };
85
+ for (l = 0; l < this.levels.length; l++) {
86
+ if (distance < this.levels[l].distance) {
87
+ break;
88
+ }
89
+ }
90
+ this.levels.splice(l, 0, levelObject);
91
+ if (preload) {
92
+ this.loadLevel(l);
93
+ }
94
+ }
95
+
96
+ //load the mesh at index, return true if morph is not ready
97
+ this.loadLevel = (index) => {
98
+ const level = this.levels[index];
99
+ if (!level.morph && !level.loaded &&
100
+ !level.loading) {
101
+ level.loading = true;
102
+ this._loader.load(level.url, this.lodLoader(level.distance),
103
+ undefined, undefined);
104
+ }
105
+ return (level.morph === undefined);
106
+ }
107
+
108
+
109
+ this.calculateDistance = function (level) {
110
+ this._parent.getBoundingBox();
111
+ const radius = this._parent.radius;
112
+ let distance = 0;
113
+ if (level === "far") {
114
+ distance = radius * 4.5;
115
+ } else if (level === "medium") {
116
+ distance = radius * 2.5;
117
+ } else if (level === "close") {
118
+ distance = 0;
119
+ }
120
+ return distance;
121
+ }
122
+
123
+ /**
124
+ * Check if there are multiple levels.
125
+ */
126
+ this.containsLevels = () => {
127
+ if (this.levels && this.levels.length > 1) {
128
+ return true;
129
+ }
130
+ return false;
131
+ }
132
+
133
+ /**
134
+ * Check if material is transparent, create secondary mesh
135
+ * for better rendering if required.
136
+ */
137
+ this.checkTransparentMesh = (animationGroup, transparentChanged) => {
138
+ const level = this.levels[this._currentLevel];
139
+ if (this._material) {
140
+ if (this._material.transparent) {
141
+ if (!this._secondaryMaterial) {
142
+ this._secondaryMaterial = this._material.clone();
143
+ this._secondaryMaterial.side = THREE.FrontSide;
144
+ }
145
+ this._secondaryMaterial.opacity = this._material.opacity;
146
+ // THREE.Mesh - for utilities purpose such as rendering
147
+ // transparent surfaces - one for front face and one for back face.
148
+ if (!level.secondaryMesh) {
149
+ level.secondaryMesh = new THREE.Mesh(level.morph.geometry,
150
+ this._secondaryMaterial);
151
+ level.secondaryMesh.renderOrder = level.morph.renderOrder + 1;
152
+ level.secondaryMesh.userData = level.morph.userData;
153
+ level.secondaryMesh.name = level.morph.name;
154
+ }
155
+ if (transparentChanged) {
156
+ this._material.side = THREE.BackSide;
157
+ this._material.needsUpdate = true;
158
+ level.morph.add(level.secondaryMesh);
159
+ animationGroup.add(level.secondaryMesh);
160
+ }
161
+ } else {
162
+ if (level.secondaryMesh) {
163
+ //Do not delete this mesh, remove it from
164
+ //rendering and animation group instead
165
+ level.morph.remove(level.secondaryMesh);
166
+ animationGroup.uncache(level.secondaryMesh);
167
+ animationGroup.remove(level.secondaryMesh);
168
+ }
169
+ this._material.side = THREE.DoubleSide;
170
+ }
171
+ }
172
+ }
173
+
174
+ this.dispose = () => {
175
+ this.levels.forEach((level) => {
176
+ if (level.morph && level.morph.geometry) {
177
+ level.morph.geometry.dispose();
178
+ }
179
+ });
180
+ if (this._material) {
181
+ this._material.dispose();
182
+ }
183
+ if (this._secondaryMaterial) {
184
+ this._secondaryMaterial.dispose();
185
+ }
186
+ }
187
+
188
+ this.getCurrentLevel = () => {
189
+ return this._currentLevel;
190
+ }
191
+
192
+ this.getCurrentMorph = () => {
193
+ const level = this.levels[this._currentLevel];
194
+ if (level && level.morph) {
195
+ return level.morph;
196
+ }
197
+ return this._parent.morph;
198
+ }
199
+
200
+ /**
201
+ * Loader for lod object
202
+ */
203
+ this.lodLoader = function (distance) {
204
+ return (geometryIn) => {
205
+ const material = this._material;
206
+ const options = {
207
+ localTimeEnabled: this._parent.timeEnabled,
208
+ localMorphColour: this._parent.morphColour,
209
+ }
210
+ const geometry = toBufferGeometry(geometryIn, options);
211
+ const mesh = new THREE.Mesh(geometry, material);
212
+ geometryIn.dispose();
213
+ this.levelLoaded(mesh, distance);
214
+ };
215
+ }
216
+
217
+ this.updateMorphColorAttribute = (currentOnly) => {
218
+ //Multilayers - set all
219
+ if (this._material) {
220
+ if ((this._material.vertexColors == THREE.VertexColors) ||
221
+ (this._material.vertexColors == true)) {
222
+ if (currentOnly) {
223
+ const morph = this.getCurrentMorph();
224
+ updateMorphColorAttribute(morph.geometry, morph);
225
+ } else {
226
+ this.levels.forEach((level) => {
227
+ if (level.morph && level.morph.geometry) {
228
+ updateMorphColorAttribute(level.morph.geometry, level.morph);
229
+ }
230
+ });
231
+ }
232
+ }
233
+ }
234
+ }
235
+
236
+ this.setColour = (colour) => {
237
+ this._material.color = colour;
238
+ if (this._secondaryMaterial) {
239
+ this._secondaryMaterial.color = colour;
240
+ }
241
+ updateGeometryColour();
242
+ }
243
+
244
+ this.setFrustumCulled = (flag) => {
245
+ this.levels.forEach((level) => {
246
+ if (level.morph) {
247
+ level.morph.frustumCulled = flag;
248
+ }
249
+ if (level.secondaryMesh) {
250
+ level.secondaryMesh.frustumCulled = flag;
251
+ }
252
+ });
253
+ }
254
+
255
+ this.setMaterial = (material) => {
256
+ if (material) {
257
+ if (!this._material || (this._material.id !== material.id)) {
258
+ this._material = material;
259
+ if (this._secondaryMaterial) {
260
+ this._secondaryMaterial.dispose();
261
+ this._secondaryMaterial = material.clone()
262
+ this._secondaryMaterial.side = THREE.FrontSide;
263
+ }
264
+ this.levels.forEach((level) => {
265
+ if (level.morph) {
266
+ level.morph.material = this._material;
267
+ if (level.morph.geometry) {
268
+ level.morph.geometry.colorsNeedUpdate = true;
269
+ }
270
+ }
271
+ if (level.secondaryMesh) {
272
+ level.secondaryMesh.material = this._secondaryMaterial;
273
+ }
274
+ });
275
+ }
276
+ }
277
+ }
278
+
279
+ this.setName = (name) => {
280
+ this.levels.forEach((level) => {
281
+ if (level.morph) {
282
+ level.morph.name = name;
283
+ }
284
+ if (level.secondaryMesh) {
285
+ level.secondaryMesh.name = name;
286
+ }
287
+ });
288
+ }
289
+
290
+ this.setRenderOrder = (order) => {
291
+ this._renderOrder = order;
292
+ this.levels.forEach((level) => {
293
+ if (level.morph) {
294
+ level.morph.renderOrder = order;
295
+ }
296
+ if (level.secondaryMesh) {
297
+ level.secondaryMesh.renderOrder = order;
298
+ }
299
+ });
300
+ }
301
+
302
+ this.setVertexColors = (vertexColors) => {
303
+ this._material.vertexColors = vertexColors;
304
+ updateGeometryColour();
305
+ if (this._secondaryMaterial) {
306
+ this._secondaryMaterial.vertexColors = vertexColors;
307
+ }
308
+ }
309
+
310
+ /* Update layers based on the */
311
+ this.update = (camera, center) => {
312
+ const levels = this.levels;
313
+ if (levels.length > 1) {
314
+ const distance = camera.cameraObject.position.distanceTo(center);
315
+ let visibleIndex = -1;
316
+ let optimalIndex = -1;
317
+ let i, l;
318
+ //Found a visible index that is within range of the LOD
319
+ for (i = 0, l = levels.length; i < l; i++) {
320
+ if (distance >= levels[i].distance) {
321
+ //Check if a level is loading
322
+ if (levels[i].morph) {
323
+ if (visibleIndex > -1 && levels[visibleIndex].morph) {
324
+ levels[visibleIndex].morph.visible = false;
325
+ }
326
+ visibleIndex = i;
327
+ levels[i].morph.visible = true;
328
+ optimalIndex = -1;
329
+ }
330
+ else {
331
+ optimalIndex = i;
332
+ }
333
+ } else {
334
+ break;
335
+ }
336
+ }
337
+ if (optimalIndex > -1) {
338
+ this.loadLevel(optimalIndex);
339
+ }
340
+ for (; i < l; i++) {
341
+ if (levels[i].morph) {
342
+ //Set visibility of other morph to false
343
+ //and set the closest lod to true if
344
+ //none is found
345
+ if (visibleIndex > -1) {
346
+ levels[i].morph.visible = false;
347
+ } else {
348
+ levels[i].morph.visible = true;
349
+ visibleIndex = i;
350
+ }
351
+ }
352
+ }
353
+ this._currentLevel = visibleIndex;
354
+ }
355
+ }
356
+
357
+ this.toggleMarker = (marker, flag) => {
358
+ this.levels.forEach((level) => {
359
+ if (level.morph) {
360
+ if (flag) {
361
+ level.morph.add(marker);
362
+ } else {
363
+ level.morph.remove(marker);
364
+ }
365
+ }
366
+ });
367
+ }
368
+
369
+ updateGeometryColour = () => {
370
+ this.levels.forEach((level) => {
371
+ if (level.morph && level.morph.geometry) {
372
+ level.morph.geometry.colorsNeedUpdate = true;
373
+ }
374
+ });
375
+ }
376
+ }
377
+
378
+ exports.LOD = LOD;
@@ -21,6 +21,7 @@ const Marker = function(zincObject) {
21
21
  let spriteMaterial = undefined;
22
22
  let sprite = undefined;
23
23
  this.morph = new THREE.Group();
24
+ this.group = this.morph;
24
25
  this.parent = zincObject;
25
26
  this.isMarker = true;
26
27
  let enabled = false;
@@ -1,5 +1,6 @@
1
1
  const THREE = require('three');
2
2
  const Points = require('../three/Points').Points;
3
+ const toBufferGeometry = require('../utilities').toBufferGeometry;
3
4
 
4
5
  /**
5
6
  * Provides an object which stores points and provides method which controls its position.
@@ -37,7 +38,7 @@ const Pointset = function () {
37
38
  */
38
39
  this.createMesh = (geometryIn, materialIn, options) => {
39
40
  if (geometryIn && materialIn) {
40
- let geometry = this.toBufferGeometry(geometryIn, options);
41
+ let geometry = toBufferGeometry(geometryIn, options);
41
42
  const texture = getCircularTexture();
42
43
  materialIn.map = texture;
43
44
  let point = new Points(geometry, materialIn);
@@ -16,7 +16,7 @@ const TextureSlides = function (textureIn) {
16
16
  this.isTextureSlides = true;
17
17
  const textureSettings = [];
18
18
  const idTextureMap = {};
19
- this.morph = new THREE.Group();
19
+ this.setMorph(new THREE.Group());
20
20
  this.morph.userData = this;
21
21
  const alpha = 1.0;
22
22