janusweb 1.5.42 → 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.
Files changed (34) hide show
  1. package/CHANGELOG +23 -0
  2. package/css/janusweb.css +7 -2
  3. package/media/assets/webui/apps/buttons/buttons.js +17 -3
  4. package/media/assets/webui/apps/comms/comms.css +1 -1
  5. package/media/assets/webui/apps/comms/comms.js +1 -1
  6. package/media/assets/webui/apps/comms/voip.css +12 -3
  7. package/media/assets/webui/apps/comms/voip.js +16 -6
  8. package/media/assets/webui/apps/editor/editor.css +1 -0
  9. package/media/assets/webui/apps/editor/editor.js +19 -12
  10. package/media/assets/webui/apps/locomotion/teleporter.js +11 -4
  11. package/media/assets/webui/apps/xrmenu/images/audio-settings.png +0 -0
  12. package/media/assets/webui/apps/xrmenu/xrmenu-assets.json +2 -1
  13. package/media/assets/webui/apps/xrmenu/xrmenu.js +142 -40
  14. package/media/assets/webui/themes/default.css +42 -0
  15. package/package.json +2 -2
  16. package/scripts/client.js +12 -1
  17. package/scripts/config.js +1 -1
  18. package/scripts/elements/outliner.js +7 -1
  19. package/scripts/external/JanusClientConnection.js +14 -8
  20. package/scripts/image.js +1 -1
  21. package/scripts/janusbase.js +49 -27
  22. package/scripts/janusghost.js +14 -10
  23. package/scripts/januslight.js +46 -4
  24. package/scripts/janusparticle.js +116 -13
  25. package/scripts/janusplayer.js +97 -22
  26. package/scripts/janusweb.js +18 -5
  27. package/scripts/janusxrplayer.js +117 -17
  28. package/scripts/object.js +75 -31
  29. package/scripts/parts.js +1 -1
  30. package/scripts/portal.js +21 -10
  31. package/scripts/remoteplayer.js +3 -2
  32. package/scripts/room.js +159 -49
  33. package/scripts/text.js +7 -4
  34. package/scripts/websurface.js +3 -3
@@ -285,7 +285,7 @@ elation.require(['janusweb.janusbase'], function() {
285
285
  this.emitted = 0;
286
286
  }
287
287
  this.updateParticles = function(ev) {
288
- if (!this.loaded || !this.started || !this.parent) return;
288
+ if (!this.loaded || !this.started || !this.parent || !this.visible) return;
289
289
  var now = performance.now(),
290
290
  elapsed = now - this.lasttime,
291
291
  endtime = now + this.duration * 1000,
@@ -553,9 +553,10 @@ elation.require(['janusweb.janusbase'], function() {
553
553
 
554
554
  point.active = 1;
555
555
 
556
- var pos = this.geometry.attributes.position.array,
557
- color = this.geometry.attributes.customColor.array,
558
- size = this.geometry.attributes.size.array;
556
+ var geo = this.geometry,
557
+ pos = geo.attributes.position.array,
558
+ color = geo.attributes.customColor.array,
559
+ size = geo.attributes.size.array;
559
560
 
560
561
  if (newpos) {
561
562
  point.pos.copy(newpos);
@@ -564,8 +565,14 @@ elation.require(['janusweb.janusbase'], function() {
564
565
  pos[offset + 1] = newpos.y;
565
566
  pos[offset + 2] = newpos.z;
566
567
 
567
- this.geometry.attributes.position.needsUpdate = true;
568
- this.updateBoundingSphere(newpos);
568
+ geo.attributes.position.needsUpdate = true;
569
+ //this.updateBoundingSphere(newpos);
570
+ if (!this.updateBoundingSphereTimer) {
571
+ this.updateBoundingSphereTimer = setTimeout(() => {
572
+ this.updateBoundingSphere(newpos);
573
+ this.updateBoundingSphereTimer = false;
574
+ }, 0);
575
+ }
569
576
  }
570
577
 
571
578
  if (newvel) {
@@ -582,23 +589,119 @@ elation.require(['janusweb.janusbase'], function() {
582
589
  color[pointnum*4 ] = newcol.x;
583
590
  color[pointnum*4 + 1] = newcol.y;
584
591
  color[pointnum*4 + 2] = newcol.z;
585
- color[pointnum*4 + 3] = elation.utils.any(point.opacity, this.opacity, 1);
592
+ color[pointnum*4 + 3] = elation.utils.any(point.opacity, this.properties.opacity, 1);
586
593
 
587
- this.geometry.attributes.customColor.needsUpdate = true;
594
+ geo.attributes.customColor.needsUpdate = true;
588
595
  }
589
596
  if (newsize) {
590
597
  point.size = newsize;
591
598
  size[pointnum] = newsize;
592
599
 
593
- this.geometry.attributes.size.needsUpdate = true;
600
+ geo.attributes.size.needsUpdate = true;
594
601
  }
595
602
  point.opacity = newopacity;
596
603
 
597
- if (pointnum >= this.count) {
598
- this.count = this.particles.length;
599
- this.createParticles(false);
600
- this.updateParticles();
604
+ if (pointnum >= this.properties.count) {
605
+ if (!this.updateParticleTimer) {
606
+ this.updateParticleTimer = setTimeout(() => {
607
+ this.count = this.particles.length;
608
+ this.createParticles(false);
609
+ this.updateParticleTimer = false;
610
+ }, 0);
611
+ }
601
612
  }
602
613
  }
614
+ this.setPoints = (function() {
615
+ let furthest = new THREE.Vector3();
616
+ return function(points) {
617
+ var geo = this.geometry,
618
+ pos = geo.attributes.position.array,
619
+ color = geo.attributes.customColor.array,
620
+ size = geo.attributes.size.array;
621
+ furthestDistSq = 0,
622
+ particles = this.particles;
623
+ for (let i = 0; i < points.length; i++) {
624
+ let point = particles[i],
625
+ newpoint = points[i],
626
+ offset = i * 3;
627
+
628
+ if (!point) {
629
+ point = this.createPoint();
630
+ point.active = 1;
631
+ particles[i] = point;
632
+ }
633
+
634
+ point.active = 1;
635
+
636
+ if ('pos' in newpoint) {
637
+ //point.pos.copy(newpoint.pos);
638
+ let p1 = point.pos,
639
+ p2 = newpoint.pos;
640
+ pos[offset ] = p1.x = p2.x;
641
+ pos[offset + 1] = p1.y = p2.y;
642
+ pos[offset + 2] = p1.z = p2.z;
643
+
644
+ /*
645
+ point.pos.copy(newpoint.pos);
646
+ pos[offset ] = point.pos.x;
647
+ pos[offset + 1] = point.pos.y;
648
+ pos[offset + 2] = point.pos.z;
649
+ */
650
+
651
+ //this.updateBoundingSphere(newpos);
652
+ let distSq = p2.x * p2.x + p2.y * p2.y + p2.z * p2.z;
653
+ if (distSq > furthestDistSq) {
654
+ furthest.x = newpoint.pos.x;
655
+ furthest.y = newpoint.pos.y;
656
+ furthest.z = newpoint.pos.z;
657
+ furthestDistSq = distSq;
658
+ }
659
+ }
660
+
661
+ if ('vel' in newpoint) {
662
+ //point.vel.copy(newpoint.vel);
663
+ point.vel.x = newpoint.vel.x;
664
+ point.vel.y = newpoint.vel.y;
665
+ point.vel.z = newpoint.vel.z;
666
+ }
667
+
668
+ if ('accel' in newpoint) {
669
+ //point.accel.copy(newpoint.accel);
670
+ point.accel.x = newpoint.accel.x;
671
+ point.accel.y = newpoint.accel.y;
672
+ point.accel.z = newpoint.accel.z;
673
+ }
674
+
675
+ if ('opacity' in newpoint) {
676
+ point.opacity = newpoint.opacity;
677
+ }
678
+
679
+
680
+ if ('col' in newpoint) {
681
+ point.color.setRGB(newpoint.col.x, newpoint.col.y, newpoint.col.z);
682
+
683
+ color[i*4 ] = newpoint.col.x;
684
+ color[i*4 + 1] = newpoint.col.y;
685
+ color[i*4 + 2] = newpoint.col.z;
686
+ color[i*4 + 3] = elation.utils.any(point.opacity, this.properties.opacity, 1);
687
+
688
+ geo.attributes.customColor.needsUpdate = true;
689
+ }
690
+ if ('size' in newpoint) {
691
+ point.size = newpoint.size;
692
+ size[i] = newpoint.size;
693
+
694
+ geo.attributes.size.needsUpdate = true;
695
+ }
696
+ }
697
+ geo.attributes.position.needsUpdate = true;
698
+ this.updateBoundingSphere(furthest);
699
+ if (points.length >= this.properties.count) {
700
+ this.count = particles.length;
701
+ this.createParticles(false);
702
+ this.updateParticleTimer = false;
703
+ }
704
+ }
705
+ })();
603
706
  }, elation.engine.things.janusbase);
604
707
  });
@@ -3,6 +3,7 @@ elation.require(['engine.things.player', 'janusweb.external.JanusVOIP', 'ui.butt
3
3
 
4
4
  elation.component.add('engine.things.janusplayer', function() {
5
5
  //this.defaultavatar = '<FireBoxRoom>\n <Assets>\n <AssetObject id="screen" src="https://web.janusxr.org/media/assets/hoverscreen.obj" mtl="https://web.janusxr.org/media/assets/hoverscreen.mtl" />\n </Assets>\n <Room>\n <Ghost id="januswebuser" col="#ffffff" lighting="true" head_pos="0 1.4 0" body_id="" eye_pos="0 1.6 0" userid_pos="0 0.5 0" cull_face="back" screen_name="screen_Cube.004">\n <Object id="screen" js_id="head" />\n </Ghost>\n </Room>\n</FireBoxRoom>'
6
+ //this.defaultavatar = '<FireBoxRoom>\n<Assets>\n<AssetObject id="screen" src="https://vesta.janusxr.org/avatars/static/janusweb/janusweb.obj.gz" mtl="https://vesta.janusxr.org/user_avatar/12689/janusweb.mtl" /></Assets>\n<Room>\n<Ghost id="januswebuser" head_id="screen" head_pos="0 1.4 0" body_id="" eye_pos="0 1.6 0" userid_pos="0 0.5 0" cull_face="back" />\n</Room>\n</FireBoxRoom>';
6
7
  this.defaultavatar = `
7
8
  <FireBoxRoom>
8
9
  <assets>
@@ -35,6 +36,8 @@ elation.require(['engine.things.player', 'janusweb.external.JanusVOIP', 'ui.butt
35
36
  party_mode: { type: 'boolean', set: this.updatePartyMode },
36
37
  avatarsrc: { type: 'string' },
37
38
  cameraview: { type: 'string', default: 'firstperson' },
39
+ camerazoom: { type: 'float', default: 0 },
40
+ cameraangle: { type: 'float', default: 0 },
38
41
  decouplehead: { type: 'boolean', default: false },
39
42
  });
40
43
 
@@ -48,11 +51,12 @@ elation.require(['engine.things.player', 'janusweb.external.JanusVOIP', 'ui.butt
48
51
  elation.events.add(this.engine.client.view.container, 'touchstart', elation.bind(this, this.handleTouchStart));
49
52
  elation.events.add(this.engine.client.view.container, 'touchmove', elation.bind(this, this.handleTouchMove));
50
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));
51
55
 
52
56
  this.controlstate2 = this.engine.systems.controls.addContext('janusplayer', {
53
- 'toggle_view': ['keyboard_v,keyboard_shift_v', elation.bind(this, this.toggleCamera)],
54
- 'zoom_out': ['mouse_wheel_down', ev => this.zoomView(-1)],
55
- 'zoom_in': ['mouse_wheel_up', ev => this.zoomView(1)],
57
+ 'toggle_view': ['keyboard_nomod_v,keyboard_shift_v', elation.bind(this, this.toggleCamera)],
58
+ 'zoom_out': ['mouse_wheel_down', ev => this.zoomView(-1, ev)],
59
+ 'zoom_in': ['mouse_wheel_up', ev => this.zoomView(1, ev)],
56
60
  //'browse_back': ['gamepad_any_button_4', elation.bind(this, this.browseBack)],
57
61
  //'browse_forward': ['gamepad_any_button_5', elation.bind(this, this.browseForward)],
58
62
  });
@@ -101,6 +105,17 @@ elation.require(['engine.things.player', 'janusweb.external.JanusVOIP', 'ui.butt
101
105
  this.cursor_style = 'default';
102
106
  this.cursor_object = '';
103
107
  this.lookat_object = '';
108
+ window.addEventListener('blur', ev => {
109
+ if (document.pointerLockElement && document.activeElement instanceof HTMLIFrameElement) {
110
+ document.pointerLockElement.focus();
111
+ //this.disable();
112
+ this.engine.systems.controls.deactivateContext('janusplayer');
113
+ this.engine.systems.controls.activateContext('janusplayer');
114
+ let click = new MouseEvent('click', { });
115
+ document.body.dispatchEvent(click);
116
+ //setTimeout(() => this.enable(), 100);
117
+ }
118
+ });
104
119
 
105
120
  if (this.usevoip) {
106
121
  this.voip = new JanusVOIPRecorder({audioScale: 1024});
@@ -400,7 +415,7 @@ elation.require(['engine.things.player', 'janusweb.external.JanusVOIP', 'ui.butt
400
415
  }
401
416
  if (this.controlstate.jump && !this.jumping) {
402
417
  let jumptime = 1;
403
- if (this.ghost && this.ghost.body.animations && this.ghost.body.animations.jump) {
418
+ if (this.ghost && this.ghost.body && this.ghost.body.animations && this.ghost.body.animations.jump) {
404
419
  let jumpanim = this.ghost.body.animations.jump;
405
420
  let jumpclip = jumpanim.getClip();
406
421
 
@@ -542,8 +557,34 @@ elation.require(['engine.things.player', 'janusweb.external.JanusVOIP', 'ui.butt
542
557
  }
543
558
  }
544
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});
545
574
  }
546
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
+ }
547
588
  }
548
589
  this.getProxyObject = function() {
549
590
  if (!this._proxyobject) {
@@ -846,11 +887,18 @@ elation.require(['engine.things.player', 'janusweb.external.JanusVOIP', 'ui.butt
846
887
  if (proxyobj) {
847
888
  //var realobj = this.room.getObjectFromProxy(proxyobj);
848
889
  if (proxyobj.parent) {
849
- proxyobj.parent.removeChild(proxyobj);
890
+ if (typeof proxyobj.parent.removeChild == 'function') {
891
+ proxyobj.parent.removeChild(proxyobj);
892
+ } else if (typeof proxyobj.parent.remove == 'function') {
893
+ proxyobj.parent.remove(proxyobj._target);
894
+ }
850
895
  }
851
896
  var realobj = proxyobj._target;
852
897
  if (realobj) {
853
898
  this.add(realobj);
899
+ if (typeof realobj.start == 'function') {
900
+ realobj.start();
901
+ }
854
902
  }
855
903
  }
856
904
  }
@@ -863,6 +911,9 @@ elation.require(['engine.things.player', 'janusweb.external.JanusVOIP', 'ui.butt
863
911
  //var realobj = this.room.getObjectFromProxy(proxyobj);
864
912
  var realobj = proxyobj._target;
865
913
  if (realobj) {
914
+ if (typeof realobj.stop == 'function') {
915
+ realobj.stop();
916
+ }
866
917
  this.remove(realobj);
867
918
  }
868
919
  }
@@ -874,6 +925,7 @@ elation.require(['engine.things.player', 'janusweb.external.JanusVOIP', 'ui.butt
874
925
  this.setCollider('sphere', {
875
926
  radius: this.collision_radius,
876
927
  });
928
+ this.collidable = false;
877
929
  */
878
930
  this.pickable = false;
879
931
  this.setCollider('capsule', {
@@ -951,6 +1003,7 @@ elation.require(['engine.things.player', 'janusweb.external.JanusVOIP', 'ui.butt
951
1003
  }
952
1004
  }
953
1005
  this.handleTouchStart = function(ev) {
1006
+ //if (!this.enabled) return;
954
1007
  let halfscreenwidth = window.innerWidth / 2;
955
1008
  this.enabled = true;
956
1009
  for (let i = 0; i < ev.changedTouches.length; i++) {
@@ -963,8 +1016,9 @@ elation.require(['engine.things.player', 'janusweb.external.JanusVOIP', 'ui.butt
963
1016
  }
964
1017
  }
965
1018
  if (!document.fullscreenElement) {
966
- //this.engine.client.toggleFullscreen({data: 1});
1019
+ this.engine.client.toggleFullscreen({data: 1});
967
1020
  }
1021
+ this.cancelTouchMovement(ev);
968
1022
  }
969
1023
  this.handleTouchMove = function(ev) {
970
1024
  if (ev.defaultPrevented) return;
@@ -1000,22 +1054,22 @@ elation.require(['engine.things.player', 'janusweb.external.JanusVOIP', 'ui.butt
1000
1054
  this.touchcache.positions[touch.identifier][0] = touch.clientX;
1001
1055
  this.touchcache.positions[touch.identifier][1] = touch.clientY;
1002
1056
  }
1003
-
1004
1057
  }
1058
+ this.cancelTouchMovement(ev);
1005
1059
  }
1006
1060
  this.handleTouchEnd = function(ev) {
1007
- for (let i = 0; i < ev.changedTouches.length; i++) {
1008
- 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];
1009
1066
  if (touch.identifier === this.touchindex[0]) {
1010
- this.controlstate.move_right = 0;
1011
- this.controlstate.move_forward = 0;
1012
- this.touchindex[0] = null;
1013
- } else if (touch.identifier === this.touchindex[1]) {
1014
- this.controlstate.turn_right = 0;
1015
- this.controlstate.look_down = 0;
1016
- this.touchindex[1] = null;
1067
+ return;
1017
1068
  }
1018
1069
  }
1070
+ this.controlstate.move_right = 0;
1071
+ this.controlstate.move_forward = 0;
1072
+ this.touchindex[0] = null;
1019
1073
  }
1020
1074
  this.updatePartyMode = function(key, value) {
1021
1075
  if (typeof value != 'undefined') {
@@ -1112,8 +1166,10 @@ elation.require(['engine.things.player', 'janusweb.external.JanusVOIP', 'ui.butt
1112
1166
  elapsed = now - this.lookAtLERPstart,
1113
1167
  n = Math.min(1, Math.max(0, elapsed / this.lookAtLERPtime));
1114
1168
 
1115
- THREE.Quaternion.slerp(this.lookAtLERPq1body, this.lookAtLERPq2body, this.orientation, n);
1116
- THREE.Quaternion.slerp(this.lookAtLERPq1head, this.lookAtLERPq2head, this.head.orientation, n);
1169
+ //THREE.Quaternion.slerp(this.lookAtLERPq1body, this.lookAtLERPq2body, this.orientation, n);
1170
+ //THREE.Quaternion.slerp(this.lookAtLERPq1head, this.lookAtLERPq2head, this.head.orientation, n);
1171
+ this.orientation.slerpQuaternions(this.lookAtLERPq1body, this.lookAtLERPq2body, n);
1172
+ this.head.orientation.slerpQuaternions(this.lookAtLERPq1head, this.lookAtLERPq2head, n);
1117
1173
  if (n == 1) {
1118
1174
  this.lookAtLERPtime = 0;
1119
1175
  }
@@ -1136,16 +1192,35 @@ elation.require(['engine.things.player', 'janusweb.external.JanusVOIP', 'ui.butt
1136
1192
  if (ev.value == 1) {
1137
1193
  if (this.cameraview == 'firstperson') {
1138
1194
  this.cameraview = 'thirdperson';
1139
- this.camera.position.z = 2;
1195
+ this.cameraangle = 0;
1196
+ this.camerazoom = 2;
1140
1197
  } else {
1141
1198
  this.cameraview = 'firstperson';
1142
- this.camera.position.z = 0;
1199
+ this.cameraangle = 0;
1200
+ this.camerazoom = 0;
1143
1201
  }
1202
+ this.updateCamera();
1144
1203
  }
1145
1204
  }
1146
- this.zoomView = function(amount) {
1205
+ this.zoomView = function(amount, ev) {
1147
1206
  if (this.cameraview == 'thirdperson') {
1148
- this.camera.position.z -= amount / 10;
1207
+ //this.camera.position.z -= amount / 10;
1208
+ //this.camera.position.z = Math.max(0.001, this.camera.position.z * (amount > 0 ? .95 : 1.05));
1209
+ let state = this.engine.systems.controls.state;
1210
+ if (state.keyboard_alt) {
1211
+ this.cameraangle += amount * Math.PI / 64;
1212
+ } else {
1213
+ this.camerazoom = Math.max(0.001, this.camerazoom * (amount > 0 ? .95 : 1.05));
1214
+ }
1215
+ this.updateCamera();
1216
+ }
1217
+ }
1218
+ this.updateCamera = function() {
1219
+ if (this.camera) {
1220
+ this.camera.fov = this.fov;
1221
+ this.camera.position.z = Math.cos(this.cameraangle) * this.camerazoom;
1222
+ this.camera.position.x = Math.sin(this.cameraangle) * this.camerazoom;
1223
+ this.camera.orientation.setFromEuler(new THREE.Euler(0, this.cameraangle, 0));
1149
1224
  }
1150
1225
  }
1151
1226
  this.setAnimationSequence = function(sequence) {
@@ -90,7 +90,7 @@ elation.require([
90
90
  this.engine.systems.controls.addContext('janus', {
91
91
  //'load_url': [ 'keyboard_tab', elation.bind(this, this.showLoadURL) ],
92
92
  'toggle_menu': [ 'keyboard_esc', elation.bind(this, this.toggleMenu) ],
93
- 'room_debug': [ 'keyboard_f6', elation.bind(this, this.showRoomDebug) ],
93
+ //'room_debug': [ 'keyboard_f6', elation.bind(this, this.showRoomDebug) ],
94
94
  'chat': [ 'keyboard_t', elation.bind(this, this.showChat) ],
95
95
  'bookmark': [ 'keyboard_ctrl_b', elation.bind(this, this.addBookmark) ],
96
96
  'mute': [ 'keyboard_ctrl_m', elation.bind(this, this.mute) ]
@@ -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
 
@@ -265,6 +265,10 @@ elation.require(['engine.things.generic', 'janusweb.external.webxr-input-profile
265
265
  pos: menupos,
266
266
  rotation: menurot,
267
267
  });
268
+ this.menupos = menupos;
269
+ this.menurot = menurot;
270
+ this.removeChild(this.menu);
271
+
268
272
  player.setHand(this.device.handedness, this.virtualskeleton);
269
273
  },
270
274
  updateDevice(device) {
@@ -390,10 +394,34 @@ elation.require(['engine.things.generic', 'janusweb.external.webxr-input-profile
390
394
  this.updateMotionControllerModel(this.motionController);
391
395
  }
392
396
  }
393
- if (this.pointer && raypose) {
394
- this.pointer.pos.copy(raypose.transform.position);
395
- this.pointer.orientation.copy(raypose.transform.orientation);
396
- this.pointer.updateCursorOpacity();
397
+ if (this.pointer) {
398
+ if (raypose) {
399
+ this.pointer.pos.copy(raypose.transform.position);
400
+ this.pointer.orientation.copy(raypose.transform.orientation);
401
+ this.pointer.updateCursorOpacity();
402
+ this.pointer.visible = this.visible && this.opacity > 0;
403
+ } else {
404
+ this.pointer.visible = false;
405
+ }
406
+ }
407
+ if (this.gamepad && this.gamepad.buttons && this.gamepad.buttons[4]) {
408
+ let button = this.gamepad.buttons[4];
409
+ if (button.pressed) {
410
+ this.buttonwaspressed = true;
411
+ } else if (this.buttonwaspressed && !button.pressed) {
412
+ this.buttonwaspressed = false;
413
+ if (!this.menu.parent || this.menu.parent === this) {
414
+ player.appendChild(this.menu);
415
+ player.worldToLocal(this.pointer.localToWorld(this.menu.pos.set(0,0,-.25)));
416
+ this.menu.billboard = 'y';
417
+ } else {
418
+ //this.appendChild(this.menu);
419
+ player.removeChild(this.menu);
420
+ this.menu.billboard = '';
421
+ this.menu.pos.copy(this.menupos);
422
+ //this.menu.visible = false;
423
+ }
424
+ }
397
425
  }
398
426
  },
399
427
  createButtons() {
@@ -542,7 +570,7 @@ elation.require(['engine.things.generic', 'janusweb.external.webxr-input-profile
542
570
  create() {
543
571
  this.lasercolor = V(1,0,0);
544
572
  this.laser = this.createObject('linesegments', {
545
- positions: [V(0,0,0), V(0,0,-.5)],
573
+ positions: [V(0,0,0), V(0,0,-5)],
546
574
  opacity: .8,
547
575
  col: this.lasercolor,
548
576
  visible: false,
@@ -552,7 +580,7 @@ elation.require(['engine.things.generic', 'janusweb.external.webxr-input-profile
552
580
  id: 'cylinder',
553
581
  col: 'white',
554
582
  lighting: false,
555
- scale: V(.005, .5, .005),
583
+ scale: V(.005, 5, .005),
556
584
  rotation: V(-90,0,0),
557
585
  opacity: .2,
558
586
  });
@@ -587,6 +615,7 @@ elation.require(['engine.things.generic', 'janusweb.external.webxr-input-profile
587
615
  //this.cursor.zdir.copy(player.view_dir).multiplyScalar(-1);
588
616
  //this.cursor.zdir = normal;
589
617
  this.cursor.visible = true;
618
+ this.cursor.opacity = .8 * player.cursor_opacity;
590
619
  },
591
620
  updateCursorOpacity() {
592
621
  if (!this.activeobject) return;
@@ -605,6 +634,8 @@ elation.require(['engine.things.generic', 'janusweb.external.webxr-input-profile
605
634
  this.laser.updateColor();
606
635
  this.cursor.image_id = 'cursor_dot_active';
607
636
  this.cursor.opacity = player.cursor_opacity;
637
+ this.bonk.col.setRGB(.5,1,.5);
638
+ this.bonk.opacity = 0.2 * player.cursor_opacity;
608
639
  //this.laser.visible = false; // FIXME - hack to disable laser without breaking things
609
640
 
610
641
  /*
@@ -620,6 +651,7 @@ elation.require(['engine.things.generic', 'janusweb.external.webxr-input-profile
620
651
  this.laser.updateColor();
621
652
  this.cursor.image_id = 'cursor_dot_inactive';
622
653
  this.cursor.opacity = player.cursor_opacity / 2;
654
+ this.bonk.col.setRGB(1,1,1);
623
655
  //this.laser.visible = false; // FIXME - hack to disable laser without breaking things
624
656
  }
625
657
  },
@@ -769,6 +801,34 @@ elation.require(['engine.things.generic', 'janusweb.external.webxr-input-profile
769
801
  fingernames: ['THUMB', 'INDEX', 'MIDDLE', 'RING', 'LITTLE'],
770
802
  phalanxnames: ['METACARPAL', 'PHALANX_PROXIMAL', 'PHALANX_DISTAL', 'PHALANX_TIP'],
771
803
 
804
+ jointnames: [
805
+ 'wrist',
806
+ 'thumb-metacarpal',
807
+ 'thumb-phalanx-proximal',
808
+ 'thumb-phalanx-distal',
809
+ 'thumb-tip',
810
+ 'index-finger-metacarpal',
811
+ 'index-finger-phalanx-proximal',
812
+ 'index-finger-phalanx-intermediate',
813
+ 'index-finger-phalanx-distal',
814
+ 'index-finger-tip',
815
+ 'middle-finger-metacarpal',
816
+ 'middle-finger-phalanx-proximal',
817
+ 'middle-finger-phalanx-intermediate',
818
+ 'middle-finger-phalanx-distal',
819
+ 'middle-finger-tip',
820
+ 'ring-finger-metacarpal',
821
+ 'ring-finger-phalanx-proximal',
822
+ 'ring-finger-phalanx-intermediate',
823
+ 'ring-finger-phalanx-distal',
824
+ 'ring-finger-tip',
825
+ 'pinky-finger-metacarpal',
826
+ 'pinky-finger-phalanx-proximal',
827
+ 'pinky-finger-phalanx-intermediate',
828
+ 'pinky-finger-phalanx-distal',
829
+ 'pinky-finger-tip',
830
+ ],
831
+
772
832
  isactive: true,
773
833
  handpos: null,
774
834
  p0: null,
@@ -781,11 +841,24 @@ elation.require(['engine.things.generic', 'janusweb.external.webxr-input-profile
781
841
  this.handmodel = this.parent.createObject('object', {
782
842
  id: 'cube',
783
843
  scale: V(.075, .025, .075),
784
- col: 'green'
844
+ col: 'green',
845
+ visible: false
785
846
  });
786
847
  this.tmpobj = new THREE.Object3D();
787
- this.joints = new THREE.InstancedMesh(new THREE.SphereBufferGeometry(1), new THREE.MeshPhysicalMaterial({color: 0xccffcc, metalness: .2, roughness: .5}), 26);
848
+ this.tmpquat = new THREE.Quaternion();
849
+ this.jointmaterial = new THREE.MeshPhysicalMaterial({color: 0xccffcc, metalness: 1, roughness: .5, emissive: 0xccffcc, transparent: true});
850
+ this.tmpobj.matrixAutoUpdate = false;
851
+ this.joints = new THREE.InstancedMesh(new THREE.SphereGeometry(1), this.jointmaterial, 26);
852
+ this.joints.frustumCulled = false;
788
853
  this.joints.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
854
+ let tmpobj = this.tmpobj;
855
+ for (let i = 0; i < 26; i++) {
856
+ tmpobj.position.set(Math.random(), Math.random(), Math.random());
857
+ tmpobj.scale.set(.0001, .0001, .0001);
858
+ tmpobj.updateMatrix();
859
+ this.joints.setMatrixAt(i, tmpobj.matrix);
860
+ }
861
+
789
862
  this.jointposes = {};
790
863
  this.objects['3d'].add(this.joints);
791
864
  this.handpos = new THREE.Vector3(0, 0, 0);
@@ -796,11 +869,14 @@ elation.require(['engine.things.generic', 'janusweb.external.webxr-input-profile
796
869
  this.p4 = new THREE.Vector3(0, 0, 0);
797
870
  },
798
871
  updatePose(xrFrame, xrReferenceFrame) {
799
- if (!this.hand || !this.joints || !this.hand[0]) return;
872
+ if (!this.hand || !this.joints || !this.tmpobj) {
873
+ return;
874
+ }
800
875
 
801
- let tmpobj = this.tmpobj,
876
+ let tmpobj = this.tmpobj, tmpquat = this.tmpquat,
802
877
  i = 0;
803
878
  let poses = this.jointposes;
879
+ /*
804
880
  let wristpose = xrFrame.getJointPose(this.hand[XRHand['WRIST']], xrReferenceFrame);
805
881
  this.jointposes['WRIST'] = wristpose;
806
882
  for (let fingernum = 0; fingernum < this.fingernames.length; fingernum++) {
@@ -820,15 +896,39 @@ elation.require(['engine.things.generic', 'janusweb.external.webxr-input-profile
820
896
  this.jointposes[jointname] = jointpose;
821
897
  }
822
898
  }
899
+ */
900
+ const handvalues = this.hand.values(), jointposes = this.jointposes;
901
+ for ( const inputjoint of handvalues ) {
902
+ const jointpose = xrFrame.getJointPose( inputjoint, xrReferenceFrame );
903
+ const jointname = inputjoint.jointName;
904
+ if (jointpose && jointpose.transform) {
905
+ let radius = Math.max(.002, jointpose.radius);
906
+ /*
907
+ tmpobj.position.copy(jointpose.transform.position);
908
+ tmpobj.quaternion.copy(jointpose.transform.orientation);
909
+ tmpobj.scale.set(radius, radius, radius);
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)
915
+ this.joints.setMatrixAt(i, tmpobj.matrix);
916
+ //FIVARSlog('xr.debug', 'update joint: ' + i + ', ' + jointname + ', ' + tmpobj.matrix.elements.join(', '));
917
+ }
918
+ i++;
919
+ jointposes[jointname] = jointpose;
920
+ }
823
921
  this.joints.instanceMatrix.needsUpdate = true;
824
-
825
- if (this.jointposes['WRIST']) this.localToWorld(this.handpos.copy(this.jointposes['WRIST'].transform.position));
826
- if (this.jointposes['THUMB_PHALANX_TIP']) this.localToWorld(this.p0.copy(this.jointposes['THUMB_PHALANX_TIP'].transform.position));
827
- if (this.jointposes['INDEX_PHALANX_TIP']) this.localToWorld(this.p1.copy(this.jointposes['INDEX_PHALANX_TIP'].transform.position));
828
- if (this.jointposes['MIDDLE_PHALANX_TIP']) this.localToWorld(this.p2.copy(this.jointposes['MIDDLE_PHALANX_TIP'].transform.position));
829
- if (this.jointposes['RING_PHALANX_TIP']) this.localToWorld(this.p3.copy(this.jointposes['RING_PHALANX_TIP'].transform.position));
830
- if (this.jointposes['LITTLE_PHALANX_TIP']) this.localToWorld(this.p4.copy(this.jointposes['LITTLE_PHALANX_TIP'].transform.position));
922
+ //this.joints.computeBoundingSphere();
923
+
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));
831
930
  this.isactive = true;
931
+ this.jointmaterial.opacity = player.cursor_opacity;
832
932
  }
833
933
  });
834
934
  janus.registerElement('trackedplayer_hand_virtualskeleton', {