topical media & game development

talk show tell print

graphic-o3d-samples-o3djs-io.js / js



  /*
   * Copyright 2009, Google Inc.
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are
   * met:
   *
   *     * Redistributions of source code must retain the above copyright
   * notice, this list of conditions and the following disclaimer.
   *     * Redistributions in binary form must reproduce the above
   * copyright notice, this list of conditions and the following disclaimer
   * in the documentation and/or other materials provided with the
   * distribution.
   *     * Neither the name of Google Inc. nor the names of its
   * contributors may be used to endorse or promote products derived from
   * this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  
@fileoverview This file contains various functions and class for io.

  
  
  o3djs.provide('o3djs.io');
  
  
A Module with various io functions and classes. @namespace

  
  o3djs.io = o3djs.io || {};
  
  
Creates a LoadInfo object.
parameter: {!o3d.ArchiveRequest} opt_request The request to watch.
parameter: {boolean} opt_hasStatus true if opt_request is a o3d.ArchiveRequest vs for example an o3d.FileRequest or an XMLHttpRequest.
returns: {!o3djs.io.LoadInfo} The new LoadInfo.
see: o3djs.io.LoadInfo

  
  o3djs.io.createLoadInfo = function(opt_request, opt_hasStatus) {
    return new o3djs.io.LoadInfo(opt_request, opt_hasStatus);
  };
  
  
A class to help with progress reporting for most loading utilities. Example: <pre> var g_loadInfo = null; g_id = window.setInterval(statusUpdate, 500); g_loadInfo = o3djs.scene.loadScene(client, pack, parent, 'http://google.com/somescene.tgz', callback); function callback(pack, parent, exception) { g_loadInfo = null; window.clearInterval(g_id); if (!exception) { // do something with scene just loaded } } function statusUpdate() { if (g_loadInfo) { var progress = g_loadInfo.getKnownProgressInfoSoFar(); document.getElementById('loadstatus').innerHTML = progress.percent; } } </pre> @constructor
parameter: {!o3d.ArchiveRequest} opt_request The request to watch.
parameter: {boolean} opt_hasStatus true if opt_request is a o3d.ArchiveRequest vs for example an o3d.FileRequest or an XMLHttpRequest.
see: o3djs.scene.loadScene
see: o3djs.io.loadArchive
see: o3djs.io.loadTexture
see: o3djs.loader.Loader

  
  o3djs.io.LoadInfo = function(opt_request, opt_hasStatus) {
    this.request_ = opt_request;
    this.hasStatus_ = opt_hasStatus;
    this.streamLength_ = 0;  // because the request may have been freed.
    this.children_ = [];
  };
  
  
Adds another LoadInfo as a child of this LoadInfo so they can be managed as a group.
parameter: {!o3djs.io.LoadInfo} loadInfo The child LoadInfo.

  
  o3djs.io.LoadInfo.prototype.addChild = function(loadInfo) {
    this.children_.push(loadInfo);
  };
  
  
Marks this LoadInfo as finished.

  
  o3djs.io.LoadInfo.prototype.finish = function() {
    if (this.request_) {
      if (this.hasStatus_) {
        this.streamLength_ = this.request_.streamLength;
      }
      this.request_ = null;
    }
  };
  
  
Gets the total bytes that will be streamed known so far. If you are only streaming 1 file then this will be the info for that file but if you have queued up many files using a o3djs.loader.Loader only a couple of files are streamed at a time meaning that the size is not known for files that have yet started to download. If you are downloading many files for your application and you want to provide a progress status you have about 4 options 1) Use LoadInfo.getTotalBytesDownloaded() / LoadInfo.getTotalKnownBytesToStreamSoFar() and just be aware the bar will grown and then shrink as new files start to download and their lengths become known. 2) Use LoadInfo.getTotalRequestsDownloaded() / LoadInfo.getTotalKnownRequestsToStreamSoFar() and be aware the granularity is not all that great since it only reports fully downloaded files. If you are downloading a bunch of small files this might be ok. 3) Put all your files in one archive. Then there will be only one file and method 1 will work well. 4) Figure out the total size in bytes of the files you will download and put that number in your application, then use LoadInfo.getTotalBytesDownloaded() / MY_APPS_TOTAL_BYTES_TO_DOWNLOAD.
returns: {number} The total number of currently known bytes to be streamed.

  
  o3djs.io.LoadInfo.prototype.getTotalKnownBytesToStreamSoFar = function() {
    if (!this.streamLength_ && this.request_ && this.hasStatus_) {
      this.streamLength_ = this.request_.streamLength;
    }
    var total = this.streamLength_;
    for (var cc = 0; cc < this.children_.length; ++cc) {
      total += this.children_[cc].getTotalKnownBytesToStreamSoFar();
    }
    return total;
  };
  
  
Gets the total bytes downloaded so far.
returns: {number} The total number of currently known bytes to be streamed.

  
  o3djs.io.LoadInfo.prototype.getTotalBytesDownloaded = function() {
    var total = (this.request_ && this.hasStatus_) ?
                this.request_.bytesReceived : this.streamLength_;
    for (var cc = 0; cc < this.children_.length; ++cc) {
      total += this.children_[cc].getTotalBytesDownloaded();
    }
    return total;
  };
  
  
Gets the total streams that will be download known so far. We can't know all the streams since you could use a o3djs.loader.Loader object, request some streams, then call this function, then request some more. See LoadInfo.getTotalKnownBytesToStreamSoFar for details.
returns: {number} The total number of requests currently known to be streamed.
see: o3djs.io.LoadInfo.getTotalKnownBytesToStreamSoFar

  
  o3djs.io.LoadInfo.prototype.getTotalKnownRequestsToStreamSoFar = function() {
    var total = 1;
    for (var cc = 0; cc < this.children_.length; ++cc) {
      total += this.children_[cc].getTotalKnownRequestToStreamSoFar();
    }
    return total;
  };
  
  
Gets the total requests downloaded so far.
returns: {number} The total requests downloaded so far.

  
  o3djs.io.LoadInfo.prototype.getTotalRequestsDownloaded = function() {
    var total = this.request_ ? 0 : 1;
    for (var cc = 0; cc < this.children_.length; ++cc) {
      total += this.children_[cc].getTotalRequestsDownloaded();
    }
    return total;
  };
  
  
Gets progress info. This is commonly formatted version of the information available from a LoadInfo. See LoadInfo.getTotalKnownBytesToStreamSoFar for details.
returns: {percent: number, downloaded: string, totalBytes: string, base: number, suffix: string} progress info.
see: o3djs.io.LoadInfo.getTotalKnownBytesToStreamSoFar

  
  o3djs.io.LoadInfo.prototype.getKnownProgressInfoSoFar = function() {
    var percent = 0;
    var bytesToDownload = this.getTotalKnownBytesToStreamSoFar();
    var bytesDownloaded = this.getTotalBytesDownloaded();
    if (bytesToDownload > 0) {
      percent = Math.floor(bytesDownloaded / bytesToDownload * 100);
    }
  
    var base = (bytesToDownload < 1024 * 1024) ? 1024 : (1024 * 1024);
  
    return {
      percent: percent,
      downloaded: (bytesDownloaded / base).toFixed(2),
      totalBytes: (bytesToDownload / base).toFixed(2),
      base: base,
      suffix: (base == 1024 ? 'kb' : 'mb')}
  
  };
  
  
Loads text from an external file. This function is synchronous.
parameter: {string} url The url of the external file.
returns: {string} the loaded text if the request is synchronous.

  
  o3djs.io.loadTextFileSynchronous = function(url) {
    o3djs.BROWSER_ONLY;
  
    var error = 'loadTextFileSynchronous failed to load url "' + url + '"';
    var request;
    if (!o3djs.base.IsMSIE() && window.XMLHttpRequest) {
      request = new XMLHttpRequest();
      if (request.overrideMimeType) {
        request.overrideMimeType('text/plain');
      }
    } else if (window.ActiveXObject) {
      request = new ActiveXObject('MSXML2.XMLHTTP.3.0');
    } else {
      throw 'XMLHttpRequest is disabled';
    }
    request.open('GET', url, false);
    request.send(null);
    if (request.readyState != 4) {
      throw error;
    }
    return request.responseText;
  };
  
  
Loads text from an external file. This function is asynchronous.
parameter: {string} url The url of the external file.
parameter: {function(string, *): void} callback A callback passed the loaded string and an exception which will be null on success.
returns: {!o3djs.io.LoadInfo} A LoadInfo to track progress.

  
  o3djs.io.loadTextFile = function(url, callback) {
    o3djs.BROWSER_ONLY;
  
    var error = 'loadTextFile failed to load url "' + url + '"';
    var request;
    if (!o3djs.base.IsMSIE() && window.XMLHttpRequest) {
      request = new XMLHttpRequest();
      if (request.overrideMimeType) {
        request.overrideMimeType('text/plain');
      }
    } else if (window.ActiveXObject) {
      request = new ActiveXObject('MSXML2.XMLHTTP.3.0');
    } else {
      throw 'XMLHttpRequest is disabled';
    }
    var loadInfo = o3djs.io.createLoadInfo(request, false);
    request.open('GET', url, true);
    var finish = function() {
      if (request.readyState == 4) {
        var text = '';
        // HTTP reports success with a 200 status. The file protocol reports
        // success with zero. HTTP does not use zero as a status code (they
        // start at 100).
        // https://developer.mozilla.org/En/Using_XMLHttpRequest
        var success = request.status == 200 || request.status == 0;
        if (success) {
          text = request.responseText;
        }
        loadInfo.finish();
        callback(text, success ? null : 'could not load: ' + url);
      }
    };
    request.onreadystatechange = finish;
    request.send(null);
    return loadInfo;
  };
  
  
A ArchiveInfo object loads and manages an archive of files. There are methods for locating a file by uri and for freeing the archive. You can only read archives that have as their first file a file named 'aaaaaaaa.o3d' the contents of the which is 'o3d'. This is to prevent O3D from being used to read arbitrary tar gz files. Example: <pre> var loadInfo = o3djs.io.loadArchive(pack, 'http://google.com/files.tgz', callback); function callback(archiveInfo, exception) { if (!exception) { pack.createTextureFromRawData( archiveInfo.getFileByURI('logo.jpg'), true); pack.createTextureFromRawData( archiveInfo.getFileByURI('wood/oak.png'), true); pack.createTextureFromRawData( archiveInfo.getFileByURI('wood/maple.dds'), true); archiveInfo.destroy(); } else { alert(exception); } } </pre> @constructor
parameter: {!o3d.Pack} pack Pack to create request in.
parameter: {string} url The url of the archive file.
parameter: {!function(!o3djs.io.ArchiveInfo, *): void} onFinished A callback that is called when the archive is finished loading and passed the ArchiveInfo and an exception which is null on success.

  
  o3djs.io.ArchiveInfo = function(pack, url, onFinished) {
    var that = this;
  
    
The list of files in the archive by uri. @type {!Object}

  
    this.files = {};
  
    
The pack used to create the archive request. @type {!o3d.Pack}

  
    this.pack = pack;
  
    
True if this archive has not be destroyed. @type {boolean}

  
    this.destroyed = false;
  
    this.request_ = null;
  
    
Records each RawData file as it comes in. @private
parameter: {!o3d.RawData} rawData RawData from archive request.

  
    function addFile(rawData) {
      that.files[rawData.uri] = rawData;
    }
  
    
The LoadInfo to track loading progress. @type {!o3djs.io.LoadInfo}

  
    this.loadInfo = o3djs.io.loadArchiveAdvanced(
        pack,
        url,
        addFile,
        function(request, exception) {
          that.request_ = request;
          onFinished(that, exception);
        });
  };
  
  
Releases all the RAW data associated with this archive. It does not release any objects created from that RAW data.

  
  o3djs.io.ArchiveInfo.prototype.destroy = function() {
    if (!this.destroyed) {
      this.pack.removeObject(this.request_);
      this.destroyed = true;
      this.files = {};
    }
  };
  
  
Gets files by regular expression or wildcards from the archive.
parameter: {(string|!RegExp)} uri of file to get. Can have wildcards '*' and '?'.
parameter: {boolean} opt_caseInsensitive Only valid if it's a wildcard string.
returns: {!Array.} An array of the matching RawDatas for the files matching or undefined if it doesn't exist.

  
  o3djs.io.ArchiveInfo.prototype.getFiles = function(uri,
                                                     opt_caseInsensitive) {
    if (!(uri instanceof RegExp)) {
      uri = uri.replace(/(\W)/g, '\$&');
      uri = uri.replace(/\\\*/g, '.*');
      uri = uri.replace(/\\\?/g, '.');
      uri = new RegExp(uri, opt_caseInsensitive ? 'i' : '');
    }
    var files = [];
    for (var key in this.files) {
      if (uri.test(key)) {
        files.push(this.files[key]);
      }
    }
  
    return files;
  };
  
  
Gets a file by URI from the archive.
parameter: {string} uri of file to get.
parameter: {boolean} opt_caseInsensitive True to be case insensitive. Default false.
returns: {(o3d.RawData|undefined)} The RawData for the file or undefined if it doesn't exist.

  
  o3djs.io.ArchiveInfo.prototype.getFileByURI = function(
      uri,
      opt_caseInsensitive) {
    if (opt_caseInsensitive) {
      uri = uri.toLowerCase();
      for (var key in this.files) {
        if (key.toLowerCase() == uri) {
          return this.files[key];
        }
      }
      return undefined;
    } else {
      return this.files[uri];
    }
  };
  
  
Loads an archive file. When the entire archive is ready the onFinished callback will be called with an ArchiveInfo for accessing the archive.
parameter: {!o3d.Pack} pack Pack to create request in.
parameter: {string} url The url of the archive file.
parameter: {!function(!o3djs.io.ArchiveInfo, *): void} onFinished A callback that is called when the archive is successfully loaded and an Exception object which is null on success.
returns: {!o3djs.io.LoadInfo} The a LoadInfo for tracking progress.
see: o3djs.io.ArchiveInfo

  
  o3djs.io.loadArchive = function(pack,
                                  url,
                                  onFinished) {
    var archiveInfo = new o3djs.io.ArchiveInfo(pack, url, onFinished);
    return archiveInfo.loadInfo;
  };
  
  
Loads an archive file. This function is asynchronous. This is a low level version of o3djs.io.loadArchive which can be used for things like progressive loading.
parameter: {!o3d.Pack} pack Pack to create request in.
parameter: {string} url The url of the archive file.
parameter: {!function(RawData): void} onFileAvailable A callback, taking a single argument 'data'. As each file is loaded from the archive, this function is called with the file's data.
parameter: {!function(!o3d.ArchiveRequest, *): void} onFinished A callback that is called when the archive is successfully loaded. It is passed the ArchiveRquest and null on success or a javascript exception on failure.
returns: {!o3djs.io.LoadInfo} A LoadInfo for tracking progress.

  
  o3djs.io.loadArchiveAdvanced = function(pack,
                                          url,
                                          onFileAvailable,
                                          onFinished) {
    var error = 'loadArchive failed to load url "' + url + '"';
    var request = pack.createArchiveRequest();
    var loadInfo = o3djs.io.createLoadInfo(request, true);
    request.open('GET', url);
    request.onfileavailable = function() {
      onFileAvailable(request.data);
    };
    request.onreadystatechange = function() {
      if (request.done) {
        loadInfo.finish();
        var success = request.success;
        var exception = null;
        if (!success) {
          exception = request.error;
          if (!exception) {
            exception = 'unknown error loading archive';
          }
        }
        onFinished(request, exception);
      }
    };
    request.send();
    return loadInfo;
  };
  
  
Loads a texture. Textures are loaded asynchronously. Example: <pre> var loadInfo = o3djs.io.loadTexture(pack, 'http://google.com/someimage.jpg', callback); function callback(texture, exception) { if (!exception) { g_mySampler.texture = texture; } else { alert(exception); } } </pre>
parameter: {!o3d.Pack} pack Pack to load texture into.
parameter: {string} url URL of texture to load.
parameter: {!function(!o3d.Texture, *): void} callback Callback when texture is loaded. It will be passed the texture and an exception on error or null on success.
returns: {!o3djs.io.LoadInfo} A LoadInfo to track progress.
see: o3djs.io.createLoader

  
  o3djs.io.loadTexture = function(pack, url, callback) {
    // TODO: change this to get use RawData and Bitmap
    var request = pack.createFileRequest('TEXTURE');
    var loadInfo = o3djs.io.createLoadInfo(request, false);
    request.open('GET', url, true);
    request.onreadystatechange = function() {
      if (request.done) {
        var texture = request.texture;
        var success = request.success;
        var exception = request.error;
        loadInfo.finish();
        pack.removeObject(request);
        if (!success && !exception) {
            exception = 'unknown error loading texture';
        }
        callback(texture, success ? null : exception);
      }
    };
    request.send();
    return loadInfo;
  };
  
  


(C) Æliens 20/2/2008

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.