Loader.js 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228
  1. /**
  2. * @author alteredq / http://alteredqualia.com/
  3. */
  4. THREE.Loader = function( showStatus ) {
  5. this.showStatus = showStatus;
  6. this.statusDomElement = showStatus ? this.addStatusElement() : null;
  7. };
  8. THREE.Loader.prototype = {
  9. addStatusElement: function ( ) {
  10. var e = document.createElement( "div" );
  11. e.style.fontSize = "0.8em";
  12. e.style.textAlign = "left";
  13. e.style.background = "#b00";
  14. e.style.color = "#fff";
  15. e.style.width = "140px";
  16. e.style.padding = "0.25em 0.25em 0.25em 0.5em";
  17. e.style.position = "absolute";
  18. e.style.right = "0px";
  19. e.style.top = "0px";
  20. e.style.zIndex = 1000;
  21. e.innerHTML = "Loading ...";
  22. return e;
  23. },
  24. updateProgress: function ( progress ) {
  25. var message = "Loaded ";
  26. if ( progress.total ) {
  27. message += ( 100 * progress.loaded / progress.total ).toFixed(0) + "%";
  28. } else {
  29. message += ( progress.loaded / 1000 ).toFixed(2) + " KB";
  30. }
  31. this.statusDomElement.innerHTML = message;
  32. },
  33. // Load models generated by Blender exporter and original OBJ converter (converter_obj_three.py)
  34. loadAsciiOld: function( url, callback ) {
  35. var element = document.createElement( 'script' );
  36. element.type = 'text/javascript';
  37. element.onload = callback;
  38. element.src = url;
  39. document.getElementsByTagName( "head" )[ 0 ].appendChild( element );
  40. },
  41. // Load models generated by slim OBJ converter with ASCII option (converter_obj_three_slim.py -t ascii)
  42. // - parameters
  43. // - model (required)
  44. // - callback (required)
  45. // - texture_path (optional: if not specified, textures will be assumed to be in the same folder as JS model file)
  46. loadAscii: function ( parameters ) {
  47. var url = parameters.model,
  48. callback = parameters.callback,
  49. texture_path = parameters.texture_path ? parameters.texture_path : THREE.Loader.prototype.extractUrlbase( url ),
  50. s = (new Date).getTime(),
  51. worker = new Worker( url );
  52. worker.onmessage = function( event ) {
  53. THREE.Loader.prototype.createModel( event.data, callback, texture_path );
  54. };
  55. worker.postMessage( s );
  56. },
  57. // Load models generated by slim OBJ converter with BINARY option (converter_obj_three_slim.py -t binary)
  58. // - binary models consist of two files: JS and BIN
  59. // - parameters
  60. // - model (required)
  61. // - callback (required)
  62. // - bin_path (optional: if not specified, binary file will be assumed to be in the same folder as JS model file)
  63. // - texture_path (optional: if not specified, textures will be assumed to be in the same folder as JS model file)
  64. loadBinary: function( parameters ) {
  65. // #1 load JS part via web worker
  66. // This isn't really necessary, JS part is tiny,
  67. // could be done by more ordinary means.
  68. var url = parameters.model,
  69. callback = parameters.callback,
  70. texture_path = parameters.texture_path ? parameters.texture_path : THREE.Loader.prototype.extractUrlbase( url ),
  71. bin_path = parameters.bin_path ? parameters.bin_path : THREE.Loader.prototype.extractUrlbase( url ),
  72. s = (new Date).getTime(),
  73. worker = new Worker( url ),
  74. callback_progress = this.showProgress ? THREE.Loader.prototype.updateProgress : null;
  75. worker.onmessage = function( event ) {
  76. var materials = event.data.materials,
  77. buffers = event.data.buffers;
  78. // #2 load BIN part via Ajax
  79. // For some reason it is faster doing loading from here than from within the worker.
  80. // Maybe passing of ginormous string as message between threads is costly?
  81. // Also, worker loading huge data by Ajax still freezes browser. Go figure,
  82. // worker with baked ascii JSON data keeps browser more responsive.
  83. THREE.Loader.prototype.loadAjaxBuffers( buffers, materials, callback, bin_path, texture_path, callback_progress );
  84. };
  85. worker.onerror = function (event) {
  86. alert( "worker.onerror: " + event.message + "\n" + event.data );
  87. event.preventDefault();
  88. };
  89. worker.postMessage( s );
  90. },
  91. // Binary AJAX parser based on Magi binary loader
  92. // https://github.com/kig/magi
  93. // Should look more into HTML5 File API
  94. // See also other suggestions by Gregg Tavares
  95. // https://groups.google.com/group/o3d-discuss/browse_thread/thread/a8967bc9ce1e0978
  96. loadAjaxBuffers: function( buffers, materials, callback, bin_path, texture_path, callback_progress ) {
  97. var xhr = new XMLHttpRequest(),
  98. url = bin_path + "/" + buffers;
  99. var length = 0;
  100. xhr.onreadystatechange = function() {
  101. if ( xhr.readyState == 4 ) {
  102. if ( xhr.status == 200 || xhr.status == 0 ) {
  103. THREE.Loader.prototype.createBinModel( xhr.responseText, callback, texture_path, materials );
  104. } else {
  105. alert( "Couldn't load [" + url + "] [" + xhr.status + "]" );
  106. }
  107. } else if ( xhr.readyState == 3 ) {
  108. if ( callback_progress ) {
  109. if ( length == 0 ) {
  110. length = xhr.getResponseHeader( "Content-Length" );
  111. }
  112. callback_progress( { total: length, loaded: xhr.responseText.length } );
  113. }
  114. } else if ( xhr.readyState == 2 ) {
  115. length = xhr.getResponseHeader( "Content-Length" );
  116. }
  117. }
  118. xhr.open("GET", url, true);
  119. xhr.overrideMimeType("text/plain; charset=x-user-defined");
  120. xhr.setRequestHeader("Content-Type", "text/plain");
  121. xhr.send(null);
  122. },
  123. createBinModel: function ( data, callback, texture_path, materials ) {
  124. var Model = function ( texture_path ) {
  125. //var s = (new Date).getTime();
  126. var scope = this,
  127. currentOffset = 0,
  128. md,
  129. normals = [],
  130. uvs = [],
  131. tri_b, tri_c, tri_m, tri_na, tri_nb, tri_nc,
  132. quad_b, quad_c, quad_d, quad_m, quad_na, quad_nb, quad_nc, quad_nd,
  133. tri_uvb, tri_uvc, quad_uvb, quad_uvc, quad_uvd,
  134. start_tri_flat, start_tri_smooth, start_tri_flat_uv, start_tri_smooth_uv,
  135. start_quad_flat, start_quad_smooth, start_quad_flat_uv, start_quad_smooth_uv,
  136. tri_size, quad_size,
  137. len_tri_flat, len_tri_smooth, len_tri_flat_uv, len_tri_smooth_uv,
  138. len_quad_flat, len_quad_smooth, len_quad_flat_uv, len_quad_smooth_uv;
  139. THREE.Geometry.call(this);
  140. THREE.Loader.prototype.init_materials( scope, materials, texture_path );
  141. md = parseMetaData( data, currentOffset );
  142. currentOffset += md.header_bytes;
  143. // cache offsets
  144. tri_b = md.vertex_index_bytes,
  145. tri_c = md.vertex_index_bytes*2,
  146. tri_m = md.vertex_index_bytes*3,
  147. tri_na = md.vertex_index_bytes*3 + md.material_index_bytes,
  148. tri_nb = md.vertex_index_bytes*3 + md.material_index_bytes + md.normal_index_bytes,
  149. tri_nc = md.vertex_index_bytes*3 + md.material_index_bytes + md.normal_index_bytes*2,
  150. quad_b = md.vertex_index_bytes,
  151. quad_c = md.vertex_index_bytes*2,
  152. quad_d = md.vertex_index_bytes*3,
  153. quad_m = md.vertex_index_bytes*4,
  154. quad_na = md.vertex_index_bytes*4 + md.material_index_bytes,
  155. quad_nb = md.vertex_index_bytes*4 + md.material_index_bytes + md.normal_index_bytes,
  156. quad_nc = md.vertex_index_bytes*4 + md.material_index_bytes + md.normal_index_bytes*2,
  157. quad_nd = md.vertex_index_bytes*4 + md.material_index_bytes + md.normal_index_bytes*3,
  158. tri_uvb = md.uv_index_bytes,
  159. tri_uvc = md.uv_index_bytes * 2,
  160. quad_uvb = md.uv_index_bytes,
  161. quad_uvc = md.uv_index_bytes * 2,
  162. quad_uvd = md.uv_index_bytes * 3;
  163. // buffers sizes
  164. tri_size = md.vertex_index_bytes * 3 + md.material_index_bytes;
  165. quad_size = md.vertex_index_bytes * 4 + md.material_index_bytes;
  166. len_tri_flat = md.ntri_flat * ( tri_size );
  167. len_tri_smooth = md.ntri_smooth * ( tri_size + md.normal_index_bytes * 3 );
  168. len_tri_flat_uv = md.ntri_flat_uv * ( tri_size + md.uv_index_bytes * 3 );
  169. len_tri_smooth_uv = md.ntri_smooth_uv * ( tri_size + md.normal_index_bytes * 3 + md.uv_index_bytes * 3 );
  170. len_quad_flat = md.nquad_flat * ( quad_size );
  171. len_quad_smooth = md.nquad_smooth * ( quad_size + md.normal_index_bytes * 4 );
  172. len_quad_flat_uv = md.nquad_flat_uv * ( quad_size + md.uv_index_bytes * 4 );
  173. len_quad_smooth_uv = md.nquad_smooth_uv * ( quad_size + md.normal_index_bytes * 4 + md.uv_index_bytes * 4 );
  174. // read buffers
  175. currentOffset += init_vertices( currentOffset );
  176. currentOffset += init_normals( currentOffset );
  177. currentOffset += init_uvs( currentOffset );
  178. start_tri_flat = currentOffset;
  179. start_tri_smooth = start_tri_flat + len_tri_flat;
  180. start_tri_flat_uv = start_tri_smooth + len_tri_smooth;
  181. start_tri_smooth_uv = start_tri_flat_uv + len_tri_flat_uv;
  182. start_quad_flat = start_tri_smooth_uv + len_tri_smooth_uv;
  183. start_quad_smooth = start_quad_flat + len_quad_flat;
  184. start_quad_flat_uv = start_quad_smooth + len_quad_smooth;
  185. start_quad_smooth_uv= start_quad_flat_uv +len_quad_flat_uv;
  186. // have to first process faces with uvs
  187. // so that face and uv indices match
  188. init_triangles_flat_uv( start_tri_flat_uv );
  189. init_triangles_smooth_uv( start_tri_smooth_uv );
  190. init_quads_flat_uv( start_quad_flat_uv );
  191. init_quads_smooth_uv( start_quad_smooth_uv );
  192. // now we can process untextured faces
  193. init_triangles_flat( start_tri_flat );
  194. init_triangles_smooth( start_tri_smooth );
  195. init_quads_flat( start_quad_flat );
  196. init_quads_smooth( start_quad_smooth );
  197. this.computeCentroids();
  198. this.computeFaceNormals();
  199. this.sortFacesByMaterial();
  200. //var e = (new Date).getTime();
  201. //log( "binary data parse time: " + (e-s) + " ms" );
  202. function parseMetaData( data, offset ) {
  203. var metaData = {
  204. 'signature' :parseString( data, offset, 8 ),
  205. 'header_bytes' :parseUChar8( data, offset + 8 ),
  206. 'vertex_coordinate_bytes' :parseUChar8( data, offset + 9 ),
  207. 'normal_coordinate_bytes' :parseUChar8( data, offset + 10 ),
  208. 'uv_coordinate_bytes' :parseUChar8( data, offset + 11 ),
  209. 'vertex_index_bytes' :parseUChar8( data, offset + 12 ),
  210. 'normal_index_bytes' :parseUChar8( data, offset + 13 ),
  211. 'uv_index_bytes' :parseUChar8( data, offset + 14 ),
  212. 'material_index_bytes' :parseUChar8( data, offset + 15 ),
  213. 'nvertices' :parseUInt32( data, offset + 16 ),
  214. 'nnormals' :parseUInt32( data, offset + 16 + 4*1 ),
  215. 'nuvs' :parseUInt32( data, offset + 16 + 4*2 ),
  216. 'ntri_flat' :parseUInt32( data, offset + 16 + 4*3 ),
  217. 'ntri_smooth' :parseUInt32( data, offset + 16 + 4*4 ),
  218. 'ntri_flat_uv' :parseUInt32( data, offset + 16 + 4*5 ),
  219. 'ntri_smooth_uv' :parseUInt32( data, offset + 16 + 4*6 ),
  220. 'nquad_flat' :parseUInt32( data, offset + 16 + 4*7 ),
  221. 'nquad_smooth' :parseUInt32( data, offset + 16 + 4*8 ),
  222. 'nquad_flat_uv' :parseUInt32( data, offset + 16 + 4*9 ),
  223. 'nquad_smooth_uv' :parseUInt32( data, offset + 16 + 4*10 )
  224. };
  225. /*
  226. log( "signature: " + metaData.signature );
  227. log( "header_bytes: " + metaData.header_bytes );
  228. log( "vertex_coordinate_bytes: " + metaData.vertex_coordinate_bytes );
  229. log( "normal_coordinate_bytes: " + metaData.normal_coordinate_bytes );
  230. log( "uv_coordinate_bytes: " + metaData.uv_coordinate_bytes );
  231. log( "vertex_index_bytes: " + metaData.vertex_index_bytes );
  232. log( "normal_index_bytes: " + metaData.normal_index_bytes );
  233. log( "uv_index_bytes: " + metaData.uv_index_bytes );
  234. log( "material_index_bytes: " + metaData.material_index_bytes );
  235. log( "nvertices: " + metaData.nvertices );
  236. log( "nnormals: " + metaData.nnormals );
  237. log( "nuvs: " + metaData.nuvs );
  238. log( "ntri_flat: " + metaData.ntri_flat );
  239. log( "ntri_smooth: " + metaData.ntri_smooth );
  240. log( "ntri_flat_uv: " + metaData.ntri_flat_uv );
  241. log( "ntri_smooth_uv: " + metaData.ntri_smooth_uv );
  242. log( "nquad_flat: " + metaData.nquad_flat );
  243. log( "nquad_smooth: " + metaData.nquad_smooth );
  244. log( "nquad_flat_uv: " + metaData.nquad_flat_uv );
  245. log( "nquad_smooth_uv: " + metaData.nquad_smooth_uv );
  246. var total = metaData.header_bytes
  247. + metaData.nvertices * metaData.vertex_coordinate_bytes * 3
  248. + metaData.nnormals * metaData.normal_coordinate_bytes * 3
  249. + metaData.nuvs * metaData.uv_coordinate_bytes * 2
  250. + metaData.ntri_flat * ( metaData.vertex_index_bytes*3 + metaData.material_index_bytes )
  251. + metaData.ntri_smooth * ( metaData.vertex_index_bytes*3 + metaData.material_index_bytes + metaData.normal_index_bytes*3 )
  252. + metaData.ntri_flat_uv * ( metaData.vertex_index_bytes*3 + metaData.material_index_bytes + metaData.uv_index_bytes*3 )
  253. + metaData.ntri_smooth_uv * ( metaData.vertex_index_bytes*3 + metaData.material_index_bytes + metaData.normal_index_bytes*3 + metaData.uv_index_bytes*3 )
  254. + metaData.nquad_flat * ( metaData.vertex_index_bytes*4 + metaData.material_index_bytes )
  255. + metaData.nquad_smooth * ( metaData.vertex_index_bytes*4 + metaData.material_index_bytes + metaData.normal_index_bytes*4 )
  256. + metaData.nquad_flat_uv * ( metaData.vertex_index_bytes*4 + metaData.material_index_bytes + metaData.uv_index_bytes*4 )
  257. + metaData.nquad_smooth_uv * ( metaData.vertex_index_bytes*4 + metaData.material_index_bytes + metaData.normal_index_bytes*4 + metaData.uv_index_bytes*4 );
  258. log( "total bytes: " + total );
  259. */
  260. return metaData;
  261. }
  262. function parseString( data, offset, length ) {
  263. return data.substr( offset, length );
  264. }
  265. function parseFloat32( data, offset ) {
  266. var b3 = parseUChar8( data, offset ),
  267. b2 = parseUChar8( data, offset + 1 ),
  268. b1 = parseUChar8( data, offset + 2 ),
  269. b0 = parseUChar8( data, offset + 3 ),
  270. sign = 1 - ( 2 * ( b0 >> 7 ) ),
  271. exponent = ((( b0 << 1 ) & 0xff) | ( b1 >> 7 )) - 127,
  272. mantissa = (( b1 & 0x7f ) << 16) | (b2 << 8) | b3;
  273. if (mantissa == 0 && exponent == -127)
  274. return 0.0;
  275. return sign * ( 1 + mantissa * Math.pow( 2, -23 ) ) * Math.pow( 2, exponent );
  276. }
  277. function parseUInt32( data, offset ) {
  278. var b0 = parseUChar8( data, offset ),
  279. b1 = parseUChar8( data, offset + 1 ),
  280. b2 = parseUChar8( data, offset + 2 ),
  281. b3 = parseUChar8( data, offset + 3 );
  282. return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
  283. }
  284. function parseUInt16( data, offset ) {
  285. var b0 = parseUChar8( data, offset ),
  286. b1 = parseUChar8( data, offset + 1 );
  287. return (b1 << 8) + b0;
  288. }
  289. function parseSChar8( data, offset ) {
  290. var b = parseUChar8( data, offset );
  291. return b > 127 ? b - 256 : b;
  292. }
  293. function parseUChar8( data, offset ) {
  294. return data.charCodeAt( offset ) & 0xff;
  295. }
  296. function init_vertices( start ) {
  297. var i, x, y, z,
  298. stride = md.vertex_coordinate_bytes * 3,
  299. end = start + md.nvertices * stride;
  300. for( i = start; i < end; i += stride ) {
  301. x = parseFloat32( data, i );
  302. y = parseFloat32( data, i + md.vertex_coordinate_bytes );
  303. z = parseFloat32( data, i + md.vertex_coordinate_bytes*2 );
  304. THREE.Loader.prototype.v( scope, x, y, z );
  305. }
  306. return md.nvertices * stride;
  307. }
  308. function init_normals( start ) {
  309. var i, x, y, z,
  310. stride = md.normal_coordinate_bytes * 3,
  311. end = start + md.nnormals * stride;
  312. for( i = start; i < end; i += stride ) {
  313. x = parseSChar8( data, i );
  314. y = parseSChar8( data, i + md.normal_coordinate_bytes );
  315. z = parseSChar8( data, i + md.normal_coordinate_bytes*2 );
  316. normals.push( x/127, y/127, z/127 );
  317. }
  318. return md.nnormals * stride;
  319. }
  320. function init_uvs( start ) {
  321. var i, u, v,
  322. stride = md.uv_coordinate_bytes * 2,
  323. end = start + md.nuvs * stride;
  324. for( i = start; i < end; i += stride ) {
  325. u = parseFloat32( data, i );
  326. v = parseFloat32( data, i + md.uv_coordinate_bytes );
  327. uvs.push( u, v );
  328. }
  329. return md.nuvs * stride;
  330. }
  331. function add_tri( i ) {
  332. var a, b, c, m;
  333. a = parseUInt32( data, i );
  334. b = parseUInt32( data, i + tri_b );
  335. c = parseUInt32( data, i + tri_c );
  336. m = parseUInt16( data, i + tri_m );
  337. THREE.Loader.prototype.f3( scope, a, b, c, m );
  338. }
  339. function add_tri_n( i ) {
  340. var a, b, c, m, na, nb, nc;
  341. a = parseUInt32( data, i );
  342. b = parseUInt32( data, i + tri_b );
  343. c = parseUInt32( data, i + tri_c );
  344. m = parseUInt16( data, i + tri_m );
  345. na = parseUInt32( data, i + tri_na );
  346. nb = parseUInt32( data, i + tri_nb );
  347. nc = parseUInt32( data, i + tri_nc );
  348. THREE.Loader.prototype.f3n( scope, normals, a, b, c, m, na, nb, nc );
  349. }
  350. function add_quad( i ) {
  351. var a, b, c, d, m;
  352. a = parseUInt32( data, i );
  353. b = parseUInt32( data, i + quad_b );
  354. c = parseUInt32( data, i + quad_c );
  355. d = parseUInt32( data, i + quad_d );
  356. m = parseUInt16( data, i + quad_m );
  357. THREE.Loader.prototype.f4( scope, a, b, c, d, m );
  358. }
  359. function add_quad_n( i ) {
  360. var a, b, c, d, m, na, nb, nc, nd;
  361. a = parseUInt32( data, i );
  362. b = parseUInt32( data, i + quad_b );
  363. c = parseUInt32( data, i + quad_c );
  364. d = parseUInt32( data, i + quad_d );
  365. m = parseUInt16( data, i + quad_m );
  366. na = parseUInt32( data, i + quad_na );
  367. nb = parseUInt32( data, i + quad_nb );
  368. nc = parseUInt32( data, i + quad_nc );
  369. nd = parseUInt32( data, i + quad_nd );
  370. THREE.Loader.prototype.f4n( scope, normals, a, b, c, d, m, na, nb, nc, nd );
  371. }
  372. function add_uv3( i ) {
  373. var uva, uvb, uvc, u1, u2, u3, v1, v2, v3;
  374. uva = parseUInt32( data, i );
  375. uvb = parseUInt32( data, i + tri_uvb );
  376. uvc = parseUInt32( data, i + tri_uvc );
  377. u1 = uvs[ uva*2 ];
  378. v1 = uvs[ uva*2 + 1 ];
  379. u2 = uvs[ uvb*2 ];
  380. v2 = uvs[ uvb*2 + 1 ];
  381. u3 = uvs[ uvc*2 ];
  382. v3 = uvs[ uvc*2 + 1 ];
  383. THREE.Loader.prototype.uv3( scope.uvs, u1, v1, u2, v2, u3, v3 );
  384. }
  385. function add_uv4( i ) {
  386. var uva, uvb, uvc, uvd, u1, u2, u3, u4, v1, v2, v3, v4;
  387. uva = parseUInt32( data, i );
  388. uvb = parseUInt32( data, i + quad_uvb );
  389. uvc = parseUInt32( data, i + quad_uvc );
  390. uvd = parseUInt32( data, i + quad_uvd );
  391. u1 = uvs[ uva*2 ];
  392. v1 = uvs[ uva*2 + 1 ];
  393. u2 = uvs[ uvb*2 ];
  394. v2 = uvs[ uvb*2 + 1 ];
  395. u3 = uvs[ uvc*2 ];
  396. v3 = uvs[ uvc*2 + 1 ];
  397. u4 = uvs[ uvd*2 ];
  398. v4 = uvs[ uvd*2 + 1 ];
  399. THREE.Loader.prototype.uv4( scope.uvs, u1, v1, u2, v2, u3, v3, u4, v4 );
  400. }
  401. function init_triangles_flat( start ) {
  402. var i, stride = md.vertex_index_bytes * 3 + md.material_index_bytes,
  403. end = start + md.ntri_flat * stride;
  404. for( i = start; i < end; i += stride ) {
  405. add_tri( i );
  406. }
  407. return end - start;
  408. }
  409. function init_triangles_flat_uv( start ) {
  410. var i, offset = md.vertex_index_bytes * 3 + md.material_index_bytes,
  411. stride = offset + md.uv_index_bytes * 3,
  412. end = start + md.ntri_flat_uv * stride;
  413. for( i = start; i < end; i += stride ) {
  414. add_tri( i );
  415. add_uv3( i + offset );
  416. }
  417. return end - start;
  418. }
  419. function init_triangles_smooth( start ) {
  420. var i, stride = md.vertex_index_bytes * 3 + md.material_index_bytes + md.normal_index_bytes * 3,
  421. end = start + md.ntri_smooth * stride;
  422. for( i = start; i < end; i += stride ) {
  423. add_tri_n( i );
  424. }
  425. return end - start;
  426. }
  427. function init_triangles_smooth_uv( start ) {
  428. var i, offset = md.vertex_index_bytes * 3 + md.material_index_bytes + md.normal_index_bytes * 3,
  429. stride = offset + md.uv_index_bytes * 3,
  430. end = start + md.ntri_smooth_uv * stride;
  431. for( i = start; i < end; i += stride ) {
  432. add_tri_n( i );
  433. add_uv3( i + offset );
  434. }
  435. return end - start;
  436. }
  437. function init_quads_flat( start ) {
  438. var i, stride = md.vertex_index_bytes * 4 + md.material_index_bytes,
  439. end = start + md.nquad_flat * stride;
  440. for( i = start; i < end; i += stride ) {
  441. add_quad( i );
  442. }
  443. return end - start;
  444. }
  445. function init_quads_flat_uv( start ) {
  446. var i, offset = md.vertex_index_bytes * 4 + md.material_index_bytes,
  447. stride = offset + md.uv_index_bytes * 4,
  448. end = start + md.nquad_flat_uv * stride;
  449. for( i = start; i < end; i += stride ) {
  450. add_quad( i );
  451. add_uv4( i + offset );
  452. }
  453. return end - start;
  454. }
  455. function init_quads_smooth( start ) {
  456. var i, stride = md.vertex_index_bytes * 4 + md.material_index_bytes + md.normal_index_bytes * 4,
  457. end = start + md.nquad_smooth * stride;
  458. for( i = start; i < end; i += stride ) {
  459. add_quad_n( i );
  460. }
  461. return end - start;
  462. }
  463. function init_quads_smooth_uv( start ) {
  464. var i, offset = md.vertex_index_bytes * 4 + md.material_index_bytes + md.normal_index_bytes * 4,
  465. stride = offset + md.uv_index_bytes * 4,
  466. end = start + md.nquad_smooth_uv * stride;
  467. for( i = start; i < end; i += stride ) {
  468. add_quad_n( i );
  469. add_uv4( i + offset );
  470. }
  471. return end - start;
  472. }
  473. }
  474. Model.prototype = new THREE.Geometry();
  475. Model.prototype.constructor = Model;
  476. callback( new Model( texture_path ) );
  477. },
  478. createModel: function ( data, callback, texture_path ) {
  479. var Model = function ( texture_path ) {
  480. var scope = this;
  481. THREE.Geometry.call( this );
  482. THREE.Loader.prototype.init_materials( scope, data.materials, texture_path );
  483. init_vertices();
  484. init_faces();
  485. this.computeCentroids();
  486. this.computeFaceNormals();
  487. this.sortFacesByMaterial();
  488. function init_vertices() {
  489. var i, l, x, y, z, r, g, b;
  490. for( i = 0, l = data.vertices.length; i < l; i += 3 ) {
  491. x = data.vertices[ i ];
  492. y = data.vertices[ i + 1 ];
  493. z = data.vertices[ i + 2 ];
  494. THREE.Loader.prototype.v( scope, x, y, z );
  495. }
  496. if ( data.colors ) {
  497. for( i = 0, l = data.colors.length; i < l; i += 3 ) {
  498. r = data.colors[ i ];
  499. g = data.colors[ i + 1 ];
  500. b = data.colors[ i + 2 ];
  501. THREE.Loader.prototype.vc( scope, r, g, b );
  502. }
  503. }
  504. }
  505. function init_faces() {
  506. function add_tri( src, i ) {
  507. var a, b, c, m;
  508. a = src[ i ];
  509. b = src[ i + 1 ];
  510. c = src[ i + 2 ];
  511. m = src[ i + 3 ];
  512. THREE.Loader.prototype.f3( scope, a, b, c, m );
  513. }
  514. function add_tri_n( src, i ) {
  515. var a, b, c, m, na, nb, nc;
  516. a = src[ i ];
  517. b = src[ i + 1 ];
  518. c = src[ i + 2 ];
  519. m = src[ i + 3 ];
  520. na = src[ i + 4 ];
  521. nb = src[ i + 5 ];
  522. nc = src[ i + 6 ];
  523. THREE.Loader.prototype.f3n( scope, data.normals, a, b, c, m, na, nb, nc );
  524. }
  525. function add_quad( src, i ) {
  526. var a, b, c, d, m;
  527. a = src[ i ];
  528. b = src[ i + 1 ];
  529. c = src[ i + 2 ];
  530. d = src[ i + 3 ];
  531. m = src[ i + 4 ];
  532. THREE.Loader.prototype.f4( scope, a, b, c, d, m );
  533. }
  534. function add_quad_n( src, i ) {
  535. var a, b, c, d, m, na, nb, nc, nd;
  536. a = src[ i ];
  537. b = src[ i + 1 ];
  538. c = src[ i + 2 ];
  539. d = src[ i + 3 ];
  540. m = src[ i + 4 ];
  541. na = src[ i + 5 ];
  542. nb = src[ i + 6 ];
  543. nc = src[ i + 7 ];
  544. nd = src[ i + 8 ];
  545. THREE.Loader.prototype.f4n( scope, data.normals, a, b, c, d, m, na, nb, nc, nd );
  546. }
  547. function add_uv3( src, i ) {
  548. var uva, uvb, uvc, u1, u2, u3, v1, v2, v3;
  549. uva = src[ i ];
  550. uvb = src[ i + 1 ];
  551. uvc = src[ i + 2 ];
  552. u1 = data.uvs[ uva * 2 ];
  553. v1 = data.uvs[ uva * 2 + 1 ];
  554. u2 = data.uvs[ uvb * 2 ];
  555. v2 = data.uvs[ uvb * 2 + 1 ];
  556. u3 = data.uvs[ uvc * 2 ];
  557. v3 = data.uvs[ uvc * 2 + 1 ];
  558. THREE.Loader.prototype.uv3( scope.uvs, u1, v1, u2, v2, u3, v3 );
  559. if( data.uvs2 ) {
  560. u1 = data.uvs2[ uva * 2 ];
  561. v1 = data.uvs2[ uva * 2 + 1 ];
  562. u2 = data.uvs2[ uvb * 2 ];
  563. v2 = data.uvs2[ uvb * 2 + 1 ];
  564. u3 = data.uvs2[ uvc * 2 ];
  565. v3 = data.uvs2[ uvc * 2 + 1 ];
  566. THREE.Loader.prototype.uv3( scope.uvs2, u1, 1-v1, u2, 1-v2, u3, 1-v3 );
  567. }
  568. }
  569. function add_uv4( src, i ) {
  570. var uva, uvb, uvc, uvd, u1, u2, u3, u4, v1, v2, v3, v4;
  571. uva = src[ i ];
  572. uvb = src[ i + 1 ];
  573. uvc = src[ i + 2 ];
  574. uvd = src[ i + 3 ];
  575. u1 = data.uvs[ uva * 2 ];
  576. v1 = data.uvs[ uva * 2 + 1 ];
  577. u2 = data.uvs[ uvb * 2 ];
  578. v2 = data.uvs[ uvb * 2 + 1 ];
  579. u3 = data.uvs[ uvc * 2 ];
  580. v3 = data.uvs[ uvc * 2 + 1 ];
  581. u4 = data.uvs[ uvd * 2 ];
  582. v4 = data.uvs[ uvd * 2 + 1 ];
  583. THREE.Loader.prototype.uv4( scope.uvs, u1, v1, u2, v2, u3, v3, u4, v4 );
  584. if( data.uvs2 ) {
  585. u1 = data.uvs2[ uva * 2 ];
  586. v1 = data.uvs2[ uva * 2 + 1 ];
  587. u2 = data.uvs2[ uvb * 2 ];
  588. v2 = data.uvs2[ uvb * 2 + 1 ];
  589. u3 = data.uvs2[ uvc * 2 ];
  590. v3 = data.uvs2[ uvc * 2 + 1 ];
  591. u4 = data.uvs2[ uvd * 2 ];
  592. v4 = data.uvs2[ uvd * 2 + 1 ];
  593. THREE.Loader.prototype.uv4( scope.uvs2, u1, 1-v1, u2, 1-v2, u3, 1-v3, u4, 1-v4 );
  594. }
  595. }
  596. var i, l;
  597. // need to process first faces with uvs
  598. // as uvs are indexed by face indices
  599. for ( i = 0, l = data.triangles_uv.length; i < l; i+= 7 ) {
  600. add_tri( data.triangles_uv, i );
  601. add_uv3( data.triangles_uv, i + 4 );
  602. }
  603. for ( i = 0, l = data.triangles_n_uv.length; i < l; i += 10 ) {
  604. add_tri_n( data.triangles_n_uv, i );
  605. add_uv3( data.triangles_n_uv, i + 7 );
  606. }
  607. for ( i = 0, l = data.quads_uv.length; i < l; i += 9 ) {
  608. add_quad( data.quads_uv, i );
  609. add_uv4( data.quads_uv, i + 5 );
  610. }
  611. for ( i = 0, l = data.quads_n_uv.length; i < l; i += 13 ) {
  612. add_quad_n( data.quads_n_uv, i );
  613. add_uv4( data.quads_n_uv, i + 9 );
  614. }
  615. // now can process untextured faces
  616. for ( i = 0, l = data.triangles.length; i < l; i += 4 ) {
  617. add_tri( data.triangles, i );
  618. }
  619. for ( i = 0, l = data.triangles_n.length; i < l; i += 7 ) {
  620. add_tri_n( data.triangles_n, i );
  621. }
  622. for ( i = 0, l = data.quads.length; i < l; i += 5 ) {
  623. add_quad( data.quads, i );
  624. }
  625. for ( i = 0, l = data.quads_n.length; i < l; i += 9 ) {
  626. add_quad_n( data.quads_n, i );
  627. }
  628. }
  629. }
  630. Model.prototype = new THREE.Geometry();
  631. Model.prototype.constructor = Model;
  632. callback( new Model( texture_path ) );
  633. },
  634. v: function( scope, x, y, z ) {
  635. scope.vertices.push( new THREE.Vertex( new THREE.Vector3( x, y, z ) ) );
  636. },
  637. vc: function( scope, r, g, b ) {
  638. var color = new THREE.Color( 0xffffff );
  639. color.setRGB( r, g, b );
  640. scope.colors.push( color );
  641. },
  642. f3: function( scope, a, b, c, mi ) {
  643. var material = scope.materials[ mi ];
  644. scope.faces.push( new THREE.Face3( a, b, c, null, material ) );
  645. },
  646. f4: function( scope, a, b, c, d, mi ) {
  647. var material = scope.materials[ mi ];
  648. scope.faces.push( new THREE.Face4( a, b, c, d, null, material ) );
  649. },
  650. f3n: function( scope, normals, a, b, c, mi, na, nb, nc ) {
  651. var material = scope.materials[ mi ],
  652. nax = normals[ na*3 ],
  653. nay = normals[ na*3 + 1 ],
  654. naz = normals[ na*3 + 2 ],
  655. nbx = normals[ nb*3 ],
  656. nby = normals[ nb*3 + 1 ],
  657. nbz = normals[ nb*3 + 2 ],
  658. ncx = normals[ nc*3 ],
  659. ncy = normals[ nc*3 + 1 ],
  660. ncz = normals[ nc*3 + 2 ];
  661. scope.faces.push( new THREE.Face3( a, b, c,
  662. [new THREE.Vector3( nax, nay, naz ),
  663. new THREE.Vector3( nbx, nby, nbz ),
  664. new THREE.Vector3( ncx, ncy, ncz )],
  665. material ) );
  666. },
  667. f4n: function( scope, normals, a, b, c, d, mi, na, nb, nc, nd ) {
  668. var material = scope.materials[ mi ],
  669. nax = normals[ na*3 ],
  670. nay = normals[ na*3 + 1 ],
  671. naz = normals[ na*3 + 2 ],
  672. nbx = normals[ nb*3 ],
  673. nby = normals[ nb*3 + 1 ],
  674. nbz = normals[ nb*3 + 2 ],
  675. ncx = normals[ nc*3 ],
  676. ncy = normals[ nc*3 + 1 ],
  677. ncz = normals[ nc*3 + 2 ],
  678. ndx = normals[ nd*3 ],
  679. ndy = normals[ nd*3 + 1 ],
  680. ndz = normals[ nd*3 + 2 ];
  681. scope.faces.push( new THREE.Face4( a, b, c, d,
  682. [new THREE.Vector3( nax, nay, naz ),
  683. new THREE.Vector3( nbx, nby, nbz ),
  684. new THREE.Vector3( ncx, ncy, ncz ),
  685. new THREE.Vector3( ndx, ndy, ndz )],
  686. material ) );
  687. },
  688. uv3: function( where, u1, v1, u2, v2, u3, v3 ) {
  689. var uv = [];
  690. uv.push( new THREE.UV( u1, v1 ) );
  691. uv.push( new THREE.UV( u2, v2 ) );
  692. uv.push( new THREE.UV( u3, v3 ) );
  693. where.push( uv );
  694. },
  695. uv4: function( where, u1, v1, u2, v2, u3, v3, u4, v4 ) {
  696. var uv = [];
  697. uv.push( new THREE.UV( u1, v1 ) );
  698. uv.push( new THREE.UV( u2, v2 ) );
  699. uv.push( new THREE.UV( u3, v3 ) );
  700. uv.push( new THREE.UV( u4, v4 ) );
  701. where.push( uv );
  702. },
  703. init_materials: function( scope, materials, texture_path ) {
  704. scope.materials = [];
  705. for ( var i = 0; i < materials.length; ++i ) {
  706. scope.materials[i] = [ THREE.Loader.prototype.createMaterial( materials[i], texture_path ) ];
  707. }
  708. },
  709. createMaterial: function ( m, texture_path ) {
  710. function is_pow2( n ) {
  711. var l = Math.log(n) / Math.LN2;
  712. return Math.floor(l) == l;
  713. }
  714. function nearest_pow2( n ) {
  715. var l = Math.log(n) / Math.LN2;
  716. return Math.pow( 2, Math.round(l) );
  717. }
  718. function load_image( where, url ) {
  719. var image = new Image();
  720. image.onload = function () {
  721. if ( !is_pow2( this.width ) || !is_pow2( this.height ) ) {
  722. var w = nearest_pow2( this.width ),
  723. h = nearest_pow2( this.height );
  724. where.image.width = w;
  725. where.image.height = h;
  726. where.image.getContext("2d").drawImage( this, 0, 0, w, h );
  727. } else {
  728. where.image = this;
  729. }
  730. where.image.loaded = 1;
  731. };
  732. image.src = url;
  733. }
  734. var material, mtype, mpars, texture, color;
  735. // defaults
  736. mtype = "MeshLambertMaterial";
  737. mpars = { color: 0xeeeeee, opacity: 1.0, map: null, light_map: null, vertex_colors: m.vertex_colors };
  738. // parameters from model file
  739. if ( m.shading ) {
  740. if ( m.shading == "Phong" ) mtype = "MeshPhongMaterial";
  741. }
  742. if ( m.map_diffuse && texture_path ) {
  743. texture = document.createElement( 'canvas' );
  744. mpars.map = new THREE.Texture( texture );
  745. load_image( mpars.map, texture_path + "/" + m.map_diffuse );
  746. } else if ( m.col_diffuse ) {
  747. color = ( m.col_diffuse[0] * 255 << 16 ) + ( m.col_diffuse[1] * 255 << 8 ) + m.col_diffuse[2] * 255;
  748. mpars.color = color;
  749. mpars.opacity = m.transparency;
  750. } else if ( m.a_dbg_color ) {
  751. mpars.color = m.a_dbg_color;
  752. }
  753. if ( m.map_lightmap && texture_path ) {
  754. texture = document.createElement( 'canvas' );
  755. mpars.light_map = new THREE.Texture( texture );
  756. load_image( mpars.light_map, texture_path + "/" + m.map_lightmap );
  757. }
  758. material = new THREE[ mtype ]( mpars );
  759. return material;
  760. },
  761. extractUrlbase: function( url ) {
  762. var chunks = url.split( "/" );
  763. chunks.pop();
  764. return chunks.join( "/" );
  765. }
  766. };
粤ICP备19079148号