OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2010, 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 // TODO(kbr): figure out how we can reuse the o3djs.io package from |
| 33 // within here. |
| 34 // o3djs.require('o3djs.io'); |
| 35 |
| 36 // TODO(kbr): factor this out into e.g. o3djs.json and require |
| 37 // o3djs.json here. |
| 38 if(!this.JSON){this.JSON={};} |
| 39 (function(){function f(n){return n<10?'0'+n:n;} |
| 40 if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(key
){return isFinite(this.valueOf())?this.getUTCFullYear()+'-'+ |
| 41 f(this.getUTCMonth()+1)+'-'+ |
| 42 f(this.getUTCDate())+'T'+ |
| 43 f(this.getUTCHours())+':'+ |
| 44 f(this.getUTCMinutes())+':'+ |
| 45 f(this.getUTCSeconds())+'Z':null;};String.prototype.toJSON=Number.prototype.toJS
ON=Boolean.prototype.toJSON=function(key){return this.valueOf();};} |
| 46 var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u
2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600
-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uf
fff]/g,gap,indent,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','
"':'\\"','\\':'\\\\'},rep;function quote(string){escapable.lastIndex=0;return es
capable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];retu
rn typeof c==='string'?c:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4);}
)+'"':'"'+string+'"';} |
| 47 function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(
value&&typeof value==='object'&&typeof value.toJSON==='function'){value=value.to
JSON(key);} |
| 48 if(typeof rep==='function'){value=rep.call(holder,key,value);} |
| 49 switch(typeof value){case'string':return quote(value);case'number':return isFini
te(value)?String(value):'null';case'boolean':case'null':return String(value);cas
e'object':if(!value){return'null';} |
| 50 gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==='[object Arra
y]'){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||'null';
} |
| 51 v=partial.length===0?'[]':gap?'[\n'+gap+ |
| 52 partial.join(',\n'+gap)+'\n'+ |
| 53 mind+']':'['+partial.join(',')+']';gap=mind;return v;} |
| 54 if(rep&&typeof rep==='object'){length=rep.length;for(i=0;i<length;i+=1){k=rep[i]
;if(typeof k==='string'){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':
')+v);}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,v
alue);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}} |
| 55 v=partial.length===0?'{}':gap?'{\n'+gap+partial.join(',\n'+gap)+'\n'+ |
| 56 mind+'}':'{'+partial.join(',')+'}';gap=mind;return v;}} |
| 57 if(typeof JSON.stringify!=='function'){JSON.stringify=function(value,replacer,sp
ace){var i;gap='';indent='';if(typeof space==='number'){for(i=0;i<space;i+=1){in
dent+=' ';}}else if(typeof space==='string'){indent=space;} |
| 58 rep=replacer;if(replacer&&typeof replacer!=='function'&&(typeof replacer!=='obje
ct'||typeof replacer.length!=='number')){throw new Error('JSON.stringify');} |
| 59 return str('',{'':value});};} |
| 60 if(typeof JSON.parse!=='function'){JSON.parse=function(text,reviver){var j;funct
ion walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==='object'
){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!=
=undefined){value[k]=v;}else{delete value[k];}}}} |
| 61 return reviver.call(holder,key,value);} |
| 62 text=String(text);cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function
(a){return'\\u'+ |
| 63 ('0000'+a.charCodeAt(0).toString(16)).slice(-4);});} |
| 64 if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').
replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof reviver=
=='function'?walk({'':j},''):j;} |
| 65 throw new SyntaxError('JSON.parse');};}}()); |
| 66 |
| 67 |
| 68 /** |
| 69 An ArchiveRequest object is used to carry out an asynchronous request for a |
| 70 compressed archive (containing multiple files). |
| 71 |
| 72 Note: The archive must have as its first file a file named 'aaaaaaaa.o3d' |
| 73 who's contents is 'o3d'. This is to prevent O3D being used to open |
| 74 archive files that were not meant for it. |
| 75 |
| 76 \code |
| 77 var request = pack.createArchiveRequest(); |
| 78 request.open("GET", url); |
| 79 |
| 80 request.onfileavailable = myFileAvailableCallback; |
| 81 request.onreadystatechange = myReadyStateChangeCallback; |
| 82 request.send(); |
| 83 |
| 84 function myFileAvailableCallback(rawData) { |
| 85 dump("uri: " + rawData.uri + "\n"); |
| 86 dump("content: " + rawData.stringValue + "\n"); |
| 87 |
| 88 // You can pass a RawData to various creation functions. Note: rawData |
| 89 // is only valid until you remove the request. |
| 90 // Examples: |
| 91 if (rawData.uri == 'mytexture.jpg') |
| 92 pack.createTexture2d(rawData, makeMips); |
| 93 if (rawData.uri == 'myvertices.bin') |
| 94 vertexBuffer.set(rawData); |
| 95 if (rawData.uri == 'myAudio.mp3') |
| 96 audioSystem.createSound(rawData); |
| 97 } |
| 98 |
| 99 function myReadyStateChangeCallback() { |
| 100 if (request.done) { |
| 101 if (request.success) { |
| 102 // there were no errors trying to read the archive |
| 103 } else { |
| 104 dump(request.error); |
| 105 } |
| 106 } |
| 107 } |
| 108 |
| 109 // When you are done with the RawDatas loaded by the request, remove |
| 110 // the request from the pack to free them. |
| 111 pack.removeObject(request); |
| 112 */ |
| 113 |
| 114 o3d.ArchiveRequest = function() { |
| 115 o3d.ObjectBase.call(this); |
| 116 this.method_ = null; |
| 117 }; |
| 118 o3d.inherit('ArchiveRequest', 'ObjectBase'); |
| 119 |
| 120 /** |
| 121 * The URI this request is for. |
| 122 * @type {string} |
| 123 */ |
| 124 o3d.ArchiveRequest.prototype.uri = ''; |
| 125 |
| 126 /** |
| 127 * Set up several of the request fields. |
| 128 * @param {string} method "GET" is the only supported method at this time |
| 129 * @param {string} uri the location of the file to fetch |
| 130 * @param {boolean} async true is the only legal value at this time. |
| 131 */ |
| 132 o3d.ArchiveRequest.prototype.open = |
| 133 function(method, uri) { |
| 134 this.uri = uri; |
| 135 |
| 136 // Compute the parent directory of this URI. |
| 137 var parentURI = uri; |
| 138 var lastSlash = uri.lastIndexOf('/'); |
| 139 if (lastSlash != -1) { |
| 140 parentURI = parentURI.substring(0, lastSlash + 1); |
| 141 } |
| 142 |
| 143 this.parentURI_ = parentURI; |
| 144 }; |
| 145 |
| 146 /** |
| 147 * Send the request. |
| 148 * Unlike XMLHttpRequest the onreadystatechange callback will be called no |
| 149 * matter what, with success or failure. |
| 150 */ |
| 151 o3d.ArchiveRequest.prototype.send = function() { |
| 152 var that = this; |
| 153 this.done = false; |
| 154 this.success = true; |
| 155 this.error = null; |
| 156 var callback = function(sourceJSON, exc) { |
| 157 // Don't send down the original scene.json because 'eval' is used |
| 158 // elsewhere to reconstitute it, which is risky. |
| 159 var filteredJSON = JSON.stringify(JSON.parse(sourceJSON)); |
| 160 |
| 161 if (that.onfileavailable) { |
| 162 var rawData = new o3d.RawData(); |
| 163 rawData.uri = 'scene.json'; |
| 164 rawData.stringValue = filteredJSON; |
| 165 that.onfileavailable(rawData); |
| 166 } |
| 167 |
| 168 // In o3d-webgl, the "archive" is really just the top-level |
| 169 // scene.json. We run a regexp on it to find URIs for certain |
| 170 // well-known file types (.fx, .png, .jpg) and issue file requests |
| 171 // for them. |
| 172 var uriRegex = /\"([^\"]*\.(fx|png|jpg))\"/g; |
| 173 var matchArray; |
| 174 var uris = []; |
| 175 while ((matchArray = uriRegex.exec(sourceJSON)) != null) { |
| 176 uris.push(matchArray[1]); |
| 177 } |
| 178 |
| 179 that.pendingRequests_ = uris.length; |
| 180 |
| 181 // Issue requests for each of these URIs. |
| 182 for (var ii = 0; ii < uris.length; ++ii) { |
| 183 if (that.stringEndsWith_(uris[ii], ".fx")) { |
| 184 var func = function(uri) { |
| 185 var completion = function(value, exc) { |
| 186 var rawData = null; |
| 187 if (exc == null) { |
| 188 rawData = new o3d.RawData(); |
| 189 rawData.uri = uri; |
| 190 rawData.stringValue = value; |
| 191 } |
| 192 that.decrementPendingRequests_(rawData, exc); |
| 193 }; |
| 194 o3djs.io.loadTextFile(that.relativeToAbsoluteURI_(uri), |
| 195 completion); |
| 196 }; |
| 197 func(uris[ii]); |
| 198 } else if (that.stringEndsWith_(uris[ii], ".png") || |
| 199 that.stringEndsWith_(uris[ii], ".jpg")) { |
| 200 var func = function(uri) { |
| 201 var image = new Image(); |
| 202 image.onload = function() { |
| 203 var rawData = new o3d.RawData(); |
| 204 rawData.uri = uri; |
| 205 rawData.image_ = image; |
| 206 that.decrementPendingRequests_(rawData, exc); |
| 207 }; |
| 208 image.onerror = function() { |
| 209 that.decrementPendingRequests_(null, exc); |
| 210 } |
| 211 image.src = that.relativeToAbsoluteURI_(uri); |
| 212 }; |
| 213 func(uris[ii]); |
| 214 } |
| 215 } |
| 216 }; |
| 217 |
| 218 o3djs.io.loadTextFile(this.uri, callback); |
| 219 }; |
| 220 |
| 221 /** |
| 222 * A callback to call whenever the ready state of the request changes. |
| 223 * @type {function(): void} |
| 224 */ |
| 225 o3d.ArchiveRequest.prototype.onreadystatechange = null; |
| 226 |
| 227 /** |
| 228 * A callback to call when each file comes in. |
| 229 * @type {function(!o3d.RawData): void} |
| 230 */ |
| 231 o3d.ArchiveRequest.prototype.onfileavailable = null; |
| 232 |
| 233 /** |
| 234 * Converts a local URI to an absolute URI. |
| 235 * @private |
| 236 */ |
| 237 o3d.ArchiveRequest.prototype.relativeToAbsoluteURI_ = function(relativeURI) { |
| 238 return this.parentURI_ + relativeURI; |
| 239 }; |
| 240 |
| 241 /** |
| 242 * Indicates whether one string ends with another. |
| 243 * @private |
| 244 */ |
| 245 o3d.ArchiveRequest.prototype.stringEndsWith_ = function(string, suffix) { |
| 246 return string.substring(string.length - suffix.length) == suffix; |
| 247 }; |
| 248 |
| 249 /** |
| 250 * Decrements the number of pending requests. |
| 251 * @private |
| 252 */ |
| 253 o3d.ArchiveRequest.prototype.decrementPendingRequests_ = |
| 254 function(rawData, opt_exc) { |
| 255 this.success = this.success && rawData && (!opt_exc); |
| 256 if (opt_exc != null) { |
| 257 this.error = "" + opt_exc; |
| 258 } |
| 259 if (rawData && this.onfileavailable) { |
| 260 this.onfileavailable(rawData); |
| 261 } |
| 262 if (--this.pendingRequests_ == 0) { |
| 263 this.done = true; |
| 264 if (this.onreadystatechange) { |
| 265 this.onreadystatechange(); |
| 266 } |
| 267 } |
| 268 }; |
OLD | NEW |