janusweb 1.5.43 → 1.5.44

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.
@@ -169,4 +169,4 @@ janus-voip-picker>ul li button[disabled] {
169
169
  color: #888;
170
170
  text-shadow: 0 0 5px #444;
171
171
  cursor: not-allowed;
172
-
172
+ }
@@ -167,8 +167,14 @@ janus.registerElement('locomotion_teleporter', {
167
167
  speed = dir.length();
168
168
  dir.divideScalar(speed);
169
169
  let hits = room.raycast(dir, p0, null, speed);
170
- if (hits.length > 0) {
171
- let hit = hits[0];
170
+ let hit = false;
171
+ for (let j = 0; j < hits.length; j++) {
172
+ if (hits[j].object !== player) {
173
+ hit = hits[j];
174
+ break;
175
+ }
176
+ }
177
+ if (hit) {
172
178
  p1.copy(hit.point);
173
179
  if (hit.distance < 200) {
174
180
  this.pos = player.worldToLocal(hit.point);
@@ -21,6 +21,7 @@ janus.registerElement('xrmenu', {
21
21
  this.panels = {};
22
22
 
23
23
  let xrmenu = janus.ui.apps.default.apps.xrmenu;
24
+ if (!xrmenu) return;
24
25
  let asseturl = xrmenu.resolveFullURL('./xrmenu-assets.json');
25
26
  fetch(asseturl).then(res => res.json()).then(assetlist => {
26
27
  this.assetpack = elation.engine.assets.loadJSON(assetlist, xrmenu.resolveFullURL('./'));
@@ -186,28 +187,36 @@ janus.registerElement('xrmenu-popup', {
186
187
  this.shadowdom = container.attachShadow({mode: 'open'});
187
188
  //container.appendChild(element);
188
189
 
189
- setTimeout(() => {
190
- console.log('LOADED????', janus.ui, janus.ui.apps.default);
191
- this.initShadowStylesheets();
192
- }, 0);
193
- this.shadowdom.appendChild(element);
190
+ setTimeout(() => {
191
+ this.initShadowStylesheets();
192
+ }, 0);
193
+ //this.shadowdom.appendChild(element);
194
+ let a = document.createElement('html');
195
+ let b = document.createElement('body');
196
+ b.className = 'dark janusweb';
197
+ a.appendChild(b);
198
+ this.shadowdom.appendChild(a);
199
+ b.appendChild(element);
194
200
  document.body.appendChild(container);
195
201
 
202
+ elation.events.add(element, 'styleupdate', ev => {
203
+ this.initShadowStylesheets();
204
+ });
196
205
 
197
- container.style.position = 'absolute';
198
- container.style.top = '0';
199
- container.style.left = '0';
200
- container.style.zIndex = -1000;
201
- container.style.width = this.width + 'px';
202
- container.style.height = this.height + 'px';
203
- container.style.overflow = 'auto';
204
- container.style.opacity = 0;
205
- //container.style.transform = 'translateX(-40000px)';
206
- //container.style.border = '1px solid red';
206
+ container.style.position = 'absolute';
207
+ container.style.top = '0';
208
+ container.style.left = '0';
209
+ container.style.zIndex = -1000;
210
+ container.style.width = this.width + 'px';
211
+ container.style.height = this.height + 'px';
212
+ container.style.overflow = 'hidden';
213
+ container.style.opacity = 0;
214
+ //container.style.transform = 'translateX(-40000px)';
215
+ //container.style.border = '1px solid red';
207
216
 
208
- this.elementcontainer = container;
217
+ this.elementcontainer = container;
209
218
 
210
- this.initElementCanvas();
219
+ this.initElementCanvas();
211
220
 
212
221
  this.plane = this.createObject('object', {
213
222
  id: 'plane',
@@ -249,6 +258,7 @@ canvas.style.border = '1px solid red';
249
258
  this.loadNewAsset('image', {
250
259
  id: 'xrmenu-element-canvas',
251
260
  canvas: canvas,
261
+ transparent: true,
252
262
  });
253
263
  this.plane.image_id = 'xrmenu-element-canvas';
254
264
  this.canvas = canvas;
@@ -264,12 +274,23 @@ canvas.style.border = '1px solid red';
264
274
  let promises = [];
265
275
  for (let i = 0; i < document.styleSheets.length; i++) {
266
276
  //promises.push(new Promise(accept => {
267
- let styleel = document.createElement('link');
268
- styleel.rel = 'stylesheet';
269
- styleel.href = elation.engine.assets.corsproxy + document.styleSheets[i].href;
270
- //styleel.onload = accept;
271
- this.shadowdom.appendChild(styleel);
272
- console.log('add link', document.styleSheets[i].href);
277
+ if (document.styleSheets[i].href ) {
278
+ // external stylesheet
279
+ let styleel = document.createElement('link');
280
+ styleel.rel = 'stylesheet';
281
+ styleel.href = elation.engine.assets.corsproxy + document.styleSheets[i].href;
282
+ this.shadowdom.appendChild(styleel);
283
+ } else if (document.styleSheets[i].cssRules.length > 0) {
284
+ // inline <style> definition
285
+ let txt = '';
286
+ let sheet = document.styleSheets[i];
287
+ for (let i = 0; i < sheet.cssRules.length; i++) {
288
+ txt += sheet.cssRules[i].cssText + '\n';
289
+ }
290
+ let styleel = document.createElement('style');
291
+ styleel.appendChild(document.createTextNode(txt));
292
+ this.shadowdom.appendChild(styleel);
293
+ }
273
294
  //}));
274
295
  }
275
296
  /*
@@ -336,7 +357,6 @@ setTimeout(() => {
336
357
  clientY: mousexy[1],
337
358
  view: window,
338
359
  });
339
- console.log(mouseover);
340
360
  target.dispatchEvent(mouseover);
341
361
  }
342
362
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "janusweb",
3
3
  "description": "Web client for JanusVR worlds",
4
- "version": "1.5.43",
4
+ "version": "1.5.44",
5
5
  "main": "scripts/janusweb.js",
6
6
  "author": "James Baicoianu",
7
7
  "license": "MIT",
package/scripts/client.js CHANGED
@@ -133,6 +133,17 @@ elation.require(['elements.elements', 'elements', 'engine.engine', 'engine.asset
133
133
  this.startXR();
134
134
  });
135
135
  }
136
+ window.addEventListener('load', ev => {
137
+ window.scrollTo(0, 1);
138
+ });
139
+ window.addEventListener('touchend', ev => {
140
+ // FIXME - useragent hack isn't the best way of handling this, but it beats getting stuck in non-immersive fullscreen mode while in a VR headset
141
+ if (navigator.userAgent.indexOf('OculusBrowser') != -1) {
142
+ this.startXR();
143
+ } else if (!this.view.isFullscreen()) {
144
+ this.toggleFullscreen({value: 1});
145
+ }
146
+ });
136
147
  }
137
148
  initButtons() {
138
149
  this.sharebutton = elation.ui.button({classname: 'janusweb_sharing', label: 'Share'});
package/scripts/config.js CHANGED
@@ -26,7 +26,7 @@ elation.config.set('share.targets.yahoo.clientid', '374523350201-p566ctvssq49sa4
26
26
  elation.config.set('share.targets.facebook.clientid', '1197654320349894');
27
27
  elation.config.set('share.targets.file.enabled', true);
28
28
 
29
- elation.config.set('serviceworker.enabled', true);
29
+ elation.config.set('serviceworker.enabled', false);
30
30
 
31
31
  // FIXME - hack for dev, we should support role-based config
32
32
  if (typeof document != 'undefined' && document.location.origin == 'https://bai.dev.supcrit.com') {
@@ -178,7 +178,7 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
178
178
  collider.traverse(n => {
179
179
  // Ignore collider if it's too high-poly
180
180
  if (n instanceof THREE.Mesh && n.geometry instanceof THREE.BufferGeometry) {
181
- if (n.geometry.attributes.position.count > 65536) {
181
+ if (n.geometry.attributes.position.count > 65536 * 3) {
182
182
  console.warn('Collider mesh rejected, too many polys!', collision_id, this, n, collider);
183
183
  elation.events.fire({type: 'thing_collider_rejected', element: this, data: {root: collider, mesh: n}});
184
184
  remove.push(n);
@@ -564,7 +564,8 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
564
564
  hasalpha: args.hasalpha,
565
565
  maxsize: args.maxsize,
566
566
  preload: args.preload,
567
- baseurl: this.baseurl
567
+ baseurl: this.baseurl,
568
+ srgb: args.srgb
568
569
  };
569
570
  assetlist.push(assetargs);
570
571
  } else if (args.canvas) {
@@ -766,8 +767,8 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
766
767
  dir = new THREE.Vector3(),
767
768
  up = new THREE.Vector3();
768
769
  return function(ev) {
769
- let parent = this.properties.parent;
770
- let billboard = this.properties.billboard;
770
+ const parent = this.properties.parent;
771
+ const billboard = this.properties.billboard;
771
772
  if (billboard && parent) {
772
773
  //player.camera.localToWorld(playerpos.set(0,0,0));
773
774
  //this.localToWorld(objpos.set(0,0,0));
@@ -795,14 +796,11 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
795
796
  */
796
797
  // TODO - Simple trig makes this much faster, but to get the same functionality as before we'll need to implement each dimension
797
798
  // For now, we only support billboarding with the Y axis locked (eg, doom sprites)
798
- let views = this.engine.systems.render.views;
799
- let camera = player.camera;
800
- if (views.xr && views.xr.enabled && views.xr.camera && views.xr.camera.userData.thing) {
801
- camera = views.xr.camera.userData.thing;
802
- }
803
- parent.worldToLocal(camera.getWorldPosition(playerpos)).sub(this.position);
804
- dir.copy(playerpos).normalize();
805
799
  if (billboard == 'y' || billboard === true || billboard == 'true') {
800
+ const views = this.engine.systems.render.views;
801
+ const camera = (views.xr && views.xr.enabled && views.xr.camera && views.xr.camera.userData.thing ? views.xr.camera.userData.thing : player.camera)
802
+ parent.worldToLocal(camera.getWorldPosition(playerpos)).sub(this.position);
803
+ dir.copy(playerpos).normalize();
806
804
  this.rotation.radians.set(0, Math.atan2(dir.x, dir.z), 0);
807
805
  this.frameupdates['rotation'] = true;
808
806
  }
@@ -837,7 +835,7 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
837
835
 
838
836
  this.resetFrameUpdates();
839
837
  this.dispatchEvent({type: 'update', data: ev.data, bubbles: false});
840
- var proxy = this.getProxyObject();
838
+ const proxy = this.getProxyObject();
841
839
  if (this.created && typeof proxy.update == 'function') {
842
840
  proxy.update(ev.data);
843
841
  }
@@ -918,6 +916,8 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
918
916
  this.frameupdates['zdir'] = false;
919
917
  this.frameupdates['rotation'] = false;
920
918
  this.frameupdates['rotation_dir'] = false;
919
+ this.frameupdates['rotation_order'] = false;
920
+ this.frameupdates['fwd'] = false;
921
921
 
922
922
  for (var k in this.lastframevalues) {
923
923
  this.lastframevalues[k].copy(this.properties[k]);
@@ -1096,12 +1096,12 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
1096
1096
  if (!event.target) {
1097
1097
  event.target = target || event.element;
1098
1098
  }
1099
- /*
1099
+
1100
1100
  var handlerfn = 'on' + event.type;
1101
1101
  if (handlerfn in this) {
1102
1102
  this.executeCallback(this[handlerfn], event);
1103
1103
  }
1104
- */
1104
+
1105
1105
  // Bubble event up to parents, unless the event was thrown with bubbling disabled or an event handler called stopPropagation()
1106
1106
  let firedev = elation.events.fire(event);
1107
1107
  let returnValue = true;
@@ -828,10 +828,12 @@ return;
828
828
  let headaction = this.headaction || this._target.headaction;
829
829
  if (headaction && headaction._clip.tracks[0]) {
830
830
  let track = headaction._clip.tracks[0];
831
- track.values[0] = orientation.x * (invert ? -1 : 1);
832
- track.values[1] = orientation.y * (invert ? -1 : 1);
833
- track.values[2] = orientation.z * (invert ? -1 : 1);
834
- track.values[3] = orientation.w; // * (invert ? -1 : 1);
831
+ if (track) {
832
+ track.values[0] = orientation.x * (invert ? -1 : 1);
833
+ track.values[1] = orientation.y * (invert ? -1 : 1);
834
+ track.values[2] = orientation.z * (invert ? -1 : 1);
835
+ track.values[3] = orientation.w; // * (invert ? -1 : 1);
836
+ }
835
837
  }
836
838
  }
837
839
  this.blink = function() {
@@ -51,6 +51,7 @@ elation.require(['engine.things.player', 'janusweb.external.JanusVOIP', 'ui.butt
51
51
  elation.events.add(this.engine.client.view.container, 'touchstart', elation.bind(this, this.handleTouchStart));
52
52
  elation.events.add(this.engine.client.view.container, 'touchmove', elation.bind(this, this.handleTouchMove));
53
53
  elation.events.add(this.engine.client.view.container, 'touchend', elation.bind(this, this.handleTouchEnd));
54
+ elation.events.add(this.engine.client.view.container, 'touchcancel', elation.bind(this, this.handleTouchEnd));
54
55
 
55
56
  this.controlstate2 = this.engine.systems.controls.addContext('janusplayer', {
56
57
  'toggle_view': ['keyboard_nomod_v,keyboard_shift_v', elation.bind(this, this.toggleCamera)],
@@ -556,8 +557,34 @@ document.body.dispatchEvent(click);
556
557
  }
557
558
  }
558
559
  this.start = function() {
560
+ if (!this.started) {
561
+ if (!this.static) {
562
+ elation.events.add(this.room, 'janusweb_script_frame_end', this.handleFrameUpdates);
563
+ } else {
564
+ this.handleFrameUpdates({data: {dt: 0}});
565
+ }
566
+ this.started = true;
567
+ }
568
+ for (var k in this.children) {
569
+ if (this.children[k].start) {
570
+ this.children[k].start();
571
+ }
572
+ }
573
+ this.dispatchEvent({type: 'start', bubbles: false});
559
574
  }
560
575
  this.stop = function() {
576
+ for (var k in this.children) {
577
+ if (this.children[k].stop) {
578
+ this.children[k].stop();
579
+ }
580
+ }
581
+ if (this.started) {
582
+ if (!this.static) {
583
+ elation.events.remove(this.room, 'janusweb_script_frame_end', this.handleFrameUpdates);
584
+ }
585
+ this.started = false;
586
+ this.dispatchEvent({type: 'stop', bubbles: false});
587
+ }
561
588
  }
562
589
  this.getProxyObject = function() {
563
590
  if (!this._proxyobject) {
@@ -898,9 +925,9 @@ document.body.dispatchEvent(click);
898
925
  this.setCollider('sphere', {
899
926
  radius: this.collision_radius,
900
927
  });
901
- this.pickable = false;
902
928
  this.collidable = false;
903
929
  */
930
+ this.pickable = false;
904
931
  this.setCollider('capsule', {
905
932
  radius: this.collision_radius,
906
933
  length: 1,
@@ -989,8 +1016,9 @@ document.body.dispatchEvent(click);
989
1016
  }
990
1017
  }
991
1018
  if (!document.fullscreenElement) {
992
- //this.engine.client.toggleFullscreen({data: 1});
1019
+ this.engine.client.toggleFullscreen({data: 1});
993
1020
  }
1021
+ this.cancelTouchMovement(ev);
994
1022
  }
995
1023
  this.handleTouchMove = function(ev) {
996
1024
  if (ev.defaultPrevented) return;
@@ -1026,22 +1054,22 @@ document.body.dispatchEvent(click);
1026
1054
  this.touchcache.positions[touch.identifier][0] = touch.clientX;
1027
1055
  this.touchcache.positions[touch.identifier][1] = touch.clientY;
1028
1056
  }
1029
-
1030
1057
  }
1058
+ this.cancelTouchMovement(ev);
1031
1059
  }
1032
1060
  this.handleTouchEnd = function(ev) {
1033
- for (let i = 0; i < ev.changedTouches.length; i++) {
1034
- let touch = ev.changedTouches[i];
1061
+ this.cancelTouchMovement(ev);
1062
+ }
1063
+ this.cancelTouchMovement = function(ev) {
1064
+ for (let i = 0; i < ev.touches.length; i++) {
1065
+ let touch = ev.touches[i];
1035
1066
  if (touch.identifier === this.touchindex[0]) {
1036
- this.controlstate.move_right = 0;
1037
- this.controlstate.move_forward = 0;
1038
- this.touchindex[0] = null;
1039
- } else if (touch.identifier === this.touchindex[1]) {
1040
- this.controlstate.turn_right = 0;
1041
- this.controlstate.look_down = 0;
1042
- this.touchindex[1] = null;
1067
+ return;
1043
1068
  }
1044
1069
  }
1070
+ this.controlstate.move_right = 0;
1071
+ this.controlstate.move_forward = 0;
1072
+ this.touchindex[0] = null;
1045
1073
  }
1046
1074
  this.updatePartyMode = function(key, value) {
1047
1075
  if (typeof value != 'undefined') {
@@ -315,7 +315,7 @@ elation.require([
315
315
  baseurl: baseurl,
316
316
  corsproxy: this.corsproxy,
317
317
  deferload: true
318
- });
318
+ }, makeactive && typeof makeactive != 'undefined');
319
319
 
320
320
  if (this.currentroom && !stripreferrer) {
321
321
  room.referrer = this.currentroom.url;
@@ -356,7 +356,7 @@ elation.require([
356
356
  room = this.rooms[roomid];
357
357
  }
358
358
  } else if (url.type == 'janusroom') {
359
- room = url;
359
+ room = url._target || url;
360
360
  url = room.url;
361
361
  }
362
362
  var player = this.engine.client.player;
@@ -424,7 +424,7 @@ elation.require([
424
424
  janus: this,
425
425
  corsproxy: this.corsproxy,
426
426
  deferload: true
427
- });
427
+ }, !makeactive);
428
428
 
429
429
  this.rooms[newroom.roomid] = newroom;
430
430
  //console.log('made new room', url, room);
@@ -485,9 +485,22 @@ elation.require([
485
485
  var hashurl = hashargs['janus.url'];
486
486
  if (hashurl && hashurl != this.properties.url && !this.loading) {
487
487
  this.setActiveRoom(hashurl, this.currentroom.url, true);
488
- } else if (!hashurl && this.properties.url != this.homepage && !document.location.hash) {
488
+ } else if (!hashurl && this.properties.url != this.homepage) { // && !document.location.hash) {
489
489
  this.setActiveRoom(this.homepage);
490
490
  }
491
+ if (document.location.hash && document.location.hash.substr(1) in room.objects) {
492
+ let jumpto = room.objects[document.location.hash.substr(1)];
493
+ if (typeof jumpto.activate == 'function') {
494
+ jumpto.activate();
495
+ } else if (typeof jumpto.navigate == 'function') {
496
+ jumpto.navigate();
497
+ } else {
498
+ player.pos = jumpto.pos;
499
+ player.xdir.copy(jumpto.xdir);
500
+ player.ydir.copy(jumpto.ydir);
501
+ player.zdir.copy(jumpto.zdir);
502
+ }
503
+ }
491
504
  }
492
505
  }
493
506
 
@@ -570,7 +570,7 @@ elation.require(['engine.things.generic', 'janusweb.external.webxr-input-profile
570
570
  create() {
571
571
  this.lasercolor = V(1,0,0);
572
572
  this.laser = this.createObject('linesegments', {
573
- positions: [V(0,0,0), V(0,0,-.5)],
573
+ positions: [V(0,0,0), V(0,0,-5)],
574
574
  opacity: .8,
575
575
  col: this.lasercolor,
576
576
  visible: false,
@@ -580,7 +580,7 @@ elation.require(['engine.things.generic', 'janusweb.external.webxr-input-profile
580
580
  id: 'cylinder',
581
581
  col: 'white',
582
582
  lighting: false,
583
- scale: V(.005, .5, .005),
583
+ scale: V(.005, 5, .005),
584
584
  rotation: V(-90,0,0),
585
585
  opacity: .2,
586
586
  });
@@ -634,6 +634,7 @@ elation.require(['engine.things.generic', 'janusweb.external.webxr-input-profile
634
634
  this.laser.updateColor();
635
635
  this.cursor.image_id = 'cursor_dot_active';
636
636
  this.cursor.opacity = player.cursor_opacity;
637
+ this.bonk.col.setRGB(.5,1,.5);
637
638
  this.bonk.opacity = 0.2 * player.cursor_opacity;
638
639
  //this.laser.visible = false; // FIXME - hack to disable laser without breaking things
639
640
 
@@ -650,6 +651,7 @@ elation.require(['engine.things.generic', 'janusweb.external.webxr-input-profile
650
651
  this.laser.updateColor();
651
652
  this.cursor.image_id = 'cursor_dot_inactive';
652
653
  this.cursor.opacity = player.cursor_opacity / 2;
654
+ this.bonk.col.setRGB(1,1,1);
653
655
  //this.laser.visible = false; // FIXME - hack to disable laser without breaking things
654
656
  }
655
657
  },
@@ -843,7 +845,9 @@ elation.require(['engine.things.generic', 'janusweb.external.webxr-input-profile
843
845
  visible: false
844
846
  });
845
847
  this.tmpobj = new THREE.Object3D();
848
+ this.tmpquat = new THREE.Quaternion();
846
849
  this.jointmaterial = new THREE.MeshPhysicalMaterial({color: 0xccffcc, metalness: 1, roughness: .5, emissive: 0xccffcc, transparent: true});
850
+ this.tmpobj.matrixAutoUpdate = false;
847
851
  this.joints = new THREE.InstancedMesh(new THREE.SphereGeometry(1), this.jointmaterial, 26);
848
852
  this.joints.frustumCulled = false;
849
853
  this.joints.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
@@ -869,7 +873,7 @@ elation.require(['engine.things.generic', 'janusweb.external.webxr-input-profile
869
873
  return;
870
874
  }
871
875
 
872
- let tmpobj = this.tmpobj,
876
+ let tmpobj = this.tmpobj, tmpquat = this.tmpquat,
873
877
  i = 0;
874
878
  let poses = this.jointposes;
875
879
  /*
@@ -893,30 +897,36 @@ elation.require(['engine.things.generic', 'janusweb.external.webxr-input-profile
893
897
  }
894
898
  }
895
899
  */
896
- for ( const inputjoint of this.hand.values() ) {
900
+ const handvalues = this.hand.values(), jointposes = this.jointposes;
901
+ for ( const inputjoint of handvalues ) {
897
902
  const jointpose = xrFrame.getJointPose( inputjoint, xrReferenceFrame );
898
903
  const jointname = inputjoint.jointName;
899
904
  if (jointpose && jointpose.transform) {
900
905
  let radius = Math.max(.002, jointpose.radius);
906
+ /*
901
907
  tmpobj.position.copy(jointpose.transform.position);
902
908
  tmpobj.quaternion.copy(jointpose.transform.orientation);
903
909
  tmpobj.scale.set(radius, radius, radius);
904
910
  tmpobj.updateMatrix();
911
+ */
912
+ tmpquat.copy(jointpose.transform.orientation);
913
+ if (tmpobj.scale.x != radius) tmpobj.scale.set(radius, radius, radius);
914
+ tmpobj.matrix.compose(jointpose.transform.position, tmpquat, tmpobj.scale)
905
915
  this.joints.setMatrixAt(i, tmpobj.matrix);
906
916
  //FIVARSlog('xr.debug', 'update joint: ' + i + ', ' + jointname + ', ' + tmpobj.matrix.elements.join(', '));
907
917
  }
908
918
  i++;
909
- this.jointposes[jointname] = jointpose;
919
+ jointposes[jointname] = jointpose;
910
920
  }
911
921
  this.joints.instanceMatrix.needsUpdate = true;
912
922
  //this.joints.computeBoundingSphere();
913
923
 
914
- if (this.jointposes['wrist']) this.localToWorld(this.handpos.copy(this.jointposes['wrist'].transform.position));
915
- if (this.jointposes['thumb-tip']) this.localToWorld(this.p0.copy(this.jointposes['thumb-tip'].transform.position));
916
- if (this.jointposes['index-finger-tip']) this.localToWorld(this.p1.copy(this.jointposes['index-finger-tip'].transform.position));
917
- if (this.jointposes['middle-finger-tip']) this.localToWorld(this.p2.copy(this.jointposes['middle-finger-tip'].transform.position));
918
- if (this.jointposes['ring-finger-tip']) this.localToWorld(this.p3.copy(this.jointposes['ring-finger-tip'].transform.position));
919
- if (this.jointposes['pinky-finger-tip']) this.localToWorld(this.p4.copy(this.jointposes['pinky-finger-tip'].transform.position));
924
+ if (jointposes['wrist']) this.localToWorld(this.handpos.copy(this.jointposes['wrist'].transform.position));
925
+ if (jointposes['thumb-tip']) this.localToWorld(this.p0.copy(this.jointposes['thumb-tip'].transform.position));
926
+ if (jointposes['index-finger-tip']) this.localToWorld(this.p1.copy(this.jointposes['index-finger-tip'].transform.position));
927
+ if (jointposes['middle-finger-tip']) this.localToWorld(this.p2.copy(this.jointposes['middle-finger-tip'].transform.position));
928
+ if (jointposes['ring-finger-tip']) this.localToWorld(this.p3.copy(this.jointposes['ring-finger-tip'].transform.position));
929
+ if (jointposes['pinky-finger-tip']) this.localToWorld(this.p4.copy(this.jointposes['pinky-finger-tip'].transform.position));
920
930
  this.isactive = true;
921
931
  this.jointmaterial.opacity = player.cursor_opacity;
922
932
  }
package/scripts/object.js CHANGED
@@ -195,7 +195,7 @@ elation.require(['janusweb.janusbase', 'janusweb.websurface'], function() {
195
195
  if (this.modelasset) {
196
196
  this.initAnimations(this.modelasset.animations);
197
197
  if (this.animations && this.anim_id && this.animations[this.anim_id]) {
198
- console.log('start animation', this);
198
+ //console.log('start animation', this);
199
199
  this.animations[this.anim_id].play();
200
200
  this.activeanimation = this.animations[this.anim_id];
201
201
  }
@@ -867,6 +867,12 @@ elation.require(['janusweb.janusbase', 'janusweb.websurface'], function() {
867
867
  m.emissive.copy(this.emissive)
868
868
  }
869
869
  m.emissiveIntensity = this.emissive_intensity;
870
+ } else {
871
+ if (textureEmissive) {
872
+ m.map = textureEmissive;
873
+ textureEmissive.encoding = THREE.sRGBEncoding;
874
+ m.color = new THREE.Color(0xffffff);
875
+ }
870
876
  }
871
877
  if (textureAlpha) {
872
878
  m.alphaMap = textureAlpha;
@@ -1028,6 +1034,11 @@ elation.require(['janusweb.janusbase', 'janusweb.websurface'], function() {
1028
1034
  }
1029
1035
  }
1030
1036
  if (oldmat.emissiveIntensity !== undefined) m.emissiveIntensity = oldmat.emissiveIntensity;
1037
+ } else {
1038
+ if (oldmat.emissiveMap && !oldmat.map) {
1039
+ m.map = oldmat.emissiveMap;
1040
+ oldmat.color.setRGB(1,1,1);
1041
+ }
1031
1042
  }
1032
1043
 
1033
1044
  m.lightMap = oldmat.lightMap;
package/scripts/portal.js CHANGED
@@ -21,6 +21,7 @@ elation.require(['janusweb.janusbase'], function() {
21
21
  'mirror_recursion': { type: 'integer', default: 2, set: this.updateGeometry },
22
22
  'mirror_texturesize': { type: 'integer', default: 1024, set: this.updateGeometry },
23
23
  'external': { type: 'boolean', default: false },
24
+ 'preload': { type: 'boolean', default: false },
24
25
  'target': { type: 'string', default: '' },
25
26
  'round': { type: 'boolean', default: false },
26
27
  'cooldown': { type: 'float', default: 1000 },
@@ -289,7 +290,12 @@ elation.require(['janusweb.janusbase'], function() {
289
290
  this.closePortal();
290
291
  }
291
292
  } else if (this.url) {
292
- this.properties.janus.setActiveRoom(this.url, room.url);
293
+ if (this.preload) {
294
+ let newroom = this.properties.janus.preload(this.url);
295
+ elation.events.add(newroom, 'room_load_complete', ev => this.properties.janus.setActiveRoom(newroom));
296
+ } else {
297
+ this.properties.janus.setActiveRoom(this.url, room.url);
298
+ }
293
299
  }
294
300
  }
295
301
  var gamepads = this.engine.systems.controls.gamepads;
@@ -320,6 +326,7 @@ elation.require(['janusweb.janusbase'], function() {
320
326
  shader_id: ['property', 'shader_id'],
321
327
  size: ['property', 'size'],
322
328
  round: ['property', 'round'],
329
+ preload: ['property', 'preload'],
323
330
  };
324
331
  }
325
332
  return this._proxyobject;
package/scripts/room.js CHANGED
@@ -5,6 +5,18 @@ elation.require([
5
5
  'janusweb.sound', 'janusweb.januslight', 'janusweb.janusparticle', 'janusweb.janusghost',
6
6
  'janusweb.translators.bookmarks', 'janusweb.translators.reddit', 'janusweb.translators.error', 'janusweb.translators.blank', 'janusweb.translators.default', 'janusweb.translators.dat', 'janusweb.translators.janusvfs'
7
7
  ], function() {
8
+ let roomTranslators = false;
9
+ function initRoomTranslators() {
10
+ roomTranslators = {
11
+ '^janus-vfs:': elation.janusweb.translators.janusvfs({janus: janus}),
12
+ '^about:blank$': elation.janusweb.translators.blank({janus: janus}),
13
+ '^bookmarks$': elation.janusweb.translators.bookmarks({janus: janus}),
14
+ '^dat:': elation.janusweb.translators.dat({janus: janus}),
15
+ '^https?:\/\/(www\.)?reddit.com': elation.janusweb.translators.reddit({janus: janus}),
16
+ '^error$': elation.janusweb.translators.error({janus: janus}),
17
+ '^default$': elation.janusweb.translators.default({janus: janus})
18
+ };
19
+ }
8
20
  elation.component.add('engine.things.janusroom', function() {
9
21
  this.postinit = function() {
10
22
  elation.engine.things.janusroom.extendclass.postinit.call(this);
@@ -82,15 +94,11 @@ elation.require([
82
94
  'sync': { type: 'boolean', default: false },
83
95
  'pointerlock': { type: 'boolean', default: true, set: this.updatePointerLock },
84
96
  });
85
- this.translators = {
86
- '^janus-vfs:': elation.janusweb.translators.janusvfs({janus: this.janus}),
87
- '^about:blank$': elation.janusweb.translators.blank({janus: this.janus}),
88
- '^bookmarks$': elation.janusweb.translators.bookmarks({janus: this.janus}),
89
- '^dat:': elation.janusweb.translators.dat({janus: this.janus}),
90
- '^https?:\/\/(www\.)?reddit.com': elation.janusweb.translators.reddit({janus: this.janus}),
91
- '^error$': elation.janusweb.translators.error({janus: this.janus}),
92
- '^default$': elation.janusweb.translators.default({janus: this.janus})
93
- };
97
+
98
+ if (!roomTranslators) {
99
+ initRoomTranslators();
100
+ }
101
+
94
102
  this.spawnpoint = new THREE.Object3D();
95
103
  this.roomsrc = '';
96
104
  this.changes = {};
@@ -151,6 +159,8 @@ elation.require([
151
159
  this.loadFromSource(this.source);
152
160
  }
153
161
  elation.events.add(this, 'thing_remove', elation.bind(this, this.onThingRemove));
162
+
163
+ document.addEventListener('visibilitychange', ev => this.handleVisibilityChange());
154
164
  }
155
165
  this.createChildren = function() {
156
166
  this.collidable = false;
@@ -211,13 +221,13 @@ elation.require([
211
221
  }
212
222
  }
213
223
  this.setActive = function() {
224
+ this.active = true;
214
225
  this.setSkybox();
215
226
  this.setFog();
216
227
  this.updateBloom();
217
228
  this.updateToneMapping();
218
229
  this.setNearFar();
219
230
  this.setPlayerPosition();
220
- this.active = true;
221
231
  elation.events.fire({element: this, type: 'room_active', data: this});
222
232
  }
223
233
  this.setPlayerPosition = function(pos, orientation) {
@@ -475,13 +485,17 @@ elation.require([
475
485
  }
476
486
  }
477
487
  this.updateToneMapping = function() {
478
- this.engine.systems.render.renderer.toneMapping = this.toneMappingTypes[this.tonemapping_type] || 0;
479
- this.engine.systems.render.renderer.toneMappingExposure = this.tonemapping_exposure;
480
- this.refresh();
488
+ if (this.active) {
489
+ this.engine.systems.render.renderer.toneMapping = this.toneMappingTypes[this.tonemapping_type] || 0;
490
+ this.engine.systems.render.renderer.toneMappingExposure = this.tonemapping_exposure;
491
+ this.refresh();
492
+ }
481
493
  }
482
494
  this.setNearFar = function() {
483
- this.engine.client.player.camera.camera.near = this.properties.near_dist;
484
- this.engine.client.player.camera.camera.far = this.properties.far_dist;
495
+ if (this.active) {
496
+ this.engine.client.player.camera.camera.near = this.properties.near_dist;
497
+ this.engine.client.player.camera.camera.far = this.properties.far_dist;
498
+ }
485
499
  }
486
500
  this.showDebug = function() {
487
501
  this.engine.client.player.disable();
@@ -624,7 +638,7 @@ elation.require([
624
638
  this.loadFromSource(data);
625
639
  }),
626
640
  failurecallback: elation.bind(this, function(xhr) {
627
- var translator = this.translators['^error$'];
641
+ var translator = roomTranslators['^error$'];
628
642
  translator.exec({janus: this.properties.janus, room: this, error: xhr.status || 404})
629
643
  .then(elation.bind(this, function(objs) {
630
644
  var datapath = elation.config.get('janusweb.datapath', '/media/janusweb');
@@ -684,7 +698,7 @@ elation.require([
684
698
  //this.parseerror = false;
685
699
  elation.events.fire({element: this, type: 'room_load_processed'});
686
700
  elation.events.fire({type: 'janus_room_load', element: this});
687
- if (this.pendingassets.length == 0) {
701
+ if (this.pendingassets.length == 0 && !this.completed) {
688
702
  setTimeout(() => elation.events.fire({element: this, type: 'room_load_complete'}), 0);
689
703
  }
690
704
  } catch (e) {
@@ -1028,11 +1042,11 @@ elation.require([
1028
1042
  });
1029
1043
  }
1030
1044
  this.getTranslator = function(url) {
1031
- var keys = Object.keys(this.translators);
1045
+ var keys = Object.keys(roomTranslators);
1032
1046
  for (var i = 0; i < keys.length; i++) {
1033
1047
  var re = new RegExp(keys[i]);
1034
1048
  if (url.match(re)) {
1035
- return this.translators[keys[i]];
1049
+ return roomTranslators[keys[i]];
1036
1050
  }
1037
1051
  }
1038
1052
  // TODO - implement default page handling as translator
@@ -1758,10 +1772,12 @@ elation.require([
1758
1772
  this.pendingassets.splice(idx, 1);
1759
1773
  if (this.pendingassets.length == 0) {
1760
1774
  this.applyingEdits = false;
1761
- setTimeout(elation.bind(this, function() {
1762
- this.completed = true;
1763
- elation.events.fire({element: this, type: 'room_load_complete'});
1764
- }), 0);
1775
+ if (!this.completed) {
1776
+ setTimeout(elation.bind(this, function() {
1777
+ this.completed = true;
1778
+ elation.events.fire({element: this, type: 'room_load_complete'});
1779
+ }), 0);
1780
+ }
1765
1781
  }
1766
1782
  }
1767
1783
  }
@@ -1882,6 +1898,10 @@ elation.require([
1882
1898
  }
1883
1899
  }
1884
1900
  */
1901
+ // FIXME - hack to disable XR rendering while room is still loading. this can be handled better.
1902
+ if (this.engine.systems.render.views.xr && this.engine.systems.render.renderer.xr.isPresenting) {
1903
+ this.engine.systems.render.views.xr.enabled = this.completed;
1904
+ }
1885
1905
  this.janus.scriptframeargs[0] = ev.data.delta * 1000;
1886
1906
  elation.events.fire({element: this, type: 'janusweb_script_frame', data: ev.data.delta});
1887
1907
  elation.events.fire({element: this, type: 'janusweb_script_frame_end', data: ev.data.delta});
@@ -2074,6 +2094,7 @@ elation.require([
2074
2094
  sync: ['property', 'sync'],
2075
2095
  js_id: ['property', 'roomid'],
2076
2096
  pickable: ['property', 'pickable'],
2097
+ audionodes: ['property', 'audionodes'],
2077
2098
 
2078
2099
  skybox: ['property', 'skybox'],
2079
2100
  skybox_intensity: ['property', 'skybox_intensity'],
@@ -2706,12 +2727,13 @@ elation.require([
2706
2727
  }
2707
2728
  this.dispatchEvent = function(event, target) {
2708
2729
  let firedev = elation.events.fire({element: this, target: target || event.target, event: event});
2709
- /*
2710
2730
  if (!event.element) event.element = target || this;
2711
2731
  var handlerfn = 'on' + event.type;
2712
- if (this[handlerfn]) {
2713
- this.executeCallback(this[handlerfn], event);
2732
+ let proxy = this.getProxyObject();
2733
+ if (proxy[handlerfn] && typeof proxy[handlerfn] == 'function') {
2734
+ proxy.executeCallback(proxy[handlerfn], event);
2714
2735
  }
2736
+ /*
2715
2737
  let firedev = elation.events.fire(event);
2716
2738
  let returnValue = true;
2717
2739
  firedev.forEach(e => returnValue &= e.returnValue);
@@ -2721,6 +2743,17 @@ console.log('dispatch to parent', event, this, event.target);
2721
2743
  }
2722
2744
  */
2723
2745
  }
2746
+ this.executeCallback = function(callback, args) {
2747
+ if (callback instanceof Function) {
2748
+ callback(args);
2749
+ } else if (elation.utils.isString(callback)) {
2750
+ (function(fn) {
2751
+ var event = args;
2752
+ return eval(callback);
2753
+ }).call(this.getProxyObject(), callback);
2754
+
2755
+ }
2756
+ }
2724
2757
  this.handleDelayedSound = function(ev) {
2725
2758
  // TODO - implement some visual indicator that this room is trying to play sound but was temporarily blocked
2726
2759
  }
@@ -2802,7 +2835,7 @@ console.log('dispatch to parent', event, this, event.target);
2802
2835
  ctx = this.audionodes.listener.context;
2803
2836
  //gain.gain.setValueAtTime(0, ctx.currentTime);
2804
2837
  gain.gain.cancelScheduledValues(ctx.currentTime);
2805
- gain.gain.linearRampToValueAtTime(0, ctx.currentTime);
2838
+ gain.gain.linearRampToValueAtTime(gain.gain.value, ctx.currentTime);
2806
2839
  gain.gain.linearRampToValueAtTime(value, ctx.currentTime + time);
2807
2840
  }
2808
2841
  }
@@ -2934,6 +2967,19 @@ console.log('unknown material', mat);
2934
2967
  this.updatePointerLock = function() {
2935
2968
  this.engine.systems.controls.pointerLockEnabled = this.pointerlock;
2936
2969
  }
2970
+ this.handleVisibilityChange = function(ev) {
2971
+ if (this.audionodes) {
2972
+ if (document.visibilityState == 'visible') {
2973
+ if (this.audioFadeTimer) clearTimeout(this.audioFadeTimer);
2974
+ if (this.audionodes.gain.gain.value < 1) {
2975
+ this.fadeAudioIn(1);
2976
+ }
2977
+ } else {
2978
+ if (this.audioFadeTimer) clearTimeout(this.audioFadeTimer);
2979
+ this.audioFadeTimer = setTimeout(() => this.fadeAudioOut(10), 10000);
2980
+ }
2981
+ }
2982
+ }
2937
2983
  }, elation.engine.things.generic);
2938
2984
  });
2939
2985
 
package/scripts/text.js CHANGED
@@ -2,7 +2,6 @@ elation.require(['engine.things.label'], function() {
2
2
  elation.component.add('engine.things.janustext', function() {
3
3
  this.postinit = function() {
4
4
  elation.engine.things.janustext.extendclass.postinit.call(this);
5
- this.frameupdates = [];
6
5
  this.textcache = this.engine.getScratchObject('textcache');
7
6
  this.defineProperties({
8
7
  'text': { type: 'string', default: '', refreshGeometry: true },
@@ -30,7 +29,6 @@ elation.require(['engine.things.label'], function() {
30
29
  'wireframe': { type: 'boolean', default: false, set: this.updateMaterial, comment: 'Wireframe rendering' },
31
30
  });
32
31
  this.emptygeometry = new THREE.BufferGeometry();
33
- elation.events.add(this.engine, 'engine_frame', elation.bind(this, this.handleFrameUpdates));
34
32
  }
35
33
  this.createObject3D = function() {
36
34
  this.objects['3d'] = new THREE.Object3D();