Loader.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999
  1. /**
  2. * @author alteredq / http://alteredqualia.com/
  3. */
  4. THREE.Loader = function() {
  5. };
  6. THREE.Loader.prototype = {
  7. // Load models generated by Blender exporter and original OBJ converter (converter_obj_three.py)
  8. loadAsciiOld: function( url, callback ) {
  9. var element = document.createElement( 'script' );
  10. element.type = 'text/javascript';
  11. element.onload = callback;
  12. element.src = url;
  13. document.getElementsByTagName( "head" )[ 0 ].appendChild( element );
  14. },
  15. // Load models generated by slim OBJ converter with ASCII option (converter_obj_three_slim.py -t ascii)
  16. // - urlbase parameter is optional (it only applies to models with textures)
  17. loadAscii: function ( url, callback, urlbase ) {
  18. var s = (new Date).getTime(),
  19. worker = new Worker( url );
  20. worker.onmessage = function( event ) {
  21. THREE.Loader.prototype.createModel( event.data, callback, urlbase );
  22. };
  23. worker.postMessage( s );
  24. },
  25. // Load models generated by slim OBJ converter with BINARY option (converter_obj_three_slim.py -t binary)
  26. // - urlbase parameter is mandatory (it applies to all models, it tells where to find the file with binary buffers)
  27. // - binary models consist of two files: JS and BIN
  28. loadBinary: function( url, callback, urlbase ) {
  29. // #1 load JS part via web worker
  30. // This isn't really necessary, JS part is tiny,
  31. // could be done by more ordinary means.
  32. var s = (new Date).getTime(),
  33. worker = new Worker( url );
  34. worker.onmessage = function( event ) {
  35. var materials = event.data.materials,
  36. buffers = event.data.buffers;
  37. // #2 load BIN part via Ajax
  38. // For some reason it is faster doing loading from here than from within the worker.
  39. // Maybe passing of ginormous string as message between threads is costly?
  40. // Also, worker loading huge data by Ajax still freezes browser. Go figure,
  41. // worker with baked ascii JSON data keeps browser more responsive.
  42. THREE.Loader.prototype.loadAjaxBuffers( buffers, materials, callback, urlbase );
  43. };
  44. worker.onerror = function (event) {
  45. alert( "worker.onerror: " + event.message + "\n" + event.data );
  46. event.preventDefault();
  47. };
  48. worker.postMessage( s );
  49. },
  50. // Binary AJAX parser based on Magi binary loader
  51. // https://github.com/kig/magi
  52. // Should look more into HTML5 File API
  53. // See also other suggestions by Gregg Tavares
  54. // https://groups.google.com/group/o3d-discuss/browse_thread/thread/a8967bc9ce1e0978
  55. loadAjaxBuffers: function( buffers, materials, callback, urlbase ) {
  56. var xhr = new XMLHttpRequest(),
  57. url = urlbase + "/" + buffers;
  58. xhr.onreadystatechange = function() {
  59. if ( xhr.readyState == 4 ) {
  60. if ( xhr.status == 200 || xhr.status == 0 ) {
  61. THREE.Loader.prototype.createBinModel( xhr.responseText, callback, urlbase, materials );
  62. } else {
  63. alert( "Couldn't load [" + url + "] [" + xhr.status + "]" );
  64. }
  65. }
  66. }
  67. xhr.open("GET", url, true);
  68. xhr.overrideMimeType("text/plain; charset=x-user-defined");
  69. xhr.setRequestHeader("Content-Type", "text/plain");
  70. xhr.send(null);
  71. },
  72. createBinModel: function ( data, callback, urlbase, materials ) {
  73. var Model = function ( urlbase ) {
  74. //var s = (new Date).getTime();
  75. var scope = this,
  76. currentOffset = 0,
  77. md,
  78. normals = [],
  79. uvs = [],
  80. tri_b, tri_c, tri_m, tri_na, tri_nb, tri_nc,
  81. quad_b, quad_c, quad_d, quad_m, quad_na, quad_nb, quad_nc, quad_nd,
  82. tri_uvb, tri_uvc, quad_uvb, quad_uvc, quad_uvd;
  83. THREE.Geometry.call(this);
  84. THREE.Loader.prototype.init_materials( scope, materials, urlbase );
  85. md = parseMetaData( data, currentOffset );
  86. currentOffset += md.header_bytes;
  87. // cache offsets
  88. tri_b = md.vertex_index_bytes,
  89. tri_c = md.vertex_index_bytes*2,
  90. tri_m = md.vertex_index_bytes*3,
  91. tri_na = md.vertex_index_bytes*3 + md.material_index_bytes,
  92. tri_nb = md.vertex_index_bytes*3 + md.material_index_bytes + md.normal_index_bytes,
  93. tri_nc = md.vertex_index_bytes*3 + md.material_index_bytes + md.normal_index_bytes*2,
  94. quad_b = md.vertex_index_bytes,
  95. quad_c = md.vertex_index_bytes*2,
  96. quad_d = md.vertex_index_bytes*3,
  97. quad_m = md.vertex_index_bytes*4,
  98. quad_na = md.vertex_index_bytes*4 + md.material_index_bytes,
  99. quad_nb = md.vertex_index_bytes*4 + md.material_index_bytes + md.normal_index_bytes,
  100. quad_nc = md.vertex_index_bytes*4 + md.material_index_bytes + md.normal_index_bytes*2,
  101. quad_nd = md.vertex_index_bytes*4 + md.material_index_bytes + md.normal_index_bytes*3,
  102. tri_uvb = md.uv_index_bytes,
  103. tri_uvc = md.uv_index_bytes * 2,
  104. quad_uvb = md.uv_index_bytes,
  105. quad_uvc = md.uv_index_bytes * 2,
  106. quad_uvd = md.uv_index_bytes * 3;
  107. currentOffset += init_vertices( currentOffset );
  108. currentOffset += init_normals( currentOffset );
  109. currentOffset += init_uvs( currentOffset );
  110. currentOffset += init_triangles_flat( currentOffset );
  111. currentOffset += init_triangles_smooth( currentOffset );
  112. currentOffset += init_triangles_flat_uv( currentOffset );
  113. currentOffset += init_triangles_smooth_uv( currentOffset );
  114. currentOffset += init_quads_flat( currentOffset );
  115. currentOffset += init_quads_smooth( currentOffset );
  116. currentOffset += init_quads_flat_uv( currentOffset );
  117. currentOffset += init_quads_smooth_uv( currentOffset );
  118. this.computeCentroids();
  119. this.computeNormals();
  120. //var e = (new Date).getTime();
  121. //log( "binary data parse time: " + (e-s) + " ms" );
  122. function parseMetaData( data, offset ) {
  123. var metaData = {
  124. 'signature' :parseString( data, offset, 8 ),
  125. 'header_bytes' :parseUChar8( data, offset + 8 ),
  126. 'vertex_coordinate_bytes' :parseUChar8( data, offset + 9 ),
  127. 'normal_coordinate_bytes' :parseUChar8( data, offset + 10 ),
  128. 'uv_coordinate_bytes' :parseUChar8( data, offset + 11 ),
  129. 'vertex_index_bytes' :parseUChar8( data, offset + 12 ),
  130. 'normal_index_bytes' :parseUChar8( data, offset + 13 ),
  131. 'uv_index_bytes' :parseUChar8( data, offset + 14 ),
  132. 'material_index_bytes' :parseUChar8( data, offset + 15 ),
  133. 'nvertices' :parseUInt32( data, offset + 16 ),
  134. 'nnormals' :parseUInt32( data, offset + 16 + 4*1 ),
  135. 'nuvs' :parseUInt32( data, offset + 16 + 4*2 ),
  136. 'ntri_flat' :parseUInt32( data, offset + 16 + 4*3 ),
  137. 'ntri_smooth' :parseUInt32( data, offset + 16 + 4*4 ),
  138. 'ntri_flat_uv' :parseUInt32( data, offset + 16 + 4*5 ),
  139. 'ntri_smooth_uv' :parseUInt32( data, offset + 16 + 4*6 ),
  140. 'nquad_flat' :parseUInt32( data, offset + 16 + 4*7 ),
  141. 'nquad_smooth' :parseUInt32( data, offset + 16 + 4*8 ),
  142. 'nquad_flat_uv' :parseUInt32( data, offset + 16 + 4*9 ),
  143. 'nquad_smooth_uv' :parseUInt32( data, offset + 16 + 4*10 )
  144. };
  145. /*
  146. log( "signature: " + metaData.signature );
  147. log( "header_bytes: " + metaData.header_bytes );
  148. log( "vertex_coordinate_bytes: " + metaData.vertex_coordinate_bytes );
  149. log( "normal_coordinate_bytes: " + metaData.normal_coordinate_bytes );
  150. log( "uv_coordinate_bytes: " + metaData.uv_coordinate_bytes );
  151. log( "vertex_index_bytes: " + metaData.vertex_index_bytes );
  152. log( "normal_index_bytes: " + metaData.normal_index_bytes );
  153. log( "uv_index_bytes: " + metaData.uv_index_bytes );
  154. log( "material_index_bytes: " + metaData.material_index_bytes );
  155. log( "nvertices: " + metaData.nvertices );
  156. log( "nnormals: " + metaData.nnormals );
  157. log( "nuvs: " + metaData.nuvs );
  158. log( "ntri_flat: " + metaData.ntri_flat );
  159. log( "ntri_smooth: " + metaData.ntri_smooth );
  160. log( "ntri_flat_uv: " + metaData.ntri_flat_uv );
  161. log( "ntri_smooth_uv: " + metaData.ntri_smooth_uv );
  162. log( "nquad_flat: " + metaData.nquad_flat );
  163. log( "nquad_smooth: " + metaData.nquad_smooth );
  164. log( "nquad_flat_uv: " + metaData.nquad_flat_uv );
  165. log( "nquad_smooth_uv: " + metaData.nquad_smooth_uv );
  166. var total = metaData.header_bytes
  167. + metaData.nvertices * metaData.vertex_coordinate_bytes * 3
  168. + metaData.nnormals * metaData.normal_coordinate_bytes * 3
  169. + metaData.nuvs * metaData.uv_coordinate_bytes * 2
  170. + metaData.ntri_flat * ( metaData.vertex_index_bytes*3 + metaData.material_index_bytes )
  171. + metaData.ntri_smooth * ( metaData.vertex_index_bytes*3 + metaData.material_index_bytes + metaData.normal_index_bytes*3 )
  172. + metaData.ntri_flat_uv * ( metaData.vertex_index_bytes*3 + metaData.material_index_bytes + metaData.uv_index_bytes*3 )
  173. + metaData.ntri_smooth_uv * ( metaData.vertex_index_bytes*3 + metaData.material_index_bytes + metaData.normal_index_bytes*3 + metaData.uv_index_bytes*3 )
  174. + metaData.nquad_flat * ( metaData.vertex_index_bytes*4 + metaData.material_index_bytes )
  175. + metaData.nquad_smooth * ( metaData.vertex_index_bytes*4 + metaData.material_index_bytes + metaData.normal_index_bytes*4 )
  176. + metaData.nquad_flat_uv * ( metaData.vertex_index_bytes*4 + metaData.material_index_bytes + metaData.uv_index_bytes*4 )
  177. + metaData.nquad_smooth_uv * ( metaData.vertex_index_bytes*4 + metaData.material_index_bytes + metaData.normal_index_bytes*4 + metaData.uv_index_bytes*4 );
  178. log( "total bytes: " + total );
  179. */
  180. return metaData;
  181. }
  182. function parseString( data, offset, length ) {
  183. return data.substr( offset, length );
  184. }
  185. function parseFloat32( data, offset ) {
  186. var b3 = parseUChar8( data, offset ),
  187. b2 = parseUChar8( data, offset + 1 ),
  188. b1 = parseUChar8( data, offset + 2 ),
  189. b0 = parseUChar8( data, offset + 3 ),
  190. sign = 1 - ( 2 * ( b0 >> 7 ) ),
  191. exponent = ((( b0 << 1 ) & 0xff) | ( b1 >> 7 )) - 127,
  192. mantissa = (( b1 & 0x7f ) << 16) | (b2 << 8) | b3;
  193. if (mantissa == 0 && exponent == -127)
  194. return 0.0;
  195. return sign * ( 1 + mantissa * Math.pow( 2, -23 ) ) * Math.pow( 2, exponent );
  196. }
  197. function parseUInt32( data, offset ) {
  198. var b0 = parseUChar8( data, offset ),
  199. b1 = parseUChar8( data, offset + 1 ),
  200. b2 = parseUChar8( data, offset + 2 ),
  201. b3 = parseUChar8( data, offset + 3 );
  202. return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
  203. }
  204. function parseUInt16( data, offset ) {
  205. var b0 = parseUChar8( data, offset ),
  206. b1 = parseUChar8( data, offset + 1 );
  207. return (b1 << 8) + b0;
  208. }
  209. function parseSChar8( data, offset ) {
  210. var b = parseUChar8( data, offset );
  211. return b > 127 ? b - 256 : b;
  212. }
  213. function parseUChar8( data, offset ) {
  214. return data.charCodeAt( offset ) & 0xff;
  215. }
  216. function init_vertices( start ) {
  217. var i, x, y, z,
  218. stride = md.vertex_coordinate_bytes * 3,
  219. end = start + md.nvertices * stride;
  220. for( i = start; i < end; i += stride ) {
  221. x = parseFloat32( data, i );
  222. y = parseFloat32( data, i + md.vertex_coordinate_bytes );
  223. z = parseFloat32( data, i + md.vertex_coordinate_bytes*2 );
  224. THREE.Loader.prototype.v( scope, x, y, z );
  225. }
  226. return md.nvertices * stride;
  227. }
  228. function init_normals( start ) {
  229. var i, x, y, z,
  230. stride = md.normal_coordinate_bytes * 3,
  231. end = start + md.nnormals * stride;
  232. for( i = start; i < end; i += stride ) {
  233. x = parseSChar8( data, i );
  234. y = parseSChar8( data, i + md.normal_coordinate_bytes );
  235. z = parseSChar8( data, i + md.normal_coordinate_bytes*2 );
  236. normals.push( x/127, y/127, z/127 );
  237. }
  238. return md.nnormals * stride;
  239. }
  240. function init_uvs( start ) {
  241. var i, u, v,
  242. stride = md.uv_coordinate_bytes * 2,
  243. end = start + md.nuvs * stride;
  244. for( i = start; i < end; i += stride ) {
  245. u = parseFloat32( data, i );
  246. v = parseFloat32( data, i + md.uv_coordinate_bytes );
  247. uvs.push( u, v );
  248. }
  249. return md.nuvs * stride;
  250. }
  251. function add_tri( i ) {
  252. var a, b, c, m;
  253. a = parseUInt32( data, i );
  254. b = parseUInt32( data, i + tri_b );
  255. c = parseUInt32( data, i + tri_c );
  256. m = parseUInt16( data, i + tri_m );
  257. THREE.Loader.prototype.f3( scope, a, b, c, m );
  258. }
  259. function add_tri_n( i ) {
  260. var a, b, c, m, na, nb, nc;
  261. a = parseUInt32( data, i );
  262. b = parseUInt32( data, i + tri_b );
  263. c = parseUInt32( data, i + tri_c );
  264. m = parseUInt16( data, i + tri_m );
  265. na = parseUInt32( data, i + tri_na );
  266. nb = parseUInt32( data, i + tri_nb );
  267. nc = parseUInt32( data, i + tri_nc );
  268. THREE.Loader.prototype.f3n( scope, normals, a, b, c, m, na, nb, nc );
  269. }
  270. function add_quad( i ) {
  271. var a, b, c, d, m;
  272. a = parseUInt32( data, i );
  273. b = parseUInt32( data, i + quad_b );
  274. c = parseUInt32( data, i + quad_c );
  275. d = parseUInt32( data, i + quad_d );
  276. m = parseUInt16( data, i + quad_m );
  277. THREE.Loader.prototype.f4( scope, a, b, c, d, m );
  278. }
  279. function add_quad_n( i ) {
  280. var a, b, c, d, m, na, nb, nc, nd;
  281. a = parseUInt32( data, i );
  282. b = parseUInt32( data, i + quad_b );
  283. c = parseUInt32( data, i + quad_c );
  284. d = parseUInt32( data, i + quad_d );
  285. m = parseUInt16( data, i + quad_m );
  286. na = parseUInt32( data, i + quad_na );
  287. nb = parseUInt32( data, i + quad_nb );
  288. nc = parseUInt32( data, i + quad_nc );
  289. nd = parseUInt32( data, i + quad_nd );
  290. THREE.Loader.prototype.f4n( scope, normals, a, b, c, d, m, na, nb, nc, nd );
  291. }
  292. function add_uv3( i ) {
  293. var uva, uvb, uvc, u1, u2, u3, v1, v2, v3;
  294. uva = parseUInt32( data, i );
  295. uvb = parseUInt32( data, i + tri_uvb );
  296. uvc = parseUInt32( data, i + tri_uvc );
  297. u1 = uvs[ uva*2 ];
  298. v1 = uvs[ uva*2 + 1 ];
  299. u2 = uvs[ uvb*2 ];
  300. v2 = uvs[ uvb*2 + 1 ];
  301. u3 = uvs[ uvc*2 ];
  302. v3 = uvs[ uvc*2 + 1 ];
  303. THREE.Loader.prototype.uv( scope, u1, v1, u2, v2, u3, v3 );
  304. }
  305. function add_uv4( i ) {
  306. var uva, uvb, uvc, uvd, u1, u2, u3, u4, v1, v2, v3, v4;
  307. uva = parseUInt32( data, i );
  308. uvb = parseUInt32( data, i + quad_uvb );
  309. uvc = parseUInt32( data, i + quad_uvc );
  310. uvd = parseUInt32( data, i + quad_uvd );
  311. u1 = uvs[ uva*2 ];
  312. v1 = uvs[ uva*2 + 1 ];
  313. u2 = uvs[ uvb*2 ];
  314. v2 = uvs[ uvb*2 + 1 ];
  315. u3 = uvs[ uvc*2 ];
  316. v3 = uvs[ uvc*2 + 1 ];
  317. u4 = uvs[ uvd*2 ];
  318. v4 = uvs[ uvd*2 + 1 ];
  319. THREE.Loader.prototype.uv( scope, u1, v1, u2, v2, u3, v3, u4, v4 );
  320. }
  321. function init_triangles_flat( start ) {
  322. var i, stride = md.vertex_index_bytes * 3 + md.material_index_bytes,
  323. end = start + md.ntri_flat * stride;
  324. for( i = start; i < end; i += stride ) {
  325. add_tri( i );
  326. }
  327. return end - start;
  328. }
  329. function init_triangles_flat_uv( start ) {
  330. var i, offset = md.vertex_index_bytes * 3 + md.material_index_bytes,
  331. stride = offset + md.uv_index_bytes * 3,
  332. end = start + md.ntri_flat_uv * stride;
  333. for( i = start; i < end; i += stride ) {
  334. add_tri( i );
  335. add_uv3( i + offset );
  336. }
  337. return end - start;
  338. }
  339. function init_triangles_smooth( start ) {
  340. var i, stride = md.vertex_index_bytes * 3 + md.material_index_bytes + md.normal_index_bytes * 3,
  341. end = start + md.ntri_smooth * stride;
  342. for( i = start; i < end; i += stride ) {
  343. add_tri_n( i );
  344. }
  345. return end - start;
  346. }
  347. function init_triangles_smooth_uv( start ) {
  348. var i, offset = md.vertex_index_bytes * 3 + md.material_index_bytes + md.normal_index_bytes * 3,
  349. stride = offset + md.uv_index_bytes * 3,
  350. end = start + md.ntri_smooth_uv * stride;
  351. for( i = start; i < end; i += stride ) {
  352. add_tri_n( i );
  353. add_uv3( i + offset );
  354. }
  355. return end - start;
  356. }
  357. function init_quads_flat( start ) {
  358. var i, stride = md.vertex_index_bytes * 4 + md.material_index_bytes,
  359. end = start + md.nquad_flat * stride;
  360. for( i = start; i < end; i += stride ) {
  361. add_quad( i );
  362. }
  363. return end - start;
  364. }
  365. function init_quads_flat_uv( start ) {
  366. var i, offset = md.vertex_index_bytes * 4 + md.material_index_bytes,
  367. stride = offset + md.uv_index_bytes * 4,
  368. end = start + md.nquad_flat_uv * stride;
  369. for( i = start; i < end; i += stride ) {
  370. add_quad( i );
  371. add_uv4( i + offset );
  372. }
  373. return end - start;
  374. }
  375. function init_quads_smooth( start ) {
  376. var i, stride = md.vertex_index_bytes * 4 + md.material_index_bytes + md.normal_index_bytes * 4,
  377. end = start + md.nquad_smooth * stride;
  378. for( i = start; i < end; i += stride ) {
  379. add_quad_n( i );
  380. }
  381. return end - start;
  382. }
  383. function init_quads_smooth_uv( start ) {
  384. var i, offset = md.vertex_index_bytes * 4 + md.material_index_bytes + md.normal_index_bytes * 4,
  385. stride = offset + md.uv_index_bytes * 4,
  386. end = start + md.nquad_smooth_uv * stride;
  387. for( i = start; i < end; i += stride ) {
  388. add_quad_n( i );
  389. add_uv4( i + offset );
  390. }
  391. return end - start;
  392. }
  393. }
  394. Model.prototype = new THREE.Geometry();
  395. Model.prototype.constructor = Model;
  396. callback( new Model( urlbase ) );
  397. },
  398. createModel: function ( data, callback, urlbase ) {
  399. var Model = function ( urlbase ) {
  400. var scope = this;
  401. THREE.Geometry.call(this);
  402. THREE.Loader.prototype.init_materials( scope, data.materials, urlbase );
  403. init_vertices();
  404. init_faces();
  405. this.computeCentroids();
  406. this.computeNormals();
  407. function init_vertices() {
  408. var i, l, x, y, z;
  409. for( i = 0, l = data.vertices.length; i < l; i += 3 ) {
  410. x = data.vertices[ i ];
  411. y = data.vertices[ i + 1 ];
  412. z = data.vertices[ i + 2 ];
  413. THREE.Loader.prototype.v( scope, x, y, z );
  414. }
  415. }
  416. function init_faces() {
  417. function add_tri( src, i ) {
  418. var a, b, c, m;
  419. a = src[ i ];
  420. b = src[ i + 1 ];
  421. c = src[ i + 2 ];
  422. m = src[ i + 3 ];
  423. THREE.Loader.prototype.f3( scope, a, b, c, m );
  424. }
  425. function add_tri_n( src, i ) {
  426. var a, b, c, m, na, nb, nc;
  427. a = src[ i ];
  428. b = src[ i + 1 ];
  429. c = src[ i + 2 ];
  430. m = src[ i + 3 ];
  431. na = src[ i + 4 ];
  432. nb = src[ i + 5 ];
  433. nc = src[ i + 6 ];
  434. THREE.Loader.prototype.f3n( scope, data.normals, a, b, c, m, na, nb, nc );
  435. }
  436. function add_quad( src, i ) {
  437. var a, b, c, d, m;
  438. a = src[ i ];
  439. b = src[ i + 1 ];
  440. c = src[ i + 2 ];
  441. d = src[ i + 3 ];
  442. m = src[ i + 4 ];
  443. THREE.Loader.prototype.f4( scope, a, b, c, d, m );
  444. }
  445. function add_quad_n( src, i ) {
  446. var a, b, c, d, m, na, nb, nc, nd;
  447. a = src[ i ];
  448. b = src[ i + 1 ];
  449. c = src[ i + 2 ];
  450. d = src[ i + 3 ];
  451. m = src[ i + 4 ];
  452. na = src[ i + 5 ];
  453. nb = src[ i + 6 ];
  454. nc = src[ i + 7 ];
  455. nd = src[ i + 8 ];
  456. THREE.Loader.prototype.f4n( scope, data.normals, a, b, c, d, m, na, nb, nc, nd );
  457. }
  458. function add_uv3( src, i ) {
  459. var uva, uvb, uvc, u1, u2, u3, v1, v2, v3;
  460. uva = src[ i ];
  461. uvb = src[ i + 1 ];
  462. uvc = src[ i + 2 ];
  463. u1 = data.uvs[ uva * 2 ];
  464. v1 = data.uvs[ uva * 2 + 1 ];
  465. u2 = data.uvs[ uvb * 2 ];
  466. v2 = data.uvs[ uvb * 2 + 1 ];
  467. u3 = data.uvs[ uvc * 2 ];
  468. v3 = data.uvs[ uvc * 2 + 1 ];
  469. THREE.Loader.prototype.uv( scope, u1, v1, u2, v2, u3, v3 );
  470. }
  471. function add_uv4( src, i ) {
  472. var uva, uvb, uvc, uvd, u1, u2, u3, u4, v1, v2, v3, v4;
  473. uva = src[ i ];
  474. uvb = src[ i + 1 ];
  475. uvc = src[ i + 2 ];
  476. uvd = src[ i + 3 ];
  477. u1 = data.uvs[ uva * 2 ];
  478. v1 = data.uvs[ uva * 2 + 1 ];
  479. u2 = data.uvs[ uvb * 2 ];
  480. v2 = data.uvs[ uvb * 2 + 1 ];
  481. u3 = data.uvs[ uvc * 2 ];
  482. v3 = data.uvs[ uvc * 2 + 1 ];
  483. u4 = data.uvs[ uvd * 2 ];
  484. v4 = data.uvs[ uvd * 2 + 1 ];
  485. THREE.Loader.prototype.uv( scope, u1, v1, u2, v2, u3, v3, u4, v4 );
  486. }
  487. var i, l;
  488. for ( i = 0, l = data.triangles.length; i < l; i += 4 ) {
  489. add_tri( data.triangles, i );
  490. }
  491. for ( i = 0, l = data.triangles_uv.length; i < l; i+= 7 ) {
  492. add_tri( data.triangles_uv, i );
  493. add_uv3( data.triangles_uv, i + 4 );
  494. }
  495. for ( i = 0, l = data.triangles_n.length; i < l; i += 7 ) {
  496. add_tri_n( data.triangles_n, i );
  497. }
  498. for ( i = 0, l = data.triangles_n_uv.length; i < l; i += 10 ) {
  499. add_tri_n( data.triangles_n_uv, i );
  500. add_uv3( data.triangles_n_uv, i + 7 );
  501. }
  502. for ( i = 0, l = data.quads.length; i < l; i += 5 ) {
  503. add_quad( data.quads, i );
  504. }
  505. for ( i = 0, l = data.quads_uv.length; i < l; i += 9 ) {
  506. add_quad( data.quads_uv, i );
  507. add_uv4( data.quads_uv, i + 5 );
  508. }
  509. for ( i = 0, l = data.quads_n.length; i < l; i += 9 ) {
  510. add_quad_n( data.quads_n, i );
  511. }
  512. for ( i = 0, l = data.quads_n_uv.length; i < l; i += 13 ) {
  513. add_quad_n( data.quads_n_uv, i );
  514. add_uv4( data.quads_n_uv, i + 9 );
  515. }
  516. }
  517. }
  518. Model.prototype = new THREE.Geometry();
  519. Model.prototype.constructor = Model;
  520. callback( new Model( urlbase ) );
  521. },
  522. v: function( scope, x, y, z ) {
  523. scope.vertices.push( new THREE.Vertex( new THREE.Vector3( x, y, z ) ) );
  524. },
  525. f3: function( scope, a, b, c, mi ) {
  526. var material = scope.materials[ mi ];
  527. scope.faces.push( new THREE.Face3( a, b, c, null, material ) );
  528. },
  529. f4: function( scope, a, b, c, d, mi ) {
  530. var material = scope.materials[ mi ];
  531. scope.faces.push( new THREE.Face4( a, b, c, d, null, material ) );
  532. },
  533. f3n: function( scope, normals, a, b, c, mi, na, nb, nc ) {
  534. var material = scope.materials[ mi ],
  535. nax = normals[ na*3 ],
  536. nay = normals[ na*3 + 1 ],
  537. naz = normals[ na*3 + 2 ],
  538. nbx = normals[ nb*3 ],
  539. nby = normals[ nb*3 + 1 ],
  540. nbz = normals[ nb*3 + 2 ],
  541. ncx = normals[ nc*3 ],
  542. ncy = normals[ nc*3 + 1 ],
  543. ncz = normals[ nc*3 + 2 ];
  544. scope.faces.push( new THREE.Face3( a, b, c,
  545. [new THREE.Vector3( nax, nay, naz ),
  546. new THREE.Vector3( nbx, nby, nbz ),
  547. new THREE.Vector3( ncx, ncy, ncz )],
  548. material ) );
  549. },
  550. f4n: function( scope, normals, a, b, c, d, mi, na, nb, nc, nd ) {
  551. var material = scope.materials[ mi ],
  552. nax = normals[ na*3 ],
  553. nay = normals[ na*3 + 1 ],
  554. naz = normals[ na*3 + 2 ],
  555. nbx = normals[ nb*3 ],
  556. nby = normals[ nb*3 + 1 ],
  557. nbz = normals[ nb*3 + 2 ],
  558. ncx = normals[ nc*3 ],
  559. ncy = normals[ nc*3 + 1 ],
  560. ncz = normals[ nc*3 + 2 ],
  561. ndx = normals[ nd*3 ],
  562. ndy = normals[ nd*3 + 1 ],
  563. ndz = normals[ nd*3 + 2 ];
  564. scope.faces.push( new THREE.Face4( a, b, c, d,
  565. [new THREE.Vector3( nax, nay, naz ),
  566. new THREE.Vector3( nbx, nby, nbz ),
  567. new THREE.Vector3( ncx, ncy, ncz ),
  568. new THREE.Vector3( ndx, ndy, ndz )],
  569. material ) );
  570. },
  571. uv: function( scope, u1, v1, u2, v2, u3, v3, u4, v4 ) {
  572. var uv = [];
  573. uv.push( new THREE.UV( u1, v1 ) );
  574. uv.push( new THREE.UV( u2, v2 ) );
  575. uv.push( new THREE.UV( u3, v3 ) );
  576. if ( u4 && v4 ) uv.push( new THREE.UV( u4, v4 ) );
  577. scope.uvs.push( uv );
  578. },
  579. init_materials: function( scope, materials, urlbase ) {
  580. scope.materials = [];
  581. for ( var i = 0; i < materials.length; ++i ) {
  582. scope.materials[i] = [ THREE.Loader.prototype.createMaterial( materials[i], urlbase ) ];
  583. }
  584. },
  585. createMaterial: function ( m, urlbase ) {
  586. function is_pow2( n ) {
  587. var l = Math.log(n) / Math.LN2;
  588. return Math.floor(l) == l;
  589. }
  590. function nearest_pow2( n ) {
  591. var l = Math.log(n) / Math.LN2;
  592. return Math.pow( 2, Math.round(l) );
  593. }
  594. var material, texture, image, color;
  595. if ( m.map_diffuse && urlbase ) {
  596. texture = document.createElement( 'canvas' );
  597. material = new THREE.MeshBitmapMaterial( texture );
  598. image = new Image();
  599. image.onload = function () {
  600. if ( !is_pow2( this.width ) || !is_pow2( this.height ) ) {
  601. var w = nearest_pow2( this.width ),
  602. h = nearest_pow2( this.height );
  603. material.bitmap.width = w;
  604. material.bitmap.height = h;
  605. material.bitmap.getContext("2d").drawImage( this, 0, 0, w, h );
  606. } else {
  607. material.bitmap = this;
  608. }
  609. material.loaded = 1;
  610. };
  611. image.src = urlbase + "/" + m.map_diffuse;
  612. } else if ( m.col_diffuse ) {
  613. color = (m.col_diffuse[0]*255 << 16) + (m.col_diffuse[1]*255 << 8) + m.col_diffuse[2]*255;
  614. material = new THREE.MeshColorFillMaterial( color, m.transparency );
  615. } else if ( m.a_dbg_color ) {
  616. material = new THREE.MeshColorFillMaterial( m.a_dbg_color );
  617. } else {
  618. material = new THREE.MeshColorFillMaterial( 0xeeeeee );
  619. }
  620. return material;
  621. }
  622. };