PageRenderTime 42ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/ruhlamat_website/o3djs/io.js

http://demoasp.googlecode.com/
JavaScript | 577 lines | 233 code | 36 blank | 308 comment | 48 complexity | a8c61ea1c44b59eed8c301c0fe7b8dd6 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1
  1. /*
  2. * Copyright 2009, Google Inc.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are
  7. * met:
  8. *
  9. * * Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * * Redistributions in binary form must reproduce the above
  12. * copyright notice, this list of conditions and the following disclaimer
  13. * in the documentation and/or other materials provided with the
  14. * distribution.
  15. * * Neither the name of Google Inc. nor the names of its
  16. * contributors may be used to endorse or promote products derived from
  17. * this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. */
  31. /**
  32. * @fileoverview This file contains various functions and class for io.
  33. */
  34. o3djs.provide('o3djs.io');
  35. /**
  36. * A Module with various io functions and classes.
  37. * @namespace
  38. */
  39. o3djs.io = o3djs.io || {};
  40. /**
  41. * Creates a LoadInfo object.
  42. * @param {(!o3d.ArchiveRequest|!o3d.FileRequest|!XMLHttpRequest)} opt_request
  43. * The request to watch.
  44. * @param {boolean} opt_hasStatus true if opt_request is a
  45. * o3d.ArchiveRequest vs for example an o3d.FileRequest or an
  46. * XMLHttpRequest.
  47. * @return {!o3djs.io.LoadInfo} The new LoadInfo.
  48. * @see o3djs.io.LoadInfo
  49. */
  50. o3djs.io.createLoadInfo = function(opt_request, opt_hasStatus) {
  51. return new o3djs.io.LoadInfo(opt_request, opt_hasStatus);
  52. };
  53. /**
  54. * A class to help with progress reporting for most loading utilities.
  55. *
  56. * Example:
  57. * <pre>
  58. * var g_loadInfo = null;
  59. * g_id = window.setInterval(statusUpdate, 500);
  60. * g_loadInfo = o3djs.scene.loadScene(client, pack, parent,
  61. * 'http://google.com/somescene.o3dtgz',
  62. * callback);
  63. *
  64. * function callback(pack, parent, exception) {
  65. * g_loadInfo = null;
  66. * window.clearInterval(g_id);
  67. * if (!exception) {
  68. * // do something with scene just loaded
  69. * }
  70. * }
  71. *
  72. * function statusUpdate() {
  73. * if (g_loadInfo) {
  74. * var progress = g_loadInfo.getKnownProgressInfoSoFar();
  75. * document.getElementById('loadstatus').innerHTML = progress.percent;
  76. * }
  77. * }
  78. * </pre>
  79. *
  80. * @constructor
  81. * @param {(!o3d.ArchiveRequest|!o3d.FileRequest|!XMLHttpRequest)} opt_request
  82. * The request to watch.
  83. * @param {boolean} opt_hasStatus true if opt_request is a
  84. * o3d.ArchiveRequest vs for example an o3d.FileRequest or an
  85. * XMLHttpRequest.
  86. * @see o3djs.scene.loadScene
  87. * @see o3djs.io.loadArchive
  88. * @see o3djs.io.loadTexture
  89. * @see o3djs.loader.Loader
  90. */
  91. o3djs.io.LoadInfo = function(opt_request, opt_hasStatus) {
  92. this.request_ = opt_request;
  93. this.hasStatus_ = opt_hasStatus;
  94. this.streamLength_ = 0; // because the request may have been freed.
  95. this.children_ = [];
  96. };
  97. /**
  98. * Adds another LoadInfo as a child of this LoadInfo so they can be
  99. * managed as a group.
  100. * @param {!o3djs.io.LoadInfo} loadInfo The child LoadInfo.
  101. */
  102. o3djs.io.LoadInfo.prototype.addChild = function(loadInfo) {
  103. this.children_.push(loadInfo);
  104. };
  105. /**
  106. * Marks this LoadInfo as finished.
  107. */
  108. o3djs.io.LoadInfo.prototype.finish = function() {
  109. if (this.request_) {
  110. if (this.hasStatus_) {
  111. this.streamLength_ = this.request_.streamLength;
  112. }
  113. this.request_ = null;
  114. }
  115. };
  116. /**
  117. * Gets the total bytes that will be streamed known so far.
  118. * If you are only streaming 1 file then this will be the info for that file but
  119. * if you have queued up many files using an o3djs.loader.Loader only a couple of
  120. * files are streamed at a time meaning that the size is not known for files
  121. * that have yet started to download.
  122. *
  123. * If you are downloading many files for your application and you want to
  124. * provide a progress status you have about 4 options
  125. *
  126. * 1) Use LoadInfo.getTotalBytesDownloaded() /
  127. * LoadInfo.getTotalKnownBytesToStreamSoFar() and just be aware the bar will
  128. * grown and then shrink as new files start to download and their lengths
  129. * become known.
  130. *
  131. * 2) Use LoadInfo.getTotalRequestsDownloaded() /
  132. * LoadInfo.getTotalKnownRequestsToStreamSoFar() and be aware the granularity
  133. * is not all that great since it only reports fully downloaded files. If you
  134. * are downloading a bunch of small files this might be ok.
  135. *
  136. * 3) Put all your files in one archive. Then there will be only one file and
  137. * method 1 will work well.
  138. *
  139. * 4) Figure out the total size in bytes of the files you will download and put
  140. * that number in your application, then use LoadInfo.getTotalBytesDownloaded()
  141. * / MY_APPS_TOTAL_BYTES_TO_DOWNLOAD.
  142. *
  143. * @return {number} The total number of currently known bytes to be streamed.
  144. */
  145. o3djs.io.LoadInfo.prototype.getTotalKnownBytesToStreamSoFar = function() {
  146. if (!this.streamLength_ && this.request_ && this.hasStatus_) {
  147. this.streamLength_ = this.request_.streamLength;
  148. }
  149. var total = this.streamLength_;
  150. for (var cc = 0; cc < this.children_.length; ++cc) {
  151. total += this.children_[cc].getTotalKnownBytesToStreamSoFar();
  152. }
  153. return total;
  154. };
  155. /**
  156. * Gets the total bytes downloaded so far.
  157. * @return {number} The total number of currently known bytes to be streamed.
  158. */
  159. o3djs.io.LoadInfo.prototype.getTotalBytesDownloaded = function() {
  160. var total = (this.request_ && this.hasStatus_) ?
  161. this.request_.bytesReceived : this.streamLength_;
  162. for (var cc = 0; cc < this.children_.length; ++cc) {
  163. total += this.children_[cc].getTotalBytesDownloaded();
  164. }
  165. return total;
  166. };
  167. /**
  168. * Gets the total streams that will be download known so far.
  169. * We can't know all the streams since you could use an o3djs.loader.Loader
  170. * object, request some streams, then call this function, then request some
  171. * more.
  172. *
  173. * See LoadInfo.getTotalKnownBytesToStreamSoFar for details.
  174. * @return {number} The total number of requests currently known to be streamed.
  175. * @see o3djs.io.LoadInfo.getTotalKnownBytesToStreamSoFar
  176. */
  177. o3djs.io.LoadInfo.prototype.getTotalKnownRequestsToStreamSoFar = function() {
  178. var total = 1;
  179. for (var cc = 0; cc < this.children_.length; ++cc) {
  180. total += this.children_[cc].getTotalKnownRequestToStreamSoFar();
  181. }
  182. return total;
  183. };
  184. /**
  185. * Gets the total requests downloaded so far.
  186. * @return {number} The total requests downloaded so far.
  187. */
  188. o3djs.io.LoadInfo.prototype.getTotalRequestsDownloaded = function() {
  189. var total = this.request_ ? 0 : 1;
  190. for (var cc = 0; cc < this.children_.length; ++cc) {
  191. total += this.children_[cc].getTotalRequestsDownloaded();
  192. }
  193. return total;
  194. };
  195. /**
  196. * Gets progress info.
  197. * This is commonly formatted version of the information available from a
  198. * LoadInfo.
  199. *
  200. * See LoadInfo.getTotalKnownBytesToStreamSoFar for details.
  201. * @return {{percent: number, downloaded: string, totalBytes: string,
  202. * base: number, suffix: string}} progress info.
  203. * @see o3djs.io.LoadInfo.getTotalKnownBytesToStreamSoFar
  204. */
  205. o3djs.io.LoadInfo.prototype.getKnownProgressInfoSoFar = function() {
  206. var percent = 0;
  207. var bytesToDownload = this.getTotalKnownBytesToStreamSoFar();
  208. var bytesDownloaded = this.getTotalBytesDownloaded();
  209. if (bytesToDownload > 0) {
  210. percent = Math.floor(bytesDownloaded / bytesToDownload * 100);
  211. }
  212. var base = (bytesToDownload < 1024 * 1024) ? 1024 : (1024 * 1024);
  213. return {
  214. percent: percent,
  215. downloaded: (bytesDownloaded / base).toFixed(2),
  216. totalBytes: (bytesToDownload / base).toFixed(2),
  217. base: base,
  218. suffix: (base == 1024 ? 'kb' : 'mb')}
  219. };
  220. /**
  221. * Loads text from an external file. This function is synchronous.
  222. * @param {string} url The url of the external file.
  223. * @return {string} the loaded text if the request is synchronous.
  224. */
  225. o3djs.io.loadTextFileSynchronous = function(url) {
  226. o3djs.BROWSER_ONLY = true;
  227. var error = 'loadTextFileSynchronous failed to load url "' + url + '"';
  228. var request;
  229. if (!o3djs.base.IsMSIE() && window.XMLHttpRequest) {
  230. request = new XMLHttpRequest();
  231. if (request.overrideMimeType) {
  232. request.overrideMimeType('text/plain');
  233. }
  234. } else if (window.ActiveXObject) {
  235. request = new ActiveXObject('MSXML2.XMLHTTP.3.0');
  236. } else {
  237. throw 'XMLHttpRequest is disabled';
  238. }
  239. request.open('GET', url, false);
  240. request.send(null);
  241. if (request.readyState != 4) {
  242. throw error;
  243. }
  244. return request.responseText;
  245. };
  246. /**
  247. * Loads text from an external file. This function is asynchronous.
  248. * @param {string} url The url of the external file.
  249. * @param {function(string, *): void} callback A callback passed the loaded
  250. * string and an exception which will be null on success.
  251. * @return {!o3djs.io.LoadInfo} A LoadInfo to track progress.
  252. */
  253. o3djs.io.loadTextFile = function(url, callback) {
  254. o3djs.BROWSER_ONLY = true;
  255. var error = 'loadTextFile failed to load url "' + url + '"';
  256. var request;
  257. if (!o3djs.base.IsMSIE() && window.XMLHttpRequest) {
  258. request = new XMLHttpRequest();
  259. if (request.overrideMimeType) {
  260. request.overrideMimeType('text/plain');
  261. }
  262. } else if (window.ActiveXObject) {
  263. request = new ActiveXObject('MSXML2.XMLHTTP.3.0');
  264. } else {
  265. throw 'XMLHttpRequest is disabled';
  266. }
  267. var loadInfo = o3djs.io.createLoadInfo(request, false);
  268. request.open('GET', url, true);
  269. var finish = function() {
  270. if (request.readyState == 4) {
  271. var text = '';
  272. // HTTP reports success with a 200 status. The file protocol reports
  273. // success with zero. HTTP does not use zero as a status code (they
  274. // start at 100).
  275. // https://developer.mozilla.org/En/Using_XMLHttpRequest
  276. var success = request.status == 200 || request.status == 0;
  277. if (success) {
  278. text = request.responseText;
  279. }
  280. loadInfo.finish();
  281. callback(text, success ? null : 'could not load: ' + url);
  282. }
  283. };
  284. request.onreadystatechange = finish;
  285. request.send(null);
  286. return loadInfo;
  287. };
  288. /**
  289. * A ArchiveInfo object loads and manages an archive of files.
  290. * There are methods for locating a file by uri and for freeing
  291. * the archive.
  292. *
  293. * You can only read archives that have as their first file a file named
  294. * 'aaaaaaaa.o3d' the contents of the which is 'o3d'. This is to prevent O3D
  295. * from being used to read arbitrary tar gz files.
  296. *
  297. * Example:
  298. * <pre>
  299. * var loadInfo = o3djs.io.loadArchive(pack,
  300. * 'http://google.com/files.o3dtgz',
  301. * callback);
  302. *
  303. * function callback(archiveInfo, exception) {
  304. * if (!exception) {
  305. * pack.createTextureFromRawData(
  306. * archiveInfo.getFileByURI('logo.jpg'), true);
  307. * pack.createTextureFromRawData(
  308. * archiveInfo.getFileByURI('wood/oak.png'), true);
  309. * pack.createTextureFromRawData(
  310. * archiveInfo.getFileByURI('wood/maple.dds'), true);
  311. * archiveInfo.destroy();
  312. * } else {
  313. * alert(exception);
  314. * }
  315. * }
  316. * </pre>
  317. *
  318. * @constructor
  319. * @param {!o3d.Pack} pack Pack to create request in.
  320. * @param {string} url The url of the archive file.
  321. * @param {!function(!o3djs.io.ArchiveInfo, *): void} onFinished A
  322. * callback that is called when the archive is finished loading and passed
  323. * the ArchiveInfo and an exception which is null on success.
  324. */
  325. o3djs.io.ArchiveInfo = function(pack, url, onFinished) {
  326. var that = this;
  327. /**
  328. * The list of files in the archive by uri.
  329. * @type {!Object}
  330. */
  331. this.files = {};
  332. /**
  333. * The pack used to create the archive request.
  334. * @type {!o3d.Pack}
  335. */
  336. this.pack = pack;
  337. /**
  338. * True if this archive has not be destroyed.
  339. * @type {boolean}
  340. */
  341. this.destroyed = false;
  342. this.request_ = null;
  343. /**
  344. * Records each RawData file as it comes in.
  345. * @private
  346. * @param {!o3d.RawData} rawData RawData from archive request.
  347. */
  348. function addFile(rawData) {
  349. that.files[rawData.uri] = rawData;
  350. }
  351. /**
  352. * The LoadInfo to track loading progress.
  353. * @type {!o3djs.io.LoadInfo}
  354. */
  355. this.loadInfo = o3djs.io.loadArchiveAdvanced(
  356. pack,
  357. url,
  358. addFile,
  359. function(request, exception) {
  360. that.request_ = request;
  361. onFinished(that, exception);
  362. });
  363. };
  364. /**
  365. * Releases all the RAW data associated with this archive. It does not release
  366. * any objects created from that RAW data.
  367. */
  368. o3djs.io.ArchiveInfo.prototype.destroy = function() {
  369. if (!this.destroyed) {
  370. this.pack.removeObject(this.request_);
  371. this.destroyed = true;
  372. this.files = {};
  373. }
  374. };
  375. /**
  376. * Gets files by regular expression or wildcards from the archive.
  377. * @param {(string|!RegExp)} uri of file to get. Can have wildcards '*' and '?'.
  378. * @param {boolean} opt_caseInsensitive Only valid if it's a wildcard string.
  379. * @return {!Array.<!o3d.RawData>} An array of the matching RawDatas for
  380. * the files matching or undefined if it doesn't exist.
  381. */
  382. o3djs.io.ArchiveInfo.prototype.getFiles = function(uri,
  383. opt_caseInsensitive) {
  384. if (!(uri instanceof RegExp)) {
  385. uri = uri.replace(/(\W)/g, '\\$&');
  386. uri = uri.replace(/\\\*/g, '.*');
  387. uri = uri.replace(/\\\?/g, '.');
  388. uri = new RegExp(uri, opt_caseInsensitive ? 'i' : '');
  389. }
  390. var files = [];
  391. for (var key in this.files) {
  392. if (uri.test(key)) {
  393. files.push(this.files[key]);
  394. }
  395. }
  396. return files;
  397. };
  398. /**
  399. * Gets a file by URI from the archive.
  400. * @param {string} uri of file to get.
  401. * @param {boolean} opt_caseInsensitive True to be case insensitive. Default
  402. * false.
  403. * @return {(o3d.RawData|undefined)} The RawData for the file or undefined if
  404. * it doesn't exist.
  405. */
  406. o3djs.io.ArchiveInfo.prototype.getFileByURI = function(
  407. uri,
  408. opt_caseInsensitive) {
  409. if (opt_caseInsensitive) {
  410. uri = uri.toLowerCase();
  411. for (var key in this.files) {
  412. if (key.toLowerCase() == uri) {
  413. return this.files[key];
  414. }
  415. }
  416. return undefined;
  417. } else {
  418. return this.files[uri];
  419. }
  420. };
  421. /**
  422. * Loads an archive file.
  423. * When the entire archive is ready the onFinished callback will be called
  424. * with an ArchiveInfo for accessing the archive.
  425. *
  426. * @param {!o3d.Pack} pack Pack to create request in.
  427. * @param {string} url The url of the archive file.
  428. * @param {!function(!o3djs.io.ArchiveInfo, *): void} onFinished A
  429. * callback that is called when the archive is successfully loaded and an
  430. * Exception object which is null on success.
  431. * @return {!o3djs.io.LoadInfo} The a LoadInfo for tracking progress.
  432. * @see o3djs.io.ArchiveInfo
  433. */
  434. o3djs.io.loadArchive = function(pack,
  435. url,
  436. onFinished) {
  437. var archiveInfo = new o3djs.io.ArchiveInfo(pack, url, onFinished);
  438. return archiveInfo.loadInfo;
  439. };
  440. /**
  441. * Loads an archive file. This function is asynchronous. This is a low level
  442. * version of o3djs.io.loadArchive which can be used for things like
  443. * progressive loading.
  444. *
  445. * @param {!o3d.Pack} pack Pack to create request in.
  446. * @param {string} url The url of the archive file.
  447. * @param {!function(!o3d.RawData): void} onFileAvailable A callback, taking a
  448. * single argument 'data'. As each file is loaded from the archive, this
  449. * function is called with the file's data.
  450. * @param {!function(!o3d.ArchiveRequest, *): void} onFinished
  451. * A callback that is called when the archive is successfully loaded. It is
  452. * passed the ArchiveRquest and null on success or a javascript exception on
  453. * failure.
  454. * @return {!o3djs.io.LoadInfo} A LoadInfo for tracking progress.
  455. */
  456. o3djs.io.loadArchiveAdvanced = function(pack,
  457. url,
  458. onFileAvailable,
  459. onFinished) {
  460. var error = 'loadArchive failed to load url "' + url + '"';
  461. var request = pack.createArchiveRequest();
  462. var loadInfo = o3djs.io.createLoadInfo(request, true);
  463. request.open('GET', url);
  464. request.onfileavailable = function() {
  465. onFileAvailable(/** @type {!o3d.RawData} */ (request.data));
  466. };
  467. /**
  468. * @ignore
  469. */
  470. request.onreadystatechange = function() {
  471. if (request.done) {
  472. loadInfo.finish();
  473. var success = request.success;
  474. var exception = null;
  475. if (!success) {
  476. exception = request.error;
  477. if (!exception) {
  478. exception = 'unknown error loading archive';
  479. }
  480. }
  481. onFinished(request, exception);
  482. }
  483. };
  484. request.send();
  485. return loadInfo;
  486. };
  487. /**
  488. * Loads a texture.
  489. *
  490. * Textures are loaded asynchronously.
  491. *
  492. * Example:
  493. * <pre>
  494. * var loadInfo = o3djs.io.loadTexture(pack,
  495. * 'http://google.com/someimage.jpg',
  496. * callback);
  497. *
  498. * function callback(texture, exception) {
  499. * if (!exception) {
  500. * g_mySampler.texture = texture;
  501. * } else {
  502. * alert(exception);
  503. * }
  504. * }
  505. * </pre>
  506. *
  507. *
  508. * @param {!o3d.Pack} pack Pack to load texture into.
  509. * @param {string} url URL of texture to load.
  510. * @param {!function(o3d.Texture, *): void} callback Callback when
  511. * texture is loaded. It will be passed the texture and an exception on
  512. * error or null on success.
  513. * @return {!o3djs.io.LoadInfo} A LoadInfo to track progress.
  514. * @see o3djs.io.createLoader
  515. */
  516. o3djs.io.loadTexture = function(pack, url, callback) {
  517. // TODO: change this to get use RawData and Bitmap
  518. var request = pack.createFileRequest('TEXTURE');
  519. var loadInfo = o3djs.io.createLoadInfo(
  520. /** @type {!o3d.FileRequest} */ (request),
  521. false);
  522. request.open('GET', url, true);
  523. /**
  524. * @ignore
  525. */
  526. request.onreadystatechange = function() {
  527. if (request.done) {
  528. var texture = request.texture;
  529. var success = request.success;
  530. var exception = request.error;
  531. loadInfo.finish();
  532. pack.removeObject(request);
  533. if (!success && !exception) {
  534. exception = 'unknown error loading texture';
  535. }
  536. callback(texture, success ? null : exception);
  537. }
  538. };
  539. request.send();
  540. return loadInfo;
  541. };