common.js 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /* Decode the query variable */
  2. function parseQuery(url) {
  3. var vars = (url || window.location.search).substring(1).split("&");
  4. var query = {};
  5. for (var i=0;i<vars.length;i++) {
  6. var pair = vars[i].split("=");
  7. query[pair[0]] = pair[1];
  8. }
  9. return query;
  10. }
  11. /* Dynamically load a css or js object
  12. *
  13. * Examples:
  14. * loadResource("myscript.js")
  15. * loadResource("mystyle.css")
  16. *
  17. * Reference:
  18. * http://www.javascriptkit.com/javatutors/loadjavascriptcss.shtml
  19. */
  20. function loadResource(filename, async, onLoadFunc){
  21. if (endsWith(filename, ".js") || endsWith(filename, ".js.gz")){
  22. //if filename is a external JavaScript file
  23. var fileref = document.createElement('script')
  24. fileref.setAttribute("type","text/javascript")
  25. fileref.setAttribute("src", filename)
  26. if(async == "defer") {
  27. fileref.setAttribute("defer", "defer");
  28. } else if(async) {
  29. fileref.setAttribute("async", "async");
  30. }
  31. } else if (endsWith(filename, ".css") || endsWith(filename, ".css.gz")) {
  32. //if filename is an external CSS file
  33. var fileref = document.createElement("link")
  34. fileref.setAttribute("rel", "stylesheet")
  35. fileref.setAttribute("type", "text/css")
  36. fileref.setAttribute("href", filename)
  37. } else if (endsWith(filename, ".html") || endsWith(filename, ".html.gz")) {
  38. //if filename is an external HTML file
  39. var fileref = document.createElement("link")
  40. fileref.setAttribute("rel", "import")
  41. fileref.setAttribute("href", filename)
  42. }
  43. if (typeof fileref != "undefined") {
  44. if (onLoadFunc !== null) {
  45. fileref.onload = onLoadFunc;
  46. }
  47. document.getElementsByTagName("head")[0].appendChild(fileref)
  48. }
  49. }
  50. function endsWith(str, suffix) {
  51. return str.indexOf(suffix, str.length - suffix.length) !== -1;
  52. }
  53. function loadUrl(url, successCallback, errorCallback, responseType) {
  54. var request = new XMLHttpRequest();
  55. request.open('GET', url, true);
  56. if(responseType) {
  57. request.responseType = responseType;
  58. }
  59. request.onload = function() {
  60. if (request.status >= 200 && request.status < 400) {
  61. successCallback(responseType ? request.response : request.responseText);
  62. } else {
  63. if(errorCallback) {
  64. errorCallback(request.status, request.statusText, request);
  65. }
  66. }
  67. }
  68. request.onerror = function() {
  69. if(errorCallback) {
  70. errorCallback(request.status, request.statusText, request);
  71. }
  72. }
  73. request.send();
  74. }
  75. /* THREE.js Utility Functions */
  76. function getTextElement(text, scaleY, color) {
  77. const fontSizePx = 40;
  78. const lineSizePx = 50;
  79. const font = "Bold " + fontSizePx + "px Arial";
  80. var canvas = document.createElement('canvas');
  81. var ctx = canvas.getContext('2d');
  82. var material = new THREE.MeshBasicMaterial( {
  83. map: new THREE.Texture(canvas),
  84. transparent: true
  85. });
  86. function setText(text, color) {
  87. if(!text) {
  88. material.visible = false;
  89. return;
  90. }
  91. const lines = text.split('\n');
  92. const fillStyle = color || "white";
  93. var ctx = canvas.getContext('2d');
  94. ctx.font = font;
  95. ctx.fillStyle = fillStyle;
  96. var maxWidth = 0;
  97. for(var i = 0; i < lines.length; i++) {
  98. const width = ctx.measureText(lines[i]).width;
  99. maxWidth = Math.max(width, maxWidth);
  100. }
  101. canvas.width = maxWidth;
  102. canvas.height = lineSizePx * lines.length;
  103. ctx.font = font;
  104. ctx.fillStyle = fillStyle;
  105. for(var i = 0; i < lines.length; i++) {
  106. ctx.fillText(lines[i], 0, i * lineSizePx + fontSizePx);
  107. }
  108. material.map.needsUpdate = true;
  109. material.visible = true;
  110. }
  111. setText(text, color);
  112. var geometry = new THREE.PlaneBufferGeometry(scaleY * canvas.width/canvas.height, scaleY);
  113. var mesh = new THREE.Mesh(geometry, material);
  114. Object.defineProperty(mesh, 'text', {set: setText});
  115. return mesh;
  116. }
  117. // Returns a reference frame which is centered and aligned with
  118. // the dome.
  119. function domeCentricReferenceFrame(scene) {
  120. var frame = new THREE.Object3D();
  121. frame.rotation.x = -RendererConfig.dome.inclination;
  122. frame.position.y = RendererConfig.camera.startingPosition.y;
  123. scene.add(frame);
  124. return frame;
  125. }
  126. // Returns a reference frame which is appropriate for an outside-in
  127. // viewed spherical display
  128. function sphericalDisplayReferenceFrame(scene) {
  129. var frame = new THREE.Object3D();
  130. frame.rotation.x = -RendererConfig.dome.inclination + Math.PI/2;
  131. frame.position.y = RendererConfig.camera.startingPosition.y;
  132. scene.add(frame);
  133. return frame;
  134. }
  135. // Returns a quaternion that can be used to rotate a object in
  136. // the sphericalDisplayReferenceFrame so it moves correctly
  137. function getSphericalDisplayQuaternion(scene, e) {
  138. if(!this.adjustment) {
  139. this.adjustment = new THREE.Quaternion();
  140. this.adjustment.setFromAxisAngle( new THREE.Vector3( 1, 0, 0 ), Math.PI / 2 );
  141. }
  142. e.quaternion.multiply(this.adjustment);
  143. e.quaternion.y *= -1;
  144. e.quaternion.z *= -1;
  145. e.quaternion.multiply(scene.quaternion);
  146. return e.quaternion;
  147. }
  148. function positionOnDome(object, azimuth, elevation, distanceAwayFromDome) {
  149. /** * Adjust the values to make a coordinate system which makes sense for a
  150. * dome theater:
  151. *
  152. * azimuth = 0 Straight ahead
  153. * azimuth = 90 Right of ahead
  154. * azimuth = -90 Left of ahead
  155. */
  156. var inclination = 90 - elevation;
  157. azimuth = -azimuth + 180;
  158. var distance = RendererConfig.dome.radius + distanceAwayFromDome;
  159. // Convert to radians from degrees
  160. inclination *= Math.PI / 180;
  161. azimuth *= Math.PI / 180;
  162. /** The equations are from wikipedia but were adjusted to match the
  163. * * THREE.js coordinate system which puts positive Z away from the
  164. * screen towards the user.
  165. *
  166. * https://en.wikipedia.org/wiki/Spherical_coordinate_system
  167. */
  168. object.position.z = distance * Math.sin(inclination) * Math.cos(azimuth);
  169. object.position.x = distance * Math.sin(inclination) * Math.sin(azimuth);
  170. object.position.y = distance * Math.cos(inclination);
  171. // Make sure the sprite always faces the camera.
  172. object.lookAt(RendererConfig.camera.rig.position);
  173. }
  174. /* Functions for working with the Draco mesh decompressor */
  175. // Global Draco decoder type.
  176. let dracoDecoderType = {};
  177. let dracoLoader;
  178. function loadWebAssemblyDecoder(readyCallback) {
  179. dracoDecoderType['wasmBinaryFile'] = '../libs/draco/draco_decoder.wasm';
  180. const xhr = new XMLHttpRequest();
  181. xhr.open('GET', '../libs/draco/draco_decoder.wasm', true);
  182. xhr.responseType = 'arraybuffer';
  183. xhr.onload = function() {
  184. // draco_wasm_wrapper.js must be loaded before DracoModule is
  185. // created. The object passed into DracoModule() must contain a
  186. // property with the name of wasmBinary and the value must be an
  187. // ArrayBuffer containing the contents of the .wasm file.
  188. dracoDecoderType['wasmBinary'] = xhr.response;
  189. createDracoDecoder(readyCallback);
  190. };
  191. xhr.send(null)
  192. }
  193. function createDracoDecoder(readyCallback) {
  194. dracoLoader = new THREE.DRACOLoader();
  195. dracoLoader.setDracoDecoderType(dracoDecoderType);
  196. if(readyCallback) {
  197. readyCallback();
  198. }
  199. }
  200. // This function will test if the browser has support for WebAssembly. If
  201. // it does it will download the WebAssembly Draco decoder, if not it will
  202. // download the asmjs Draco decoder.
  203. // TODO: Investigate moving the Draco decoder loading code
  204. // over to DRACOLoader.js.
  205. function loadDracoDecoder(readyCallback) {
  206. if (typeof WebAssembly !== 'object') {
  207. // No WebAssembly support
  208. loadResource('../libs/draco/draco_decoder.js', true, createDracoDecoder.bind(null,readyCallback));
  209. } else {
  210. loadResource('../libs/draco/draco_wasm_wrapper.js', true, loadWebAssemblyDecoder.bind(null,readyCallback));
  211. }
  212. }
  213. function loadDracoModel(url, successCallback, errorCallback) {
  214. loadUrl(url, function(data) {dracoLoader.decodeDracoFile(data, successCallback);}, errorCallback, "arraybuffer");
  215. }
  216. /* Trick for inline strings for GLSL code:
  217. http://stackoverflow.com/questions/805107/creating-multiline-strings-in-javascript
  218. */
  219. Function.prototype.getComment = function() {
  220. var startComment = "/*!";
  221. var endComment = "*/";
  222. var str = this.toString();
  223. var start = str.indexOf(startComment);
  224. var end = str.lastIndexOf(endComment);
  225. return str.slice(start + startComment.length, -(str.length - end));
  226. };