diff --git a/.jshintrc b/.jshintrc index a8e67b5..2b13ab5 100644 --- a/.jshintrc +++ b/.jshintrc @@ -21,6 +21,7 @@ "globals" : { "OV" : true, "THREE" : false, + "rhino3dm" : false, "TextEncoder" : false, "TextDecoder" : false, "XMLHttpRequest" : false, diff --git a/README.md b/README.md index 176b553..b962992 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ The repository is separated into two parts. See more information in the [Develop - stl (text and binary) - ply (text and binary) - gltf (text and binary) +- 3dm (experimental) - off (text only) ### Export @@ -31,24 +32,29 @@ The repository is separated into two parts. See more information in the [Develop - stl (text and binary) - ply (text and binary) - gltf (text and binary) +- 3dm (experimental) - off (text only) ## Features - Load model: - - Select files from a file browser dialog - - Drag and drop files from your computer - - Specify files by web url - - Specify files by web url in hash parameters + - Select files from a file browser dialog. + - Drag and drop files from your computer. + - Specify files by web url. + - Specify files by web url in hash parameters. - Explore model: - - Orbit, pan, zoom - - Set up direction - - Fit to window + - Orbit, pan, zoom. + - Set up direction. + - Fit to window. - Investigate model: - - List used and missing files - - List all materials and meshes - - Show/hide and zoom to a specific mesh - - List materials used by a specific mesh - - Show model information (model size, vertex and polygon count) -- Export model to various format -- Embed viewer in your website + - List used and missing files. + - List all materials and meshes. + - Show/hide and zoom to a specific mesh. + - List materials used by a specific mesh. + - Show model information (model size, vertex and polygon count). +- Export model to various format. +- Embed viewer in your website. + +## External Libraries + +Online 3D Viewer uses these wonderful libraries: [jquery](https://github.com/jquery/jquery), [three.js](https://github.com/mrdoob/three.js), [rhino3dm](https://github.com/mcneel/rhino3dm). diff --git a/libs/rhino3dm.license.txt b/libs/rhino3dm.license.txt new file mode 100644 index 0000000..e8556d0 --- /dev/null +++ b/libs/rhino3dm.license.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Robert McNeel & Associates + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/libs/rhino3dm.min.js b/libs/rhino3dm.min.js new file mode 100644 index 0000000..61e164a --- /dev/null +++ b/libs/rhino3dm.min.js @@ -0,0 +1,8 @@ +/** + * Minified by jsDelivr using Terser v5.3.5. + * Original file: /npm/rhino3dm@0.14.0/rhino3dm.js + * + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files + */ +var rhino3dm=function(){var e="undefined"!=typeof document&&document.currentScript?document.currentScript.src:void 0;return"undefined"!=typeof __filename&&(e=e||__filename),function(r){var t,n,o=void 0!==(r=r||{})?r:{};o.ready=new Promise((function(e,r){t=e,n=r}));var i,a={};for(i in o)o.hasOwnProperty(i)&&(a[i]=o[i]);var s=[],u="./this.program",c=!1,f=!1,l=!1,d=!1;c="object"==typeof window,f="function"==typeof importScripts,l="object"==typeof process&&"object"==typeof process.versions&&"string"==typeof process.versions.node,d=!c&&!l&&!f;var p,h,m,v,g="";function y(e){return o.locateFile?o.locateFile(e,g):g+e}l?(g=f?require("path").dirname(g)+"/":__dirname+"/",p=function(e,r){return m||(m=require("fs")),v||(v=require("path")),e=v.normalize(e),m.readFileSync(e,r?null:"utf8")},h=function(e){var r=p(e,!0);return r.buffer||(r=new Uint8Array(r)),D(r.buffer),r},process.argv.length>1&&(u=process.argv[1].replace(/\\/g,"/")),s=process.argv.slice(2),process.on("uncaughtException",(function(e){if(!(e instanceof no))throw e})),process.on("unhandledRejection",ge),function(e){process.exit(e)},o.inspect=function(){return"[Emscripten Module object]"}):d?("undefined"!=typeof read&&(p=function(e){return read(e)}),h=function(e){var r;return"function"==typeof readbuffer?new Uint8Array(readbuffer(e)):(D("object"==typeof(r=read(e,"binary"))),r)},"undefined"!=typeof scriptArgs?s=scriptArgs:void 0!==arguments&&(s=arguments),"function"==typeof quit&&function(e){quit(e)},"undefined"!=typeof print&&("undefined"==typeof console&&(console={}),console.log=print,console.warn=console.error="undefined"!=typeof printErr?printErr:print)):(c||f)&&(f?g=self.location.href:"undefined"!=typeof document&&document.currentScript&&(g=document.currentScript.src),e&&(g=e),g=0!==g.indexOf("blob:")?g.substr(0,g.lastIndexOf("/")+1):"",p=function(e){var r=new XMLHttpRequest;return r.open("GET",e,!1),r.send(null),r.responseText},f&&(h=function(e){var r=new XMLHttpRequest;return r.open("GET",e,!1),r.responseType="arraybuffer",r.send(null),new Uint8Array(r.response)}),function(e,r,t){var n=new XMLHttpRequest;n.open("GET",e,!0),n.responseType="arraybuffer",n.onload=function(){200==n.status||0==n.status&&n.response?r(n.response):t()},n.onerror=t,n.send(null)});var w=o.print||console.log.bind(console),_=o.printErr||console.warn.bind(console);for(i in a)a.hasOwnProperty(i)&&(o[i]=a[i]);a=null,o.arguments&&(s=o.arguments),o.thisProgram&&(u=o.thisProgram),o.quit&&o.quit;var E=16;function b(e,r){return r||(r=E),Math.ceil(e/r)*r}var k,T,P=function(e){e};o.wasmBinary&&(k=o.wasmBinary),o.noExitRuntime&&o.noExitRuntime,"object"!=typeof WebAssembly&&ge("no native wasm support detected");var F=!1;function D(e,r){e||ge("Assertion failed: "+r)}var C="undefined"!=typeof TextDecoder?new TextDecoder("utf8"):void 0;function S(e,r,t){for(var n=r+t,o=r;e[o]&&!(o>=n);)++o;if(o-r>16&&e.subarray&&C)return C.decode(e.subarray(r,o));for(var i="";r>10,56320|1023&c)}}else i+=String.fromCharCode((31&a)<<6|s)}else i+=String.fromCharCode(a)}return i}function A(e,r){return e?S(j,e,r):""}function $(e,r,t,n){if(!(n>0))return 0;for(var o=t,i=t+n-1,a=0;a=55296&&s<=57343)s=65536+((1023&s)<<10)|1023&e.charCodeAt(++a);if(s<=127){if(t>=i)break;r[t++]=s}else if(s<=2047){if(t+1>=i)break;r[t++]=192|s>>6,r[t++]=128|63&s}else if(s<=65535){if(t+2>=i)break;r[t++]=224|s>>12,r[t++]=128|s>>6&63,r[t++]=128|63&s}else{if(t+3>=i)break;r[t++]=240|s>>18,r[t++]=128|s>>12&63,r[t++]=128|s>>6&63,r[t++]=128|63&s}}return r[t]=0,t-o}function O(e,r,t){return $(e,j,r,t)}function R(e){for(var r=0,t=0;t=55296&&n<=57343&&(n=65536+((1023&n)<<10)|1023&e.charCodeAt(++t)),n<=127?++r:r+=n<=2047?2:n<=65535?3:4}return r}var x,M,j,W,N,B,U,z,I,L="undefined"!=typeof TextDecoder?new TextDecoder("utf-16le"):void 0;function H(e,r){for(var t=e,n=t>>1,o=n+r/2;!(n>=o)&&N[n];)++n;if((t=n<<1)-e>32&&L)return L.decode(j.subarray(e,t));for(var i="",a=0;!(a>=r/2);++a){var s=W[e+2*a>>1];if(0==s)break;i+=String.fromCharCode(s)}return i}function q(e,r,t){if(void 0===t&&(t=2147483647),t<2)return 0;for(var n=r,o=(t-=2)<2*e.length?t/2:e.length,i=0;i>1]=a,r+=2}return W[r>>1]=0,r-n}function V(e){return 2*e.length}function G(e,r){for(var t=0,n="";!(t>=r/4);){var o=B[e+4*t>>2];if(0==o)break;if(++t,o>=65536){var i=o-65536;n+=String.fromCharCode(55296|i>>10,56320|1023&i)}else n+=String.fromCharCode(o)}return n}function X(e,r,t){if(void 0===t&&(t=2147483647),t<4)return 0;for(var n=r,o=n+t-4,i=0;i=55296&&a<=57343)a=65536+((1023&a)<<10)|1023&e.charCodeAt(++i);if(B[r>>2]=a,(r+=4)+4>o)break}return B[r>>2]=0,r-n}function Y(e){for(var r=0,t=0;t=55296&&n<=57343&&++t,r+=4}return r}function K(e){var r=R(e)+1,t=Qn(r);return t&&$(e,M,t,r),t}function Z(e,r){M.set(e,r)}function J(e,r,t){for(var n=0;n>0]=e.charCodeAt(n);t||(M[r>>0]=0)}function Q(e,r){return e%r>0&&(e+=r-e%r),e}function ee(e){x=e,o.HEAP8=M=new Int8Array(e),o.HEAP16=W=new Int16Array(e),o.HEAP32=B=new Int32Array(e),o.HEAPU8=j=new Uint8Array(e),o.HEAPU16=N=new Uint16Array(e),o.HEAPU32=U=new Uint32Array(e),o.HEAPF32=z=new Float32Array(e),o.HEAPF64=I=new Float64Array(e)}o.INITIAL_MEMORY;var re,te=[],ne=[],oe=[],ie=[];function ae(){if(o.preRun)for("function"==typeof o.preRun&&(o.preRun=[o.preRun]);o.preRun.length;)fe(o.preRun.shift());Se(te)}function se(){!0,o.noFSInit||He.init.initialized||He.init(),ze.init(),Se(ne)}function ue(){He.ignorePermissions=!1,Se(oe)}function ce(){if(o.postRun)for("function"==typeof o.postRun&&(o.postRun=[o.postRun]);o.postRun.length;)le(o.postRun.shift());Se(ie)}function fe(e){te.unshift(e)}function le(e){ie.unshift(e)}var de=0,pe=null,he=null;function me(e){de++,o.monitorRunDependencies&&o.monitorRunDependencies(de)}function ve(e){if(de--,o.monitorRunDependencies&&o.monitorRunDependencies(de),0==de&&(null!==pe&&(clearInterval(pe),pe=null),he)){var r=he;he=null,r()}}function ge(e){o.onAbort&&o.onAbort(e),_(e+=""),F=!0,1,e="abort("+e+"). Build with -s ASSERTIONS=1 for more info.";var r=new WebAssembly.RuntimeError(e);throw n(r),r}function ye(e,r){return String.prototype.startsWith?e.startsWith(r):0===e.indexOf(r)}o.preloadedImages={},o.preloadedAudios={};var we="data:application/octet-stream;base64,";function _e(e){return ye(e,we)}var Ee="file://";function be(e){return ye(e,Ee)}var ke,Te,Pe="rhino3dm.wasm";function Fe(){try{if(k)return new Uint8Array(k);if(h)return h(Pe);throw"both async and sync fetching of the wasm failed"}catch(e){ge(e)}}function De(){return k||!c&&!f||"function"!=typeof fetch||be(Pe)?Promise.resolve().then(Fe):fetch(Pe,{credentials:"same-origin"}).then((function(e){if(!e.ok)throw"failed to load wasm binary file at '"+Pe+"'";return e.arrayBuffer()})).catch((function(){return Fe()}))}function Ce(){var e={env:Zn,wasi_snapshot_preview1:Zn};function r(e,r){var t=e.exports;o.asm=t,ee((T=o.asm.memory).buffer),re=o.asm.__indirect_function_table,ve()}function t(e){r(e.instance)}function i(r){return De().then((function(r){return WebAssembly.instantiate(r,e)})).then(r,(function(e){_("failed to asynchronously prepare wasm: "+e),ge(e)}))}if(me(),o.instantiateWasm)try{return o.instantiateWasm(e,r)}catch(e){return _("Module.instantiateWasm callback failed with error: "+e),!1}return(k||"function"!=typeof WebAssembly.instantiateStreaming||_e(Pe)||be(Pe)||"function"!=typeof fetch?i(t):fetch(Pe,{credentials:"same-origin"}).then((function(r){return WebAssembly.instantiateStreaming(r,e).then(t,(function(e){return _("wasm streaming compile failed: "+e),_("falling back to ArrayBuffer instantiation"),i(t)}))}))).catch(n),{}}function Se(e){for(;e.length>0;){var r=e.shift();if("function"!=typeof r){var t=r.func;"number"==typeof t?void 0===r.arg?re.get(t)():re.get(t)(r.arg):t(void 0===r.arg?null:r.arg)}else r(o)}}_e(Pe)||(Pe=y(Pe));var Ae={DESTRUCTOR_OFFSET:0,REFCOUNT_OFFSET:4,TYPE_OFFSET:8,CAUGHT_OFFSET:12,RETHROWN_OFFSET:13,SIZE:16};function $e(e){return Qn(e+Ae.SIZE)+Ae.SIZE}function Oe(e,r){}function Re(e){this.excPtr=e,this.ptr=e-Ae.SIZE,this.set_type=function(e){B[this.ptr+Ae.TYPE_OFFSET>>2]=e},this.get_type=function(){return B[this.ptr+Ae.TYPE_OFFSET>>2]},this.set_destructor=function(e){B[this.ptr+Ae.DESTRUCTOR_OFFSET>>2]=e},this.get_destructor=function(){return B[this.ptr+Ae.DESTRUCTOR_OFFSET>>2]},this.set_refcount=function(e){B[this.ptr+Ae.REFCOUNT_OFFSET>>2]=e},this.set_caught=function(e){e=e?1:0,M[this.ptr+Ae.CAUGHT_OFFSET>>0]=e},this.get_caught=function(){return 0!=M[this.ptr+Ae.CAUGHT_OFFSET>>0]},this.set_rethrown=function(e){e=e?1:0,M[this.ptr+Ae.RETHROWN_OFFSET>>0]=e},this.get_rethrown=function(){return 0!=M[this.ptr+Ae.RETHROWN_OFFSET>>0]},this.init=function(e,r){this.set_type(e),this.set_destructor(r),this.set_refcount(0),this.set_caught(!1),this.set_rethrown(!1)},this.add_ref=function(){var e=B[this.ptr+Ae.REFCOUNT_OFFSET>>2];B[this.ptr+Ae.REFCOUNT_OFFSET>>2]=e+1},this.release_ref=function(){var e=B[this.ptr+Ae.REFCOUNT_OFFSET>>2];return B[this.ptr+Ae.REFCOUNT_OFFSET>>2]=e-1,1===e}}function xe(e,r,t){throw new Re(e).init(r,t),e,e}function Me(e,r){var t=new Date(1e3*B[e>>2]);B[r>>2]=t.getUTCSeconds(),B[r+4>>2]=t.getUTCMinutes(),B[r+8>>2]=t.getUTCHours(),B[r+12>>2]=t.getUTCDate(),B[r+16>>2]=t.getUTCMonth(),B[r+20>>2]=t.getUTCFullYear()-1900,B[r+24>>2]=t.getUTCDay(),B[r+36>>2]=0,B[r+32>>2]=0;var n=Date.UTC(t.getUTCFullYear(),0,1,0,0,0,0),o=(t.getTime()-n)/864e5|0;return B[r+28>>2]=o,Me.GMTString||(Me.GMTString=K("GMT")),B[r+40>>2]=Me.GMTString,r}function je(e,r){return Me(e,r)}function We(e){return B[to()>>2]=e,e}var Ne={splitPath:function(e){return/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/.exec(e).slice(1)},normalizeArray:function(e,r){for(var t=0,n=e.length-1;n>=0;n--){var o=e[n];"."===o?e.splice(n,1):".."===o?(e.splice(n,1),t++):t&&(e.splice(n,1),t--)}if(r)for(;t;t--)e.unshift("..");return e},normalize:function(e){var r="/"===e.charAt(0),t="/"===e.substr(-1);return(e=Ne.normalizeArray(e.split("/").filter((function(e){return!!e})),!r).join("/"))||r||(e="."),e&&t&&(e+="/"),(r?"/":"")+e},dirname:function(e){var r=Ne.splitPath(e),t=r[0],n=r[1];return t||n?(n&&(n=n.substr(0,n.length-1)),t+n):"."},basename:function(e){if("/"===e)return"/";var r=(e=(e=Ne.normalize(e)).replace(/\/$/,"")).lastIndexOf("/");return-1===r?e:e.substr(r+1)},extname:function(e){return Ne.splitPath(e)[3]},join:function(){var e=Array.prototype.slice.call(arguments,0);return Ne.normalize(e.join("/"))},join2:function(e,r){return Ne.normalize(e+"/"+r)}};function Be(){if("object"==typeof crypto&&"function"==typeof crypto.getRandomValues){var e=new Uint8Array(1);return function(){return crypto.getRandomValues(e),e[0]}}if(l)try{var r=require("crypto");return function(){return r.randomBytes(1)[0]}}catch(e){}return function(){ge("randomDevice")}}var Ue={resolve:function(){for(var e="",r=!1,t=arguments.length-1;t>=-1&&!r;t--){var n=t>=0?arguments[t]:He.cwd();if("string"!=typeof n)throw new TypeError("Arguments to path.resolve must be strings");if(!n)return"";e=n+"/"+e,r="/"===n.charAt(0)}return(r?"/":"")+(e=Ne.normalizeArray(e.split("/").filter((function(e){return!!e})),!r).join("/"))||"."},relative:function(e,r){function t(e){for(var r=0;r=0&&""===e[t];t--);return r>t?[]:e.slice(r,t-r+1)}e=Ue.resolve(e).substr(1),r=Ue.resolve(r).substr(1);for(var n=t(e.split("/")),o=t(r.split("/")),i=Math.min(n.length,o.length),a=i,s=0;s0?t.slice(0,n).toString("utf-8"):null}else"undefined"!=typeof window&&"function"==typeof window.prompt?null!==(r=window.prompt("Input: "))&&(r+="\n"):"function"==typeof readline&&null!==(r=readline())&&(r+="\n");if(!r)return null;e.input=Yn(r,!0)}return e.input.shift()},put_char:function(e,r){null===r||10===r?(w(S(e.output,0)),e.output=[]):0!=r&&e.output.push(r)},flush:function(e){e.output&&e.output.length>0&&(w(S(e.output,0)),e.output=[])}},default_tty1_ops:{put_char:function(e,r){null===r||10===r?(_(S(e.output,0)),e.output=[]):0!=r&&e.output.push(r)},flush:function(e){e.output&&e.output.length>0&&(_(S(e.output,0)),e.output=[])}}};function Ie(e){for(var r=b(e,16384),t=Qn(r);e=r)){r=Math.max(r,t*(t<1048576?2:1.125)>>>0),0!=t&&(r=Math.max(r,256));var n=e.contents;e.contents=new Uint8Array(r),e.usedBytes>0&&e.contents.set(n.subarray(0,e.usedBytes),0)}},resizeFileStorage:function(e,r){if(e.usedBytes!=r){if(0==r)return e.contents=null,void(e.usedBytes=0);if(!e.contents||e.contents.subarray){var t=e.contents;return e.contents=new Uint8Array(r),t&&e.contents.set(t.subarray(0,Math.min(r,e.usedBytes))),void(e.usedBytes=r)}if(e.contents||(e.contents=[]),e.contents.length>r)e.contents.length=r;else for(;e.contents.length=e.node.usedBytes)return 0;var a=Math.min(e.node.usedBytes-o,n);if(a>8&&i.subarray)r.set(i.subarray(o,o+a),t);else for(var s=0;s0||n+t8)throw new He.ErrnoError(32);for(var o=Ne.normalizeArray(e.split("/").filter((function(e){return!!e})),!1),i=He.root,a="/",s=0;s40)throw new He.ErrnoError(32)}}return{path:a,node:i}},getPath:function(e){for(var r;;){if(He.isRoot(e)){var t=e.mount.mountpoint;return r?"/"!==t[t.length-1]?t+"/"+r:t+r:t}r=r?e.name+"/"+r:e.name,e=e.parent}},hashName:function(e,r){for(var t=0,n=0;n>>0)%He.nameTable.length},hashAddNode:function(e){var r=He.hashName(e.parent.id,e.name);e.name_next=He.nameTable[r],He.nameTable[r]=e},hashRemoveNode:function(e){var r=He.hashName(e.parent.id,e.name);if(He.nameTable[r]===e)He.nameTable[r]=e.name_next;else for(var t=He.nameTable[r];t;){if(t.name_next===e){t.name_next=e.name_next;break}t=t.name_next}},lookupNode:function(e,r){var t=He.mayLookup(e);if(t)throw new He.ErrnoError(t,e);for(var n=He.hashName(e.id,r),o=He.nameTable[n];o;o=o.name_next){var i=o.name;if(o.parent.id===e.id&&i===r)return o}return He.lookup(e,r)},createNode:function(e,r,t,n){var o=new He.FSNode(e,r,t,n);return He.hashAddNode(o),o},destroyNode:function(e){He.hashRemoveNode(e)},isRoot:function(e){return e===e.parent},isMountpoint:function(e){return!!e.mounted},isFile:function(e){return 32768==(61440&e)},isDir:function(e){return 16384==(61440&e)},isLink:function(e){return 40960==(61440&e)},isChrdev:function(e){return 8192==(61440&e)},isBlkdev:function(e){return 24576==(61440&e)},isFIFO:function(e){return 4096==(61440&e)},isSocket:function(e){return 49152==(49152&e)},flagModes:{r:0,"r+":2,w:577,"w+":578,a:1089,"a+":1090},modeStringToFlags:function(e){var r=He.flagModes[e];if(void 0===r)throw new Error("Unknown file open mode: "+e);return r},flagsToPermissionString:function(e){var r=["r","w","rw"][3&e];return 512&e&&(r+="w"),r},nodePermissions:function(e,r){return He.ignorePermissions||(-1===r.indexOf("r")||292&e.mode)&&(-1===r.indexOf("w")||146&e.mode)&&(-1===r.indexOf("x")||73&e.mode)?0:2},mayLookup:function(e){var r=He.nodePermissions(e,"x");return r||(e.node_ops.lookup?0:2)},mayCreate:function(e,r){try{He.lookupNode(e,r);return 20}catch(e){}return He.nodePermissions(e,"wx")},mayDelete:function(e,r,t){var n;try{n=He.lookupNode(e,r)}catch(e){return e.errno}var o=He.nodePermissions(e,"wx");if(o)return o;if(t){if(!He.isDir(n.mode))return 54;if(He.isRoot(n)||He.getPath(n)===He.cwd())return 10}else if(He.isDir(n.mode))return 31;return 0},mayOpen:function(e,r){return e?He.isLink(e.mode)?32:He.isDir(e.mode)&&("r"!==He.flagsToPermissionString(r)||512&r)?31:He.nodePermissions(e,He.flagsToPermissionString(r)):44},MAX_OPEN_FDS:4096,nextfd:function(e,r){e=e||0,r=r||He.MAX_OPEN_FDS;for(var t=e;t<=r;t++)if(!He.streams[t])return t;throw new He.ErrnoError(33)},getStream:function(e){return He.streams[e]},createStream:function(e,r,t){He.FSStream||(He.FSStream=function(){},He.FSStream.prototype={object:{get:function(){return this.node},set:function(e){this.node=e}},isRead:{get:function(){return 1!=(2097155&this.flags)}},isWrite:{get:function(){return 0!=(2097155&this.flags)}},isAppend:{get:function(){return 1024&this.flags}}});var n=new He.FSStream;for(var o in e)n[o]=e[o];e=n;var i=He.nextfd(r,t);return e.fd=i,He.streams[i]=e,e},closeStream:function(e){He.streams[e]=null},chrdev_stream_ops:{open:function(e){var r=He.getDevice(e.node.rdev);e.stream_ops=r.stream_ops,e.stream_ops.open&&e.stream_ops.open(e)},llseek:function(){throw new He.ErrnoError(70)}},major:function(e){return e>>8},minor:function(e){return 255&e},makedev:function(e,r){return e<<8|r},registerDevice:function(e,r){He.devices[e]={stream_ops:r}},getDevice:function(e){return He.devices[e]},getMounts:function(e){for(var r=[],t=[e];t.length;){var n=t.pop();r.push(n),t.push.apply(t,n.mounts)}return r},syncfs:function(e,r){"function"==typeof e&&(r=e,e=!1),He.syncFSRequests++,He.syncFSRequests>1&&_("warning: "+He.syncFSRequests+" FS.syncfs operations in flight at once, probably just doing extra work");var t=He.getMounts(He.root.mount),n=0;function o(e){return He.syncFSRequests--,r(e)}function i(e){if(e)return i.errored?void 0:(i.errored=!0,o(e));++n>=t.length&&o(null)}t.forEach((function(r){if(!r.type.syncfs)return i(null);r.type.syncfs(r,e,i)}))},mount:function(e,r,t){var n,o="/"===t,i=!t;if(o&&He.root)throw new He.ErrnoError(10);if(!o&&!i){var a=He.lookupPath(t,{follow_mount:!1});if(t=a.path,n=a.node,He.isMountpoint(n))throw new He.ErrnoError(10);if(!He.isDir(n.mode))throw new He.ErrnoError(54)}var s={type:e,opts:r,mountpoint:t,mounts:[]},u=e.mount(s);return u.mount=s,s.root=u,o?He.root=u:n&&(n.mounted=s,n.mount&&n.mount.mounts.push(s)),u},unmount:function(e){var r=He.lookupPath(e,{follow_mount:!1});if(!He.isMountpoint(r.node))throw new He.ErrnoError(28);var t=r.node,n=t.mounted,o=He.getMounts(n);Object.keys(He.nameTable).forEach((function(e){for(var r=He.nameTable[e];r;){var t=r.name_next;-1!==o.indexOf(r.mount)&&He.destroyNode(r),r=t}})),t.mounted=null;var i=t.mount.mounts.indexOf(n);t.mount.mounts.splice(i,1)},lookup:function(e,r){return e.node_ops.lookup(e,r)},mknod:function(e,r,t){var n=He.lookupPath(e,{parent:!0}).node,o=Ne.basename(e);if(!o||"."===o||".."===o)throw new He.ErrnoError(28);var i=He.mayCreate(n,o);if(i)throw new He.ErrnoError(i);if(!n.node_ops.mknod)throw new He.ErrnoError(63);return n.node_ops.mknod(n,o,r,t)},create:function(e,r){return r=void 0!==r?r:438,r&=4095,r|=32768,He.mknod(e,r,0)},mkdir:function(e,r){return r=void 0!==r?r:511,r&=1023,r|=16384,He.mknod(e,r,0)},mkdirTree:function(e,r){for(var t=e.split("/"),n="",o=0;othis.length-1||e<0)){var r=e%this.chunkSize,t=e/this.chunkSize|0;return this.getter(t)[r]}},i.prototype.setDataGetter=function(e){this.getter=e},i.prototype.cacheLength=function(){var e=new XMLHttpRequest;if(e.open("HEAD",t,!1),e.send(null),!(e.status>=200&&e.status<300||304===e.status))throw new Error("Couldn't load "+t+". Status: "+e.status);var r,n=Number(e.getResponseHeader("Content-length")),o=(r=e.getResponseHeader("Accept-Ranges"))&&"bytes"===r,i=(r=e.getResponseHeader("Content-Encoding"))&&"gzip"===r,a=1048576;o||(a=n);var s=this;s.setDataGetter((function(e){var r=e*a,o=(e+1)*a-1;if(o=Math.min(o,n-1),void 0===s.chunks[e]&&(s.chunks[e]=function(e,r){if(e>r)throw new Error("invalid range ("+e+", "+r+") or no bytes requested!");if(r>n-1)throw new Error("only "+n+" bytes available! programmer error!");var o=new XMLHttpRequest;if(o.open("GET",t,!1),n!==a&&o.setRequestHeader("Range","bytes="+e+"-"+r),"undefined"!=typeof Uint8Array&&(o.responseType="arraybuffer"),o.overrideMimeType&&o.overrideMimeType("text/plain; charset=x-user-defined"),o.send(null),!(o.status>=200&&o.status<300||304===o.status))throw new Error("Couldn't load "+t+". Status: "+o.status);return void 0!==o.response?new Uint8Array(o.response||[]):Yn(o.responseText||"",!0)}(r,o)),void 0===s.chunks[e])throw new Error("doXHR failed!");return s.chunks[e]})),!i&&n||(a=n=1,n=this.getter(0).length,a=n,w("LazyFiles on gzip forces download of the whole file when length is accessed")),this._length=n,this._chunkSize=a,this.lengthKnown=!0},"undefined"!=typeof XMLHttpRequest){if(!f)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var a=new i;Object.defineProperties(a,{length:{get:function(){return this.lengthKnown||this.cacheLength(),this._length}},chunkSize:{get:function(){return this.lengthKnown||this.cacheLength(),this._chunkSize}}});var s={isDevice:!1,contents:a}}else s={isDevice:!1,url:t};var u=He.createFile(e,r,s,n,o);s.contents?u.contents=s.contents:s.url&&(u.contents=null,u.url=s.url),Object.defineProperties(u,{usedBytes:{get:function(){return this.contents.length}}});var c={};return Object.keys(u.stream_ops).forEach((function(e){var r=u.stream_ops[e];c[e]=function(){return He.forceLoadFile(u),r.apply(null,arguments)}})),c.read=function(e,r,t,n,o){He.forceLoadFile(u);var i=e.node.contents;if(o>=i.length)return 0;var a=Math.min(i.length-o,n);if(i.slice)for(var s=0;s>2]=n.dev,B[t+4>>2]=0,B[t+8>>2]=n.ino,B[t+12>>2]=n.mode,B[t+16>>2]=n.nlink,B[t+20>>2]=n.uid,B[t+24>>2]=n.gid,B[t+28>>2]=n.rdev,B[t+32>>2]=0,Te=[n.size>>>0,(ke=n.size,+Math.abs(ke)>=1?ke>0?(0|Math.min(+Math.floor(ke/4294967296),4294967295))>>>0:~~+Math.ceil((ke-+(~~ke>>>0))/4294967296)>>>0:0)],B[t+40>>2]=Te[0],B[t+44>>2]=Te[1],B[t+48>>2]=4096,B[t+52>>2]=n.blocks,B[t+56>>2]=n.atime.getTime()/1e3|0,B[t+60>>2]=0,B[t+64>>2]=n.mtime.getTime()/1e3|0,B[t+68>>2]=0,B[t+72>>2]=n.ctime.getTime()/1e3|0,B[t+76>>2]=0,Te=[n.ino>>>0,(ke=n.ino,+Math.abs(ke)>=1?ke>0?(0|Math.min(+Math.floor(ke/4294967296),4294967295))>>>0:~~+Math.ceil((ke-+(~~ke>>>0))/4294967296)>>>0:0)],B[t+80>>2]=Te[0],B[t+84>>2]=Te[1],0},doMsync:function(e,r,t,n,o){var i=j.slice(e,e+t);He.msync(r,i,o,t,n)},doMkdir:function(e,r){return"/"===(e=Ne.normalize(e))[e.length-1]&&(e=e.substr(0,e.length-1)),He.mkdir(e,r,0),0},doMknod:function(e,r,t){switch(61440&r){case 32768:case 8192:case 24576:case 4096:case 49152:break;default:return-28}return He.mknod(e,r,t),0},doReadlink:function(e,r,t){if(t<=0)return-28;var n=He.readlink(e),o=Math.min(t,R(n)),i=M[r+o];return O(n,r,t+1),M[r+o]=i,o},doAccess:function(e,r){if(-8&r)return-28;var t;if(!(t=He.lookupPath(e,{follow:!0}).node))return-44;var n="";return 4&r&&(n+="r"),2&r&&(n+="w"),1&r&&(n+="x"),n&&He.nodePermissions(t,n)?-2:0},doDup:function(e,r,t){var n=He.getStream(t);return n&&He.close(n),He.open(e,r,0,t,t).fd},doReadv:function(e,r,t,n){for(var o=0,i=0;i>2],s=B[r+(8*i+4)>>2],u=He.read(e,M,a,s,n);if(u<0)return-1;if(o+=u,u>2],s=B[r+(8*i+4)>>2],u=He.write(e,M,a,s,n);if(u<0)return-1;o+=u}return o},varargs:void 0,get:function(){return qe.varargs+=4,B[qe.varargs-4>>2]},getStr:function(e){return A(e)},getStreamFromFD:function(e){var r=He.getStream(e);if(!r)throw new He.ErrnoError(8);return r},get64:function(e,r){return e}};function Ve(e,r,t){qe.varargs=t;try{var n=qe.getStreamFromFD(e);switch(r){case 0:return(o=qe.get())<0?-28:He.open(n.path,n.flags,0,o).fd;case 1:case 2:return 0;case 3:return n.flags;case 4:var o=qe.get();return n.flags|=o,0;case 12:o=qe.get();return W[o+0>>1]=2,0;case 13:case 14:return 0;case 16:case 8:return-28;case 9:return We(28),-1;default:return-28}}catch(e){return void 0!==He&&e instanceof He.ErrnoError||ge(e),-e.errno}}function Ge(e,r){try{var t=qe.getStreamFromFD(e);return qe.doStat(He.stat,t.path,r)}catch(e){return void 0!==He&&e instanceof He.ErrnoError||ge(e),-e.errno}}function Xe(e,r,t){qe.varargs=t;try{var n=qe.getStreamFromFD(e);switch(r){case 21509:case 21505:return n.tty?0:-59;case 21510:case 21511:case 21512:case 21506:case 21507:case 21508:return n.tty?0:-59;case 21519:if(!n.tty)return-59;var o=qe.get();return B[o>>2]=0,0;case 21520:return n.tty?-28:-59;case 21531:o=qe.get();return He.ioctl(n,r,o);case 21523:case 21524:return n.tty?0:-59;default:ge("bad ioctl syscall "+r)}}catch(e){return void 0!==He&&e instanceof He.ErrnoError||ge(e),-e.errno}}function Ye(e,r,t){qe.varargs=t;try{var n=qe.getStr(e),o=qe.get();return He.open(n,r,o).fd}catch(e){return void 0!==He&&e instanceof He.ErrnoError||ge(e),-e.errno}}function Ke(e,r){try{return e=qe.getStr(e),qe.doStat(He.stat,e,r)}catch(e){return void 0!==He&&e instanceof He.ErrnoError||ge(e),-e.errno}}var Ze={};function Je(e){for(;e.length;){var r=e.pop();e.pop()(r)}}function Qe(e){return this.fromWireType(U[e>>2])}var er={},rr={},tr={},nr=48,or=57;function ir(e){if(void 0===e)return"_unknown";var r=(e=e.replace(/[^a-zA-Z0-9_]/g,"$")).charCodeAt(0);return r>=nr&&r<=or?"_"+e:e}function ar(e,r){return e=ir(e),new Function("body","return function "+e+'() {\n "use strict"; return body.apply(this, arguments);\n};\n')(r)}function sr(e,r){var t=ar(r,(function(e){this.name=r,this.message=e;var t=new Error(e).stack;void 0!==t&&(this.stack=this.toString()+"\n"+t.replace(/^Error(:[^\n]*)?\n/,""))}));return t.prototype=Object.create(e.prototype),t.prototype.constructor=t,t.prototype.toString=function(){return void 0===this.message?this.name:this.name+": "+this.message},t}var ur=void 0;function cr(e){throw new ur(e)}function fr(e,r,t){function n(r){var n=t(r);n.length!==e.length&&cr("Mismatched type converter count");for(var o=0;o>i])},destructorFunction:null})}function br(e){if(!(this instanceof Nr))return!1;if(!(e instanceof Nr))return!1;for(var r=this.$$.ptrType.registeredClass,t=this.$$.ptr,n=e.$$.ptrType.registeredClass,o=e.$$.ptr;r.baseClass;)t=r.upcast(t),r=r.baseClass;for(;n.baseClass;)o=n.upcast(o),n=n.baseClass;return r===n&&t===o}function kr(e){return{count:e.count,deleteScheduled:e.deleteScheduled,preservePointerOnDelete:e.preservePointerOnDelete,ptr:e.ptr,ptrType:e.ptrType,smartPtr:e.smartPtr,smartPtrType:e.smartPtrType}}function Tr(e){wr(e.$$.ptrType.registeredClass.name+" instance already deleted")}var Pr=!1;function Fr(e){}function Dr(e){e.smartPtr?e.smartPtrType.rawDestructor(e.smartPtr):e.ptrType.registeredClass.rawDestructor(e.ptr)}function Cr(e){e.count.value-=1,0===e.count.value&&Dr(e)}function Sr(e){return"undefined"==typeof FinalizationGroup?(Sr=function(e){return e},e):(Pr=new FinalizationGroup((function(e){for(var r=e.next();!r.done;r=e.next()){var t=r.value;t.ptr?Cr(t):console.warn("object already deleted: "+t.ptr)}})),Fr=function(e){Pr.unregister(e.$$)},(Sr=function(e){return Pr.register(e,e.$$,e.$$),e})(e))}function Ar(){if(this.$$.ptr||Tr(this),this.$$.preservePointerOnDelete)return this.$$.count.value+=1,this;var e=Sr(Object.create(Object.getPrototypeOf(this),{$$:{value:kr(this.$$)}}));return e.$$.count.value+=1,e.$$.deleteScheduled=!1,e}function $r(){this.$$.ptr||Tr(this),this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete&&wr("Object already scheduled for deletion"),Fr(this),Cr(this.$$),this.$$.preservePointerOnDelete||(this.$$.smartPtr=void 0,this.$$.ptr=void 0)}function Or(){return!this.$$.ptr}var Rr=void 0,xr=[];function Mr(){for(;xr.length;){var e=xr.pop();e.$$.deleteScheduled=!1,e.delete()}}function jr(){return this.$$.ptr||Tr(this),this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete&&wr("Object already scheduled for deletion"),xr.push(this),1===xr.length&&Rr&&Rr(Mr),this.$$.deleteScheduled=!0,this}function Wr(){Nr.prototype.isAliasOf=br,Nr.prototype.clone=Ar,Nr.prototype.delete=$r,Nr.prototype.isDeleted=Or,Nr.prototype.deleteLater=jr}function Nr(){}var Br={};function Ur(e,r,t){if(void 0===e[r].overloadTable){var n=e[r];e[r]=function(){return e[r].overloadTable.hasOwnProperty(arguments.length)||wr("Function '"+t+"' called with an invalid number of arguments ("+arguments.length+") - expects one of ("+e[r].overloadTable+")!"),e[r].overloadTable[arguments.length].apply(this,arguments)},e[r].overloadTable=[],e[r].overloadTable[n.argCount]=n}}function zr(e,r,t){o.hasOwnProperty(e)?((void 0===t||void 0!==o[e].overloadTable&&void 0!==o[e].overloadTable[t])&&wr("Cannot register public name '"+e+"' twice"),Ur(o,e,e),o.hasOwnProperty(t)&&wr("Cannot register multiple overloads of a function with the same number of arguments ("+t+")!"),o[e].overloadTable[t]=r):(o[e]=r,void 0!==t&&(o[e].numArguments=t))}function Ir(e,r,t,n,o,i,a,s){this.name=e,this.constructor=r,this.instancePrototype=t,this.rawDestructor=n,this.baseClass=o,this.getActualType=i,this.upcast=a,this.downcast=s,this.pureVirtualFunctions=[]}function Lr(e,r,t){for(;r!==t;)r.upcast||wr("Expected null or instance of "+t.name+", got an instance of "+r.name),e=r.upcast(e),r=r.baseClass;return e}function Hr(e,r){if(null===r)return this.isReference&&wr("null is not a valid "+this.name),0;r.$$||wr('Cannot pass "'+Wt(r)+'" as a '+this.name),r.$$.ptr||wr("Cannot pass deleted object as a pointer of type "+this.name);var t=r.$$.ptrType.registeredClass;return Lr(r.$$.ptr,t,this.registeredClass)}function qr(e,r){var t;if(null===r)return this.isReference&&wr("null is not a valid "+this.name),this.isSmartPointer?(t=this.rawConstructor(),null!==e&&e.push(this.rawDestructor,t),t):0;r.$$||wr('Cannot pass "'+Wt(r)+'" as a '+this.name),r.$$.ptr||wr("Cannot pass deleted object as a pointer of type "+this.name),!this.isConst&&r.$$.ptrType.isConst&&wr("Cannot convert argument of type "+(r.$$.smartPtrType?r.$$.smartPtrType.name:r.$$.ptrType.name)+" to parameter type "+this.name);var n=r.$$.ptrType.registeredClass;if(t=Lr(r.$$.ptr,n,this.registeredClass),this.isSmartPointer)switch(void 0===r.$$.smartPtr&&wr("Passing raw pointer to smart pointer is illegal"),this.sharingPolicy){case 0:r.$$.smartPtrType===this?t=r.$$.smartPtr:wr("Cannot convert argument of type "+(r.$$.smartPtrType?r.$$.smartPtrType.name:r.$$.ptrType.name)+" to parameter type "+this.name);break;case 1:t=r.$$.smartPtr;break;case 2:if(r.$$.smartPtrType===this)t=r.$$.smartPtr;else{var o=r.clone();t=this.rawShare(t,$t((function(){o.delete()}))),null!==e&&e.push(this.rawDestructor,t)}break;default:wr("Unsupporting sharing policy")}return t}function Vr(e,r){if(null===r)return this.isReference&&wr("null is not a valid "+this.name),0;r.$$||wr('Cannot pass "'+Wt(r)+'" as a '+this.name),r.$$.ptr||wr("Cannot pass deleted object as a pointer of type "+this.name),r.$$.ptrType.isConst&&wr("Cannot convert argument of type "+r.$$.ptrType.name+" to parameter type "+this.name);var t=r.$$.ptrType.registeredClass;return Lr(r.$$.ptr,t,this.registeredClass)}function Gr(e){return this.rawGetPointee&&(e=this.rawGetPointee(e)),e}function Xr(e){this.rawDestructor&&this.rawDestructor(e)}function Yr(e){null!==e&&e.delete()}function Kr(e,r,t){if(r===t)return e;if(void 0===t.baseClass)return null;var n=Kr(e,r,t.baseClass);return null===n?null:t.downcast(n)}function Zr(){return Object.keys(rt).length}function Jr(){var e=[];for(var r in rt)rt.hasOwnProperty(r)&&e.push(rt[r]);return e}function Qr(e){Rr=e,xr.length&&Rr&&Rr(Mr)}function et(){o.getInheritedInstanceCount=Zr,o.getLiveInheritedInstances=Jr,o.flushPendingDeletes=Mr,o.setDelayFunction=Qr}var rt={};function tt(e,r){for(void 0===r&&wr("ptr should not be undefined");e.baseClass;)r=e.upcast(r),e=e.baseClass;return r}function nt(e,r){return r=tt(e,r),rt[r]}function ot(e,r){return r.ptrType&&r.ptr||cr("makeClassHandle requires ptr and ptrType"),!!r.smartPtrType!==!!r.smartPtr&&cr("Both smartPtrType and smartPtr must be specified"),r.count={value:1},Sr(Object.create(e,{$$:{value:r}}))}function it(e){var r=this.getPointee(e);if(!r)return this.destructor(e),null;var t=nt(this.registeredClass,r);if(void 0!==t){if(0===t.$$.count.value)return t.$$.ptr=r,t.$$.smartPtr=e,t.clone();var n=t.clone();return this.destructor(e),n}function o(){return this.isSmartPointer?ot(this.registeredClass.instancePrototype,{ptrType:this.pointeeType,ptr:r,smartPtrType:this,smartPtr:e}):ot(this.registeredClass.instancePrototype,{ptrType:this,ptr:e})}var i,a=this.registeredClass.getActualType(r),s=Br[a];if(!s)return o.call(this);i=this.isConst?s.constPointerType:s.pointerType;var u=Kr(r,this.registeredClass,i.registeredClass);return null===u?o.call(this):this.isSmartPointer?ot(i.registeredClass.instancePrototype,{ptrType:i,ptr:u,smartPtrType:this,smartPtr:e}):ot(i.registeredClass.instancePrototype,{ptrType:i,ptr:u})}function at(){st.prototype.getPointee=Gr,st.prototype.destructor=Xr,st.prototype.argPackAdvance=8,st.prototype.readValueFromPointer=Qe,st.prototype.deleteObject=Yr,st.prototype.fromWireType=it}function st(e,r,t,n,o,i,a,s,u,c,f){this.name=e,this.registeredClass=r,this.isReference=t,this.isConst=n,this.isSmartPointer=o,this.pointeeType=i,this.sharingPolicy=a,this.rawGetPointee=s,this.rawConstructor=u,this.rawShare=c,this.rawDestructor=f,o||void 0!==r.baseClass?this.toWireType=qr:n?(this.toWireType=Hr,this.destructorFunction=null):(this.toWireType=Vr,this.destructorFunction=null)}function ut(e,r,t){o.hasOwnProperty(e)||cr("Replacing nonexistant public symbol"),void 0!==o[e].overloadTable&&void 0!==t?o[e].overloadTable[t]=r:(o[e]=r,o[e].argCount=t)}function ct(e,r,t){return t&&t.length?o["dynCall_"+e].apply(null,[r].concat(t)):o["dynCall_"+e].call(null,r)}function ft(e,r,t){return-1!=e.indexOf("j")?ct(e,r,t):re.get(r).apply(null,t)}function lt(e,r){D(e.indexOf("j")>=0,"getDynCaller should only be called with i64 sigs");var t=[];return function(){t.length=arguments.length;for(var n=0;n0?", ":"")+l),d+=(c?"var rv = ":"")+"invoker(fn"+(l.length>0?", ":"")+l+");\n",s)d+="runDestructors(destructors);\n";else for(u=a?1:2;u>2)+n]);return t}function _t(e,r,t,n,o,i,a){var s=wt(t,n);r=gr(r),i=dt(o,i),fr([],[e],(function(e){var n=(e=e[0]).name+"."+r;function o(){mt("Cannot call "+n+" due to unbound types",s)}var u=e.registeredClass.constructor;return void 0===u[r]?(o.argCount=t-1,u[r]=o):(Ur(u,r,n),u[r].overloadTable[t-1]=o),fr([],s,(function(e){var o=[e[0],null].concat(e.slice(1)),s=yt(n,o,null,i,a);return void 0===u[r].overloadTable?(s.argCount=t-1,u[r]=s):u[r].overloadTable[t-1]=s,[]})),[]}))}function Et(e,r,t,n,o,i){D(r>0);var a=wt(r,t);o=dt(n,o);var s=[i],u=[];fr([],[e],(function(e){var t="constructor "+(e=e[0]).name;if(void 0===e.registeredClass.constructor_body&&(e.registeredClass.constructor_body=[]),void 0!==e.registeredClass.constructor_body[r-1])throw new yr("Cannot register multiple constructors with identical number of parameters ("+(r-1)+") for class '"+e.name+"'! Overload resolution is currently only performed using the parameter count, not actual type info!");return e.registeredClass.constructor_body[r-1]=function(){mt("Cannot construct "+e.name+" due to unbound types",a)},fr([],a,(function(n){return e.registeredClass.constructor_body[r-1]=function(){arguments.length!==r-1&&wr(t+" called with "+arguments.length+" arguments, expected "+(r-1)),u.length=0,s.length=r;for(var e=1;e4&&0==--Ft[e].refcount&&(Ft[e]=void 0,Pt.push(e))}function Ct(){for(var e=0,r=5;r>1])};case 2:return function(e){var r=t?B:U;return this.fromWireType(r[e>>2])};default:throw new TypeError("Unknown integer type: "+e)}}function xt(e,r,t,n){var o=hr(t);function i(){}r=gr(r),i.values={},_r(e,{name:r,constructor:i,fromWireType:function(e){return this.constructor.values[e]},toWireType:function(e,r){return r.value},argPackAdvance:8,readValueFromPointer:Rt(r,o,n),destructorFunction:null}),zr(r,i)}function Mt(e,r){var t=rr[e];return void 0===t&&wr(r+" has unknown type "+ht(e)),t}function jt(e,r,t){var n=Mt(e,"enum");r=gr(r);var o=n.constructor,i=Object.create(n.constructor.prototype,{value:{value:t},constructor:{value:ar(n.name+"_"+r,(function(){}))}});o.values[t]=i,o[r]=i}function Wt(e){if(null===e)return"null";var r=typeof e;return"object"===r||"array"===r||"function"===r?e.toString():""+e}function Nt(e,r){switch(r){case 2:return function(e){return this.fromWireType(z[e>>2])};case 3:return function(e){return this.fromWireType(I[e>>3])};default:throw new TypeError("Unknown float type: "+e)}}function Bt(e,r,t){var n=hr(t);_r(e,{name:r=gr(r),fromWireType:function(e){return e},toWireType:function(e,r){if("number"!=typeof r&&"boolean"!=typeof r)throw new TypeError('Cannot convert "'+Wt(r)+'" to '+this.name);return r},argPackAdvance:8,readValueFromPointer:Nt(r,n),destructorFunction:null})}function Ut(e,r,t){switch(r){case 0:return t?function(e){return M[e]}:function(e){return j[e]};case 1:return t?function(e){return W[e>>1]}:function(e){return N[e>>1]};case 2:return t?function(e){return B[e>>2]}:function(e){return U[e>>2]};default:throw new TypeError("Unknown integer type: "+e)}}function zt(e,r,t,n,o){r=gr(r),-1===o&&(o=4294967295);var i=hr(t),a=function(e){return e};if(0===n){var s=32-8*t;a=function(e){return e<>>s}}var u=-1!=r.indexOf("unsigned");_r(e,{name:r,fromWireType:a,toWireType:function(e,t){if("number"!=typeof t&&"boolean"!=typeof t)throw new TypeError('Cannot convert "'+Wt(t)+'" to '+this.name);if(to)throw new TypeError('Passing a number "'+Wt(t)+'" from JS side to C/C++ side to an argument of type "'+r+'", which is outside the valid range ['+n+", "+o+"]!");return u?t>>>0:0|t},argPackAdvance:8,readValueFromPointer:Ut(r,i,0!==n),destructorFunction:null})}function It(e,r,t){var n=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array][r];function o(e){var r=U,t=r[e>>=2],o=r[e+1];return new n(x,o,t)}_r(e,{name:t=gr(t),fromWireType:o,argPackAdvance:8,readValueFromPointer:o},{ignoreDuplicateRegistrations:!0})}function Lt(e,r){var t="std::string"===(r=gr(r));_r(e,{name:r,fromWireType:function(e){var r,n=U[e>>2];if(t)for(var o=e+4,i=0;i<=n;++i){var a=e+4+i;if(i==n||0==j[a]){var s=A(o,a-o);void 0===r?r=s:(r+=String.fromCharCode(0),r+=s),o=a+1}}else{var u=new Array(n);for(i=0;i>2]=o,t&&n)O(r,i+4,o+1);else if(n)for(var a=0;a255&&(eo(i),wr("String has UTF-16 code units that do not fit in 8 bits")),j[i+4+a]=s}else for(a=0;a>2],a=i(),u=e+4,c=0;c<=o;++c){var f=e+4+c*r;if(c==o||0==a[f>>s]){var l=n(u,f-u);void 0===t?t=l:(t+=String.fromCharCode(0),t+=l),u=f+r}}return eo(e),t},toWireType:function(e,n){"string"!=typeof n&&wr("Cannot pass non-string to C++ string type "+t);var i=a(n),u=Qn(4+i+r);return U[u>>2]=i>>s,o(n,u+4,i+r),null!==e&&e.push(eo,u),u},argPackAdvance:8,readValueFromPointer:Qe,destructorFunction:function(e){eo(e)}})}function qt(e,r,t,n,o,i){Ze[e]={name:gr(r),rawConstructor:dt(t,n),rawDestructor:dt(o,i),elements:[]}}function Vt(e,r,t,n,o,i,a,s,u){Ze[e].elements.push({getterReturnType:r,getter:dt(t,n),getterContext:o,setterArgumentType:i,setter:dt(a,s),setterContext:u})}function Gt(e,r,t,n,o,i){dr[e]={name:gr(r),rawConstructor:dt(t,n),rawDestructor:dt(o,i),fields:[]}}function Xt(e,r,t,n,o,i,a,s,u,c){dr[e].fields.push({fieldName:gr(r),getterReturnType:t,getter:dt(n,o),getterContext:i,setterArgumentType:a,setter:dt(s,u),setterContext:c})}function Yt(e,r){_r(e,{isVoid:!0,name:r=gr(r),argPackAdvance:0,fromWireType:function(){},toWireType:function(e,r){}})}function Kt(e){return e||wr("Cannot use deleted val. handle = "+e),Ft[e].value}function Zt(e,r,t){e=Kt(e),r=Mt(r,"emval::as");var n=[],o=$t(n);return B[t>>2]=o,r.toWireType(n,e)}function Jt(e){var r=[];return B[e>>2]=$t(r),r}var Qt={};function en(e){var r=Qt[e];return void 0===r?gr(e):r}var rn=[];function tn(e,r,t,n,o){return(e=rn[e])(r=Kt(r),t=en(t),Jt(n),o)}function nn(e,r,t,n){(e=rn[e])(r=Kt(r),t=en(t),null,n)}function on(e,r){return(e=Kt(e))==(r=Kt(r))}function an(){return"object"==typeof globalThis?globalThis:Function("return this")()}function sn(e){return 0===e?$t(an()):(e=en(e),$t(an()[e]))}function un(e){var r=rn.length;return rn.push(e),r}function cn(e,r){for(var t=new Array(e),n=0;n>2)+n],"parameter "+n);return t}function fn(e,r){for(var t=cn(e,r),n=t[0],o=n.name+"_$"+t.slice(1).map((function(e){return e.name})).join("_")+"$",i=["retType"],a=[n],s="",u=0;u4&&(Ft[e].refcount+=1)}function hn(e,r){return(e=Kt(e))instanceof(r=Kt(r))}function mn(e){return"number"==typeof(e=Kt(e))}function vn(e){return"string"==typeof(e=Kt(e))}function gn(e){for(var r="",t=0;t>> 2) + "+t+'], "parameter '+t+'");\nvar arg'+t+" = argType"+t+".readValueFromPointer(args);\nargs += argType"+t+"['argPackAdvance'];\n";return n+="var obj = new constructor("+r+");\nreturn __emval_register(obj);\n}\n",new Function("requireRegisteredType","Module","__emval_register",n)(Mt,o,$t)}var yn,wn={};function _n(e,r,t,n){e=Kt(e);var o=wn[r];return o||(o=gn(r),wn[r]=o),o(e,t,n)}function En(){return $t([])}function bn(e){return $t(en(e))}function kn(){return $t({})}function Tn(e){Je(Ft[e].value),Dt(e)}function Pn(e,r,t){e=Kt(e),r=Kt(r),t=Kt(t),e[r]=t}function Fn(e,r){return $t((e=Mt(e,"_emval_take_value")).readValueFromPointer(r))}function Dn(){ge()}function Cn(e,r,t){j.copyWithin(e,r,r+t)}function Sn(){return j.length}function An(e){try{return T.grow(e-x.byteLength+65535>>>16),ee(T.buffer),1}catch(e){}}function $n(e){e>>>=0;var r=Sn(),t=2147483648;if(e>t)return!1;for(var n=1;n<=4;n*=2){var o=r*(1+.2/n);if(o=Math.min(o,e+100663296),An(Math.min(t,Q(Math.max(16777216,e,o),65536))))return!0}return!1}function On(e){for(var r=yn();yn()-r0?t:R(e)+1,o=new Array(n),i=$(e,o,0,o.length);return r&&(o.length=i),o}ne.push({func:function(){Jn()}});var Kn,Zn={__cxa_allocate_exception:$e,__cxa_atexit:Oe,__cxa_throw:xe,__gmtime_r:je,__sys_fcntl64:Ve,__sys_fstat64:Ge,__sys_ioctl:Xe,__sys_open:Ye,__sys_stat64:Ke,_embind_finalize_value_array:lr,_embind_finalize_value_object:pr,_embind_register_bool:Er,_embind_register_class:vt,_embind_register_class_class_function:_t,_embind_register_class_constructor:Et,_embind_register_class_function:bt,_embind_register_class_property:Tt,_embind_register_emval:Ot,_embind_register_enum:xt,_embind_register_enum_value:jt,_embind_register_float:Bt,_embind_register_integer:zt,_embind_register_memory_view:It,_embind_register_std_string:Lt,_embind_register_std_wstring:Ht,_embind_register_value_array:qt,_embind_register_value_array_element:Vt,_embind_register_value_object:Gt,_embind_register_value_object_field:Xt,_embind_register_void:Yt,_emval_as:Zt,_emval_call_method:tn,_emval_call_void_method:nn,_emval_decref:Dt,_emval_equals:on,_emval_get_global:sn,_emval_get_method_caller:fn,_emval_get_module_property:ln,_emval_get_property:dn,_emval_incref:pn,_emval_instanceof:hn,_emval_is_number:mn,_emval_is_string:vn,_emval_new:_n,_emval_new_array:En,_emval_new_cstring:bn,_emval_new_object:kn,_emval_run_destructors:Tn,_emval_set_property:Pn,_emval_take_value:Fn,abort:Dn,emscripten_memcpy_big:Cn,emscripten_resize_heap:$n,emscripten_thread_sleep:On,environ_get:jn,environ_sizes_get:Wn,fd_close:Nn,fd_fdstat_get:Bn,fd_read:Un,fd_seek:zn,fd_write:In,setTempRet0:Ln,time:Hn,uuid_generate:qn},Jn=(Ce(),o.___wasm_call_ctors=function(){return(Jn=o.___wasm_call_ctors=o.asm.__wasm_call_ctors).apply(null,arguments)}),Qn=o._malloc=function(){return(Qn=o._malloc=o.asm.malloc).apply(null,arguments)},eo=o._free=function(){return(eo=o._free=o.asm.free).apply(null,arguments)},ro=o.___getTypeName=function(){return(ro=o.___getTypeName=o.asm.__getTypeName).apply(null,arguments)},to=(o.___embind_register_native_and_builtin_types=function(){return(o.___embind_register_native_and_builtin_types=o.asm.__embind_register_native_and_builtin_types).apply(null,arguments)},o.___errno_location=function(){return(to=o.___errno_location=o.asm.__errno_location).apply(null,arguments)});o.stackSave=function(){return(o.stackSave=o.asm.stackSave).apply(null,arguments)},o.stackRestore=function(){return(o.stackRestore=o.asm.stackRestore).apply(null,arguments)},o.stackAlloc=function(){return(o.stackAlloc=o.asm.stackAlloc).apply(null,arguments)},o._setThrew=function(){return(o._setThrew=o.asm.setThrew).apply(null,arguments)},o.dynCall_ji=function(){return(o.dynCall_ji=o.asm.dynCall_ji).apply(null,arguments)},o.dynCall_jiji=function(){return(o.dynCall_jiji=o.asm.dynCall_jiji).apply(null,arguments)};function no(e){this.name="ExitStatus",this.message="Program terminated with exit("+e+")",this.status=e}function oo(e){function r(){Kn||(Kn=!0,o.calledRun=!0,F||(se(),ue(),t(o),o.onRuntimeInitialized&&o.onRuntimeInitialized(),ce()))}e=e||s,de>0||(ae(),de>0||(o.setStatus?(o.setStatus("Running..."),setTimeout((function(){setTimeout((function(){o.setStatus("")}),1),r()}),1)):r()))}if(he=function e(){Kn||oo(),Kn||(he=e)},o.run=oo,o.preInit)for("function"==typeof o.preInit&&(o.preInit=[o.preInit]);o.preInit.length>0;)o.preInit.pop()();return!0,oo(),r.ready}}();"object"==typeof exports&&"object"==typeof module?module.exports=rhino3dm:"function"==typeof define&&define.amd?define([],(function(){return rhino3dm})):"object"==typeof exports&&(exports.rhino3dm=rhino3dm); +//# sourceMappingURL=/sm/6e74fdd28ca1766a1ea2cdbd056174acf9467b91d74b728f86f6dccdef311ecf.map \ No newline at end of file diff --git a/libs/rhino3dm.wasm b/libs/rhino3dm.wasm new file mode 100644 index 0000000..622829f Binary files /dev/null and b/libs/rhino3dm.wasm differ diff --git a/package.json b/package.json index 84b34b6..02406fd 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "online-3d-viewer", "description": "Online 3D Viewer", - "version": "0.7.7", + "version": "0.7.8", "repository": "github:kovacsv/Online3DViewer", "license": "MIT", "devDependencies": { diff --git a/source/export/exporter.js b/source/export/exporter.js index dd27fec..54eb751 100644 --- a/source/export/exporter.js +++ b/source/export/exporter.js @@ -11,16 +11,32 @@ OV.Exporter = class ]; } - Export (model, format, extension) + AddExporter (exporter) { - let files = []; + this.exporters.push (exporter); + } + + Export (model, format, extension, callbacks) + { + let exporter = null; for (let i = 0; i < this.exporters.length; i++) { - let exporter = this.exporters[i]; - if (exporter.CanExport (format, extension)) { - exporter.Export (model, format, files); + let currentExporter = this.exporters[i]; + if (currentExporter.CanExport (format, extension)) { + exporter = currentExporter; break; } } - return files; + if (exporter === null) { + callbacks.onError (); + return; + } + + exporter.Export (model, format, function (files) { + if (files.length === 0) { + callbacks.onError (); + } else { + callbacks.onSuccess (files); + } + }); } }; diff --git a/source/export/exporterbase.js b/source/export/exporterbase.js index 27d3d34..889505e 100644 --- a/source/export/exporterbase.js +++ b/source/export/exporterbase.js @@ -39,12 +39,15 @@ OV.ExporterBase = class return false; } - Export (model, format, files) + Export (model, format, onFinish) { - this.ExportContent (model, format, files); + let files = []; + this.ExportContent (model, format, files, function () { + onFinish (files); + }); } - ExportContent (model, format, files) + ExportContent (model, format, files, onFinish) { } diff --git a/source/export/exportergltf.js b/source/export/exportergltf.js index b931487..dce8a91 100644 --- a/source/export/exportergltf.js +++ b/source/export/exportergltf.js @@ -20,13 +20,14 @@ OV.ExporterGltf = class extends OV.ExporterBase return (format === OV.FileFormat.Text && extension === 'gltf') || (format === OV.FileFormat.Binary && extension === 'glb'); } - ExportContent (model, format, files) + ExportContent (model, format, files, onFinish) { if (format === OV.FileFormat.Text) { this.ExportAsciiContent (model, files); } else if (format === OV.FileFormat.Binary) { this.ExportBinaryContent (model, files); } + onFinish (); } ExportAsciiContent (model, files) @@ -195,9 +196,8 @@ OV.ExporterGltf = class extends OV.ExporterBase let writer = new OV.BinaryWriter (mainBufferSize, true); for (let meshIndex = 0; meshIndex < meshDataArr.length; meshIndex++) { let meshData = meshDataArr[meshIndex]; - let primitives = meshData.buffer.primitives; - for (let primitiveIndex = 0; primitiveIndex < primitives.length; primitiveIndex++) { - let primitive = primitives[primitiveIndex]; + for (let primitiveIndex = 0; primitiveIndex < meshData.buffer.PrimitiveCount (); primitiveIndex++) { + let primitive = meshData.buffer.GetPrimitive (primitiveIndex); let offset = writer.GetPosition (); for (let i = 0; i < primitive.indices.length; i++) { writer.WriteUnsignedInteger32 (primitive.indices[i]); @@ -408,6 +408,7 @@ OV.ExporterGltf = class extends OV.ExporterBase roughnessFactor : 1.0 }, emissiveFactor : ColorToRGB (material.emissive), + doubleSided : true, alphaMode : 'OPAQUE' }; diff --git a/source/export/exporterobj.js b/source/export/exporterobj.js index 51bea6d..be56287 100644 --- a/source/export/exporterobj.js +++ b/source/export/exporterobj.js @@ -1,115 +1,116 @@ OV.ExporterObj = class extends OV.ExporterBase { - constructor () - { - super (); - } + constructor () + { + super (); + } CanExport (format, extension) { return format === OV.FileFormat.Text && extension === 'obj'; } - ExportContent (model, format, files) - { - function WriteTexture (mtlWriter, keyword, texture, files) - { - if (texture === null || !texture.IsValid ()) { - return; - } - let fileName = OV.GetFileName (texture.name); - mtlWriter.WriteArrayLine ([keyword, fileName]); + ExportContent (model, format, files, onFinish) + { + function WriteTexture (mtlWriter, keyword, texture, files) + { + if (texture === null || !texture.IsValid ()) { + return; + } + let fileName = OV.GetFileName (texture.name); + mtlWriter.WriteArrayLine ([keyword, fileName]); - let fileIndex = files.findIndex (function (file) { - return file.GetName () === fileName; - }); - if (fileIndex === -1) { - let textureFile = new OV.ExportedFile (fileName); - textureFile.SetContent (texture.buffer); - files.push (textureFile); - } - } + let fileIndex = files.findIndex (function (file) { + return file.GetName () === fileName; + }); + if (fileIndex === -1) { + let textureFile = new OV.ExportedFile (fileName); + textureFile.SetContent (texture.buffer); + files.push (textureFile); + } + } - let mtlFile = new OV.ExportedFile ('model.mtl'); - let objFile = new OV.ExportedFile ('model.obj'); + let mtlFile = new OV.ExportedFile ('model.mtl'); + let objFile = new OV.ExportedFile ('model.obj'); - files.push (mtlFile); - files.push (objFile); + files.push (mtlFile); + files.push (objFile); - let mtlWriter = new OV.TextWriter (); - mtlWriter.WriteLine (this.GetHeaderText ()); - for (let materialIndex = 0; materialIndex < model.MaterialCount (); materialIndex++) { - let material = model.GetMaterial (materialIndex); - mtlWriter.WriteArrayLine (['newmtl', this.GetExportedMaterialName (material.name)]); - mtlWriter.WriteArrayLine (['Ka', material.ambient.r / 255.0, material.ambient.g / 255.0, material.ambient.b / 255.0]); - mtlWriter.WriteArrayLine (['Kd', material.diffuse.r / 255.0, material.diffuse.g / 255.0, material.diffuse.b / 255.0]); - mtlWriter.WriteArrayLine (['Ks', material.specular.r / 255.0, material.specular.g / 255.0, material.specular.b / 255.0]); - mtlWriter.WriteArrayLine (['Ns', material.shininess * 100.0]); - mtlWriter.WriteArrayLine (['d', material.opacity]); - WriteTexture (mtlWriter, 'map_Kd', material.diffuseMap, files); - WriteTexture (mtlWriter, 'map_Ks', material.specularMap, files); - WriteTexture (mtlWriter, 'bump', material.bumpMap, files); - } - mtlFile.SetContent (mtlWriter.GetText ()); + let mtlWriter = new OV.TextWriter (); + mtlWriter.WriteLine (this.GetHeaderText ()); + for (let materialIndex = 0; materialIndex < model.MaterialCount (); materialIndex++) { + let material = model.GetMaterial (materialIndex); + mtlWriter.WriteArrayLine (['newmtl', this.GetExportedMaterialName (material.name)]); + mtlWriter.WriteArrayLine (['Ka', material.ambient.r / 255.0, material.ambient.g / 255.0, material.ambient.b / 255.0]); + mtlWriter.WriteArrayLine (['Kd', material.diffuse.r / 255.0, material.diffuse.g / 255.0, material.diffuse.b / 255.0]); + mtlWriter.WriteArrayLine (['Ks', material.specular.r / 255.0, material.specular.g / 255.0, material.specular.b / 255.0]); + mtlWriter.WriteArrayLine (['Ns', material.shininess * 1000.0]); + mtlWriter.WriteArrayLine (['d', material.opacity]); + WriteTexture (mtlWriter, 'map_Kd', material.diffuseMap, files); + WriteTexture (mtlWriter, 'map_Ks', material.specularMap, files); + WriteTexture (mtlWriter, 'bump', material.bumpMap, files); + } + mtlFile.SetContent (mtlWriter.GetText ()); - let objWriter = new OV.TextWriter (); - objWriter.WriteLine (this.GetHeaderText ()); - objWriter.WriteArrayLine (['mtllib', mtlFile.GetName ()]); - let vertexOffset = 0; - let normalOffset = 0; - let uvOffset = 0; - let usedMaterialName = null; - for (let meshIndex = 0; meshIndex < model.MeshCount (); meshIndex++) { - let mesh = model.GetMesh (meshIndex); - objWriter.WriteArrayLine (['g', this.GetExportedMeshName (mesh.GetName ())]); - for (let vertexIndex = 0; vertexIndex < mesh.VertexCount (); vertexIndex++) { - let vertex = mesh.GetVertex (vertexIndex); - objWriter.WriteArrayLine (['v', vertex.x, vertex.y, vertex.z]); - } - for (let normalIndex = 0; normalIndex < mesh.NormalCount (); normalIndex++) { - let normal = mesh.GetNormal (normalIndex); - objWriter.WriteArrayLine (['vn', normal.x, normal.y, normal.z]); - } - for (let textureUVIndex = 0; textureUVIndex < mesh.TextureUVCount (); textureUVIndex++) { - let uv = mesh.GetTextureUV (textureUVIndex); - objWriter.WriteArrayLine (['vt', uv.x, uv.y]); - } - for (let triangleIndex = 0; triangleIndex < mesh.TriangleCount (); triangleIndex++) { - let triangle = mesh.GetTriangle (triangleIndex); - let v0 = triangle.v0 + vertexOffset + 1; - let v1 = triangle.v1 + vertexOffset + 1; - let v2 = triangle.v2 + vertexOffset + 1; - let n0 = triangle.n0 + normalOffset + 1; - let n1 = triangle.n1 + normalOffset + 1; - let n2 = triangle.n2 + normalOffset + 1; - if (triangle.mat !== null) { - let material = model.GetMaterial (triangle.mat); - let materialName = this.GetExportedMaterialName (material.name); - if (materialName !== usedMaterialName) { - objWriter.WriteArrayLine (['usemtl', materialName]); - usedMaterialName = materialName; - } - } - let u0 = ''; - let u1 = ''; - let u2 = ''; - if (triangle.HasTextureUVs ()) { - u0 = triangle.u0 + uvOffset + 1; - u1 = triangle.u1 + uvOffset + 1; - u2 = triangle.u2 + uvOffset + 1; - } - objWriter.WriteArrayLine (['f', [v0, u0, n0].join ('/'), [v1, u1, n1].join ('/'), [v2, u2, n2].join ('/')]); - } - vertexOffset += mesh.VertexCount (); - normalOffset += mesh.NormalCount (); - uvOffset += mesh.TextureUVCount (); - } + let objWriter = new OV.TextWriter (); + objWriter.WriteLine (this.GetHeaderText ()); + objWriter.WriteArrayLine (['mtllib', mtlFile.GetName ()]); + let vertexOffset = 0; + let normalOffset = 0; + let uvOffset = 0; + let usedMaterialName = null; + for (let meshIndex = 0; meshIndex < model.MeshCount (); meshIndex++) { + let mesh = model.GetMesh (meshIndex); + objWriter.WriteArrayLine (['g', this.GetExportedMeshName (mesh.GetName ())]); + for (let vertexIndex = 0; vertexIndex < mesh.VertexCount (); vertexIndex++) { + let vertex = mesh.GetVertex (vertexIndex); + objWriter.WriteArrayLine (['v', vertex.x, vertex.y, vertex.z]); + } + for (let normalIndex = 0; normalIndex < mesh.NormalCount (); normalIndex++) { + let normal = mesh.GetNormal (normalIndex); + objWriter.WriteArrayLine (['vn', normal.x, normal.y, normal.z]); + } + for (let textureUVIndex = 0; textureUVIndex < mesh.TextureUVCount (); textureUVIndex++) { + let uv = mesh.GetTextureUV (textureUVIndex); + objWriter.WriteArrayLine (['vt', uv.x, uv.y]); + } + for (let triangleIndex = 0; triangleIndex < mesh.TriangleCount (); triangleIndex++) { + let triangle = mesh.GetTriangle (triangleIndex); + let v0 = triangle.v0 + vertexOffset + 1; + let v1 = triangle.v1 + vertexOffset + 1; + let v2 = triangle.v2 + vertexOffset + 1; + let n0 = triangle.n0 + normalOffset + 1; + let n1 = triangle.n1 + normalOffset + 1; + let n2 = triangle.n2 + normalOffset + 1; + if (triangle.mat !== null) { + let material = model.GetMaterial (triangle.mat); + let materialName = this.GetExportedMaterialName (material.name); + if (materialName !== usedMaterialName) { + objWriter.WriteArrayLine (['usemtl', materialName]); + usedMaterialName = materialName; + } + } + let u0 = ''; + let u1 = ''; + let u2 = ''; + if (triangle.HasTextureUVs ()) { + u0 = triangle.u0 + uvOffset + 1; + u1 = triangle.u1 + uvOffset + 1; + u2 = triangle.u2 + uvOffset + 1; + } + objWriter.WriteArrayLine (['f', [v0, u0, n0].join ('/'), [v1, u1, n1].join ('/'), [v2, u2, n2].join ('/')]); + } + vertexOffset += mesh.VertexCount (); + normalOffset += mesh.NormalCount (); + uvOffset += mesh.TextureUVCount (); + } - objFile.SetContent (objWriter.GetText ()); - } + objFile.SetContent (objWriter.GetText ()); + onFinish (); + } - GetHeaderText () - { - return '# exported by https://3dviewer.net'; - } + GetHeaderText () + { + return '# exported by https://3dviewer.net'; + } }; diff --git a/source/export/exporteroff.js b/source/export/exporteroff.js index f6187d6..38348fe 100644 --- a/source/export/exporteroff.js +++ b/source/export/exporteroff.js @@ -10,7 +10,7 @@ OV.ExporterOff = class extends OV.ExporterBase return format === OV.FileFormat.Text && extension === 'off'; } - ExportContent (model, format, files) + ExportContent (model, format, files, onFinish) { let offFile = new OV.ExportedFile ('model.off'); files.push (offFile); @@ -29,5 +29,6 @@ OV.ExporterOff = class extends OV.ExporterBase }); offFile.SetContent (offWriter.GetText ()); + onFinish (); } }; diff --git a/source/export/exporterply.js b/source/export/exporterply.js index c150fab..52fde7d 100644 --- a/source/export/exporterply.js +++ b/source/export/exporterply.js @@ -10,13 +10,14 @@ OV.ExporterPly = class extends OV.ExporterBase return (format === OV.FileFormat.Text || format === OV.FileFormat.Binary) && extension === 'ply'; } - ExportContent (model, format, files) + ExportContent (model, format, files, onFinish) { if (format === OV.FileFormat.Text) { this.ExportText (model, files); } else { this.ExportBinary (model, files); } + onFinish (); } ExportText (model, files) diff --git a/source/export/exporterstl.js b/source/export/exporterstl.js index 8d4665e..fde7c86 100644 --- a/source/export/exporterstl.js +++ b/source/export/exporterstl.js @@ -10,13 +10,14 @@ OV.ExporterStl = class extends OV.ExporterBase return (format === OV.FileFormat.Text || format === OV.FileFormat.Binary) && extension === 'stl'; } - ExportContent (model, format, files) + ExportContent (model, format, files, onFinish) { if (format === OV.FileFormat.Text) { this.ExportText (model, files); } else { this.ExportBinary (model, files); } + onFinish (); } ExportText (model, files) diff --git a/source/external/rhino.exporter.js b/source/external/rhino.exporter.js new file mode 100644 index 0000000..9bf8f17 --- /dev/null +++ b/source/external/rhino.exporter.js @@ -0,0 +1,96 @@ +OV.Exporter3dm = class extends OV.ExporterBase +{ + constructor () + { + super (); + this.rhino = null; + } + + CanExport (format, extension) + { + return format === OV.FileFormat.Binary && extension === '3dm'; + } + + ExportContent (model, format, files, onFinish) + { + if (this.rhino === null) { + let obj = this; + rhino3dm ().then (function (rhino) { + obj.rhino = rhino; + obj.ExportRhinoContent (model, files, onFinish); + }); + } else { + this.ExportRhinoContent (model, files, onFinish); + } + } + + ExportRhinoContent (model, files, onFinish) + { + function ColorToRhinoColor (color) + { + return { + r : color.r, + g : color.g, + b : color.b, + a : 255 + }; + } + + let rhinoFile = new OV.ExportedFile ('model.3dm'); + files.push (rhinoFile); + + let rhinoDoc = new this.rhino.File3dm (); + for (let meshIndex = 0; meshIndex < model.MeshCount (); meshIndex++) { + let mesh = model.GetMesh (meshIndex); + let meshBuffer = OV.ConvertMeshToMeshBuffer (mesh); + for (let primitiveIndex = 0; primitiveIndex < meshBuffer.PrimitiveCount (); primitiveIndex++) { + let primitive = meshBuffer.GetPrimitive (primitiveIndex); + let threeJson = { + data : { + attributes : { + position : { + itemSize : 3, + type : 'Float32Array', + array : primitive.vertices + }, + normal : { + itemSize : 3, + type : 'Float32Array', + array : primitive.normals + } + }, + index : { + type : 'Uint16Array', + array : primitive.indices + } + } + }; + + let material = model.GetMaterial (primitive.material); + let rhinoMaterial = new this.rhino.Material (); + rhinoMaterial.name = this.GetExportedMaterialName (material.name); + rhinoMaterial.ambientColor = ColorToRhinoColor (material.ambient); + rhinoMaterial.diffuseColor = ColorToRhinoColor (material.diffuse); + rhinoMaterial.specularColor = ColorToRhinoColor (material.specular); + rhinoMaterial.transparency = 1.0 - material.opacity; + + let rhinoMaterialIndex = rhinoDoc.materials ().count (); + rhinoDoc.materials ().add (rhinoMaterial); + + let rhinoMesh = new this.rhino.Mesh.createFromThreejsJSON (threeJson); + let rhinoAttributes = new this.rhino.ObjectAttributes (); + rhinoAttributes.name = this.GetExportedMeshName (mesh.GetName ()); + rhinoAttributes.materialSource = this.rhino.ObjectMaterialSource.MaterialFromObject; + rhinoAttributes.materialIndex = rhinoMaterialIndex; + rhinoDoc.objects ().add (rhinoMesh, rhinoAttributes); + } + } + + let writeOptions = new this.rhino.File3dmWriteOptions (); + writeOptions.version = 6; + let rhinoDocBuffer = rhinoDoc.toByteArray (writeOptions); + + rhinoFile.SetContent (rhinoDocBuffer); + onFinish (); + } +}; diff --git a/source/external/rhino.importer.js b/source/external/rhino.importer.js new file mode 100644 index 0000000..0b4d854 --- /dev/null +++ b/source/external/rhino.importer.js @@ -0,0 +1,323 @@ +OV.Importer3dm = class extends OV.ImporterBase +{ + constructor () + { + super (); + this.rhino = null; + } + + CanImportExtension (extension) + { + return extension === '3dm'; + } + + GetKnownFileFormats () + { + return { + '3dm' : OV.FileFormat.Binary + }; + } + + GetUpDirection () + { + return OV.Direction.Z; + } + + ClearContent () + { + this.instanceObjects = null; + this.instanceDefinitions = null; + } + + ResetContent () + { + this.instanceObjects = {}; + this.instanceDefinitions = {}; + } + + ImportContent (fileContent, onFinish) + { + if (this.rhino === null) { + let obj = this; + rhino3dm ().then (function (rhino) { + obj.rhino = rhino; + obj.ImportRhinoContent (fileContent); + onFinish (); + }); + } else { + this.ImportRhinoContent (fileContent); + onFinish (); + } + } + + ImportRhinoContent (fileContent) + { + let rhinoDoc = this.rhino.File3dm.fromByteArray (fileContent); + if (rhinoDoc === null) { + this.SetError (); + this.SetMessage ('Failed to read Rhino file.'); + return; + } + this.ImportRhinoDocument (rhinoDoc); + if (OV.IsModelEmpty (this.model)) { + this.SetError (); + this.SetMessage ('The model doesn\'t contain any 3D meshes. Try to save the model while you are in shaded view in Rhino.'); + } + } + + ImportRhinoDocument (rhinoDoc) + { + this.InitRhinoInstances (rhinoDoc); + this.ImportRhinoGeometry (rhinoDoc); + } + + InitRhinoInstances (rhinoDoc) + { + let rhinoObjects = rhinoDoc.objects (); + for (let i = 0; i < rhinoObjects.count; i++) { + let rhinoObject = rhinoObjects.get (i); + let rhinoAttributes = rhinoObject.attributes (); + if (rhinoAttributes.isInstanceDefinitionObject) { + this.instanceObjects[rhinoAttributes.id] = rhinoObject; + } + } + let rhinoInstanceDefinitions = rhinoDoc.instanceDefinitions (); + for (let i = 0; i < rhinoInstanceDefinitions.count (); i++) { + let rhinoInstanceDefinition = rhinoInstanceDefinitions.get (i); + this.instanceDefinitions[rhinoInstanceDefinition.id] = rhinoInstanceDefinition; + } + } + + ImportRhinoGeometry (rhinoDoc) + { + let rhinoObjects = rhinoDoc.objects (); + for (let i = 0; i < rhinoObjects.count; i++) { + let rhinoObject = rhinoObjects.get (i); + this.ImportRhinoGeometryObject (rhinoDoc, rhinoObject, []); + } + } + + ImportRhinoGeometryObject (rhinoDoc, rhinoObject, rhinoInstanceReferences) + { + let rhinoGeometry = rhinoObject.geometry (); + let rhinoAttributes = rhinoObject.attributes (); + + let objectType = rhinoGeometry.objectType; + if (rhinoAttributes.isInstanceDefinitionObject && rhinoInstanceReferences.length === 0) { + return; + } + + let rhinoMesh = null; + let deleteMesh = false; + + if (objectType === this.rhino.ObjectType.Mesh) { + rhinoMesh = rhinoGeometry; + deleteMesh = false; + } else if (objectType === this.rhino.ObjectType.Extrusion) { + rhinoMesh = rhinoGeometry.getMesh (this.rhino.MeshType.Any); + deleteMesh = true; + } else if (objectType === this.rhino.ObjectType.Brep) { + rhinoMesh = new this.rhino.Mesh (); + let faces = rhinoGeometry.faces (); + for (let i = 0; i < faces.count; i++) { + let face = faces.get (i); + let mesh = face.getMesh (this.rhino.MeshType.Any); + if (mesh) { + rhinoMesh.append (mesh); + mesh.delete (); + } + face.delete (); + } + faces.delete (); + rhinoMesh.compact (); + deleteMesh = true; + } else if (objectType === this.rhino.ObjectType.SubD) { + rhinoGeometry.subdivide (3); + rhinoMesh = this.rhino.Mesh.createFromSubDControlNet (rhinoGeometry); + deleteMesh = true; + } else if (objectType === this.rhino.ObjectType.InstanceReference) { + let parentDefinitionId = rhinoGeometry.parentIdefId; + let instanceDefinition = this.instanceDefinitions[parentDefinitionId]; + if (instanceDefinition !== undefined) { + let instanceObjectIds = instanceDefinition.getObjectIds (); + for (let i = 0; i < instanceObjectIds.length; i++) { + let instanceObjectId = instanceObjectIds[i]; + let instanceObject = this.instanceObjects[instanceObjectId]; + if (instanceObject !== undefined) { + rhinoInstanceReferences.push (rhinoObject); + this.ImportRhinoGeometryObject (rhinoDoc, instanceObject, rhinoInstanceReferences); + rhinoInstanceReferences.pop (); + } + } + } + } + + if (rhinoMesh !== null) { + this.ImportRhinoMesh (rhinoDoc, rhinoMesh, rhinoObject, rhinoInstanceReferences); + if (deleteMesh) { + rhinoMesh.delete (); + } + } + } + + ImportRhinoMesh (rhinoDoc, rhinoMesh, rhinoObject, rhinoInstanceReferences) + { + let rhinoAttributes = rhinoObject.attributes (); + + let mesh = new OV.Mesh (); + mesh.SetName (rhinoAttributes.name); + + let materialIndex = this.GetMaterialIndex (rhinoDoc, rhinoObject, rhinoInstanceReferences); + let threeJson = rhinoMesh.toThreejsJSON (); + let vertices = threeJson.data.attributes.position.array; + for (let i = 0; i < vertices.length; i += 3) { + let x = vertices[i]; + let y = vertices[i + 1]; + let z = vertices[i + 2]; + mesh.AddVertex (new OV.Coord3D (x, y, z)); + } + let hasNormals = (threeJson.data.attributes.normal !== undefined); + if (hasNormals) { + let normals = threeJson.data.attributes.normal.array; + for (let i = 0; i < normals.length; i += 3) { + let x = normals[i]; + let y = normals[i + 1]; + let z = normals[i + 2]; + mesh.AddNormal (new OV.Coord3D (x, y, z)); + } + } + let hasUVs = (threeJson.data.attributes.uv !== undefined); + if (hasUVs) { + let uvs = threeJson.data.attributes.uv.array; + for (let i = 0; i < uvs.length; i += 2) { + let x = uvs[i]; + let y = uvs[i + 1]; + mesh.AddTextureUV (new OV.Coord2D (x, y)); + } + } + let indices = threeJson.data.index.array; + for (let i = 0; i < indices.length; i += 3) { + let v0 = indices[i]; + let v1 = indices[i + 1]; + let v2 = indices[i + 2]; + let triangle = new OV.Triangle (v0, v1, v2); + if (hasNormals) { + triangle.SetNormals (v0, v1, v2); + } + if (hasUVs) { + triangle.SetTextureUVs (v0, v1, v2); + } + if (materialIndex !== null) { + triangle.SetMaterial (materialIndex); + } + mesh.AddTriangle (triangle); + } + if (rhinoInstanceReferences.length !== 0) { + let matrix = new OV.Matrix ().CreateIdentity (); + for (let i = rhinoInstanceReferences.length - 1; i >= 0; i--) { + let rhinoInstanceReference = rhinoInstanceReferences[i]; + let rhinoInstanceReferenceGeometry = rhinoInstanceReference.geometry (); + let rhinoInstanceReferenceMatrix = rhinoInstanceReferenceGeometry.xform.toFloatArray (false); + let transformationMatrix = new OV.Matrix (rhinoInstanceReferenceMatrix); + matrix = matrix.MultiplyMatrix (transformationMatrix); + } + let transformation = new OV.Transformation (matrix); + OV.TransformMesh (mesh, transformation); + } + this.model.AddMesh (mesh); + } + + GetMaterialIndex (rhinoDoc, rhinoObject, rhinoInstanceReferences) + { + function GetRhinoMaterial (rhino, rhinoObject, rhinoInstanceReferences) + { + let rhinoAttributes = rhinoObject.attributes (); + if (rhinoAttributes.materialSource === rhino.ObjectMaterialSource.MaterialFromObject) { + let materialIndex = rhinoAttributes.materialIndex; + if (materialIndex > -1) { + return rhinoDoc.materials ().get (materialIndex); + } + } else if (rhinoAttributes.materialSource === rhino.ObjectMaterialSource.MaterialFromLayer) { + let layerIndex = rhinoAttributes.layerIndex; + if (layerIndex > 0) { + let layer = rhinoDoc.layers ().get (layerIndex); + let layerMaterialIndex = layer.renderMaterialIndex; + if (layerMaterialIndex > -1) { + return rhinoDoc.materials ().get (layerMaterialIndex); + } + } + } else if (rhinoAttributes.materialSource === rhino.ObjectMaterialSource.MaterialFromParent) { + if (rhinoInstanceReferences.length !== 0) { + return GetRhinoMaterial (rhino, rhinoInstanceReferences[0], []); + } + } + return null; + } + + function FindMatchingMaterial (model, rhinoMaterial) + { + function SetColor (color, rhinoColor) + { + color.Set (rhinoColor.r, rhinoColor.g, rhinoColor.b); + } + + function IsBlack (rhinoColor) + { + return rhinoColor.r === 0 && rhinoColor.g === 0 && rhinoColor.b === 0; + } + + function IsWhite (rhinoColor) + { + return rhinoColor.r === 255 && rhinoColor.g === 255 && rhinoColor.b === 255; + } + + let material = new OV.Material (); + if (rhinoMaterial === null) { + material.diffuse.Set (255, 255, 255); + } else { + material.name = rhinoMaterial.name; + SetColor (material.ambient, rhinoMaterial.ambientColor); + SetColor (material.diffuse, rhinoMaterial.diffuseColor); + SetColor (material.specular, rhinoMaterial.specularColor); + material.opacity = 1.0 - rhinoMaterial.transparency; + material.transparent = OV.IsLower (material.opacity, 1.0); + // material.shininess = rhinoMaterial.shine / 255.0; + if (IsBlack (material.diffuse) && !IsWhite (rhinoMaterial.reflectionColor)) { + SetColor (material.diffuse, rhinoMaterial.reflectionColor); + } + if (IsBlack (material.diffuse) && !IsWhite (rhinoMaterial.transparentColor)) { + SetColor (material.diffuse, rhinoMaterial.transparentColor); + } + } + for (let i = 0; i < model.MaterialCount (); i++) { + let current = model.GetMaterial (i); + if (current.name !== material.name) { + continue; + } + if (!OV.ColorIsEqual (current.ambient, material.ambient)) { + continue; + } + if (!OV.ColorIsEqual (current.diffuse, material.diffuse)) { + continue; + } + if (!OV.ColorIsEqual (current.specular, material.specular)) { + continue; + } + if (!OV.IsEqual (current.opacity, material.opacity)) { + continue; + } + if (current.transparent !== material.transparent) { + continue; + } + if (!OV.IsEqual (current.shininess, material.shininess)) { + continue; + } + return i; + } + return model.AddMaterial (material); + } + + let rhinoMaterial = GetRhinoMaterial (this.rhino, rhinoObject, rhinoInstanceReferences); + return FindMatchingMaterial (this.model, rhinoMaterial); + } +}; diff --git a/source/external/three.converter.js b/source/external/three.converter.js index 2020e6f..cc2e129 100644 --- a/source/external/three.converter.js +++ b/source/external/three.converter.js @@ -39,7 +39,7 @@ OV.ConvertModelToThreeMeshes = function (model, callbacks) color : diffuseColor, specular : specularColor, emissive : emissiveColor, - shininess : material.shininess * 10.0, + shininess : material.shininess * 100.0, opacity : material.opacity, transparent : material.transparent, alphaTest : material.alphaTest, diff --git a/source/external/three.model.loader.js b/source/external/three.model.loader.js index 62154d4..39dd5a4 100644 --- a/source/external/three.model.loader.js +++ b/source/external/three.model.loader.js @@ -3,6 +3,7 @@ OV.ThreeModelLoader = class constructor () { this.importer = new OV.Importer (); + this.importer.AddImporter (new OV.Importer3dm ()); this.callbacks = null; this.inProgress = false; } @@ -57,10 +58,10 @@ OV.ThreeModelLoader = class this.callbacks.onImportStart (); OV.RunTaskAsync (function () { obj.importer.Import (settings, { - success : function (importResult) { + onSuccess : function (importResult) { obj.OnModelImported (importResult); }, - error : function (importError) { + onError : function (importError) { obj.callbacks.onLoadError (importError); obj.inProgress = false; } diff --git a/source/import/importer.js b/source/import/importer.js index 7883d1e..592f843 100644 --- a/source/import/importer.js +++ b/source/import/importer.js @@ -1,218 +1,218 @@ OV.File = class { - constructor (file, source) - { - this.source = source; - if (source === OV.FileSource.Url) { - this.fileUrl = file; - this.fileObject = null; - this.name = OV.GetFileName (file); - this.extension = OV.GetFileExtension (file); - } else if (source === OV.FileSource.File) { - this.fileUrl = null; - this.fileObject = file; - this.name = OV.GetFileName (file.name); - this.extension = OV.GetFileExtension (file.name); - } - this.content = null; - } + constructor (file, source) + { + this.source = source; + if (source === OV.FileSource.Url) { + this.fileUrl = file; + this.fileObject = null; + this.name = OV.GetFileName (file); + this.extension = OV.GetFileExtension (file); + } else if (source === OV.FileSource.File) { + this.fileUrl = null; + this.fileObject = file; + this.name = OV.GetFileName (file.name); + this.extension = OV.GetFileExtension (file.name); + } + this.content = null; + } }; OV.FileList = class { - constructor (importers) - { - this.files = []; - this.importers = importers; - } + constructor (importers) + { + this.files = []; + this.importers = importers; + } - FillFromFileUrls (fileList) - { - this.Fill (fileList, OV.FileSource.Url); - } + FillFromFileUrls (fileList) + { + this.Fill (fileList, OV.FileSource.Url); + } - FillFromFileObjects (fileList) - { - this.Fill (fileList, OV.FileSource.File); - } + FillFromFileObjects (fileList) + { + this.Fill (fileList, OV.FileSource.File); + } - ExtendFromFileList (files) - { - for (let i = 0; i < files.length; i++) { - let file = files[i]; - if (!this.ContainsFileByPath (file.name)) { - this.files.push (file); - } - } - } + ExtendFromFileList (files) + { + for (let i = 0; i < files.length; i++) { + let file = files[i]; + if (!this.ContainsFileByPath (file.name)) { + this.files.push (file); + } + } + } - GetFiles () - { - return this.files; - } + GetFiles () + { + return this.files; + } - GetContent (onReady) - { - let obj = this; - let taskRunner = new OV.TaskRunner (); - taskRunner.Run (this.files.length, { - runTask : function (index, complete) { - obj.GetFileContent (obj.files[index], complete); - }, - onReady : onReady - }); - } + GetContent (onReady) + { + let obj = this; + let taskRunner = new OV.TaskRunner (); + taskRunner.Run (this.files.length, { + runTask : function (index, complete) { + obj.GetFileContent (obj.files[index], complete); + }, + onReady : onReady + }); + } - ContainsFileByPath (filePath) - { - return this.FindFileByPath (filePath) !== null; - } + ContainsFileByPath (filePath) + { + return this.FindFileByPath (filePath) !== null; + } - FindFileByPath (filePath) - { - let fileName = OV.GetFileName (filePath).toLowerCase (); - for (let fileIndex = 0; fileIndex < this.files.length; fileIndex++) { - let file = this.files[fileIndex]; - if (file.name.toLowerCase () === fileName) { - return file; - } - } - return null; - } + FindFileByPath (filePath) + { + let fileName = OV.GetFileName (filePath).toLowerCase (); + for (let fileIndex = 0; fileIndex < this.files.length; fileIndex++) { + let file = this.files[fileIndex]; + if (file.name.toLowerCase () === fileName) { + return file; + } + } + return null; + } - HasMainFile () - { - return this.GetMainFile () !== null; - } + HasMainFile () + { + return this.GetMainFile () !== null; + } - GetMainFile () - { - for (let fileIndex = 0; fileIndex < this.files.length; fileIndex++) { - let file = this.files[fileIndex]; - let importer = this.FindImporter (file); - if (importer !== null) { - return { - file : file, - importer : importer - }; - } - } - return null; - } + GetMainFile () + { + for (let fileIndex = 0; fileIndex < this.files.length; fileIndex++) { + let file = this.files[fileIndex]; + let importer = this.FindImporter (file); + if (importer !== null) { + return { + file : file, + importer : importer + }; + } + } + return null; + } - IsOnlySource (source) - { - if (this.files.length === 0) { - return false; - } - for (let i = 0; i < this.files.length; i++) { - let file = this.files[i]; - if (file.source !== source) { - return false; - } - } - return true; - } + IsOnlySource (source) + { + if (this.files.length === 0) { + return false; + } + for (let i = 0; i < this.files.length; i++) { + let file = this.files[i]; + if (file.source !== source) { + return false; + } + } + return true; + } - Fill (fileList, fileSource) - { - this.files = []; - for (let fileIndex = 0; fileIndex < fileList.length; fileIndex++) { - let fileObject = fileList[fileIndex]; - let file = new OV.File (fileObject, fileSource); - this.AddFile (file); - } - } + Fill (fileList, fileSource) + { + this.files = []; + for (let fileIndex = 0; fileIndex < fileList.length; fileIndex++) { + let fileObject = fileList[fileIndex]; + let file = new OV.File (fileObject, fileSource); + this.AddFile (file); + } + } - AddFile (file) - { - this.files.push (file); - } - - GetFileContent (file, complete) - { - let callbacks = { - success : function (content) { - file.content = content; - }, - error : function () { - - }, - complete : function () { - complete (); - } - }; - if (file.content !== null) { - complete (); - return; - } - let format = this.GetFileFormat (file); - if (file.source === OV.FileSource.Url) { - OV.RequestUrl (file.fileUrl, format, callbacks); - } else if (file.source === OV.FileSource.File) { - OV.ReadFile (file.fileObject, format, callbacks); - } - } - - GetFileFormat (file) - { - for (let importerIndex = 0; importerIndex < this.importers.length; importerIndex++) { - let importer = this.importers[importerIndex]; - let extension = file.extension.toLowerCase (); - let knownFormats = importer.GetKnownFileFormats (); - if (knownFormats[extension] !== undefined) { - return knownFormats[extension]; - } - } - return OV.FileFormat.Binary; - } + AddFile (file) + { + this.files.push (file); + } + + GetFileContent (file, complete) + { + let callbacks = { + success : function (content) { + file.content = content; + }, + error : function () { + + }, + complete : function () { + complete (); + } + }; + if (file.content !== null) { + complete (); + return; + } + let format = this.GetFileFormat (file); + if (file.source === OV.FileSource.Url) { + OV.RequestUrl (file.fileUrl, format, callbacks); + } else if (file.source === OV.FileSource.File) { + OV.ReadFile (file.fileObject, format, callbacks); + } + } + + GetFileFormat (file) + { + for (let importerIndex = 0; importerIndex < this.importers.length; importerIndex++) { + let importer = this.importers[importerIndex]; + let extension = file.extension.toLowerCase (); + let knownFormats = importer.GetKnownFileFormats (); + if (knownFormats[extension] !== undefined) { + return knownFormats[extension]; + } + } + return OV.FileFormat.Binary; + } - FindImporter (file) - { - for (let importerIndex = 0; importerIndex < this.importers.length; importerIndex++) { - let importer = this.importers[importerIndex]; - if (importer.CanImportExtension (file.extension.toLowerCase ())) { - return importer; - } - } - return null; - } + FindImporter (file) + { + for (let importerIndex = 0; importerIndex < this.importers.length; importerIndex++) { + let importer = this.importers[importerIndex]; + if (importer.CanImportExtension (file.extension.toLowerCase ())) { + return importer; + } + } + return null; + } }; OV.ImportSettings = class { - constructor () - { - this.defaultColor = new OV.Color (200, 200, 200); - } + constructor () + { + this.defaultColor = new OV.Color (200, 200, 200); + } }; OV.ImportErrorCode = { - NoImportableFile : 1, - ImportFailed : 2, - UnknownError : 3 + NoImportableFile : 1, + ImportFailed : 2, + UnknownError : 3 }; OV.ImportError = class { - constructor (code, message) - { - this.code = code; - this.message = message; - } + constructor (code, message) + { + this.code = code; + this.message = message; + } }; OV.ImportResult = class { - constructor () - { - this.model = null; - this.mainFile = null; - this.upVector = null; - this.usedFiles = null; - this.missingFiles = null; - } + constructor () + { + this.model = null; + this.mainFile = null; + this.upVector = null; + this.usedFiles = null; + this.missingFiles = null; + } }; OV.ImportBuffers = class @@ -257,151 +257,157 @@ OV.ImportBuffers = class OV.Importer = class { - constructor () + constructor () + { + this.importers = [ + new OV.ImporterObj (), + new OV.ImporterStl (), + new OV.ImporterOff (), + new OV.ImporterPly (), + new OV.Importer3ds (), + new OV.ImporterGltf () + ]; + this.fileList = new OV.FileList (this.importers); + this.model = null; + this.usedFiles = []; + this.missingFiles = []; + } + + AddImporter (importer) { - this.importers = [ - new OV.ImporterObj (), - new OV.ImporterStl (), - new OV.ImporterOff (), - new OV.ImporterPly (), - new OV.Importer3ds (), - new OV.ImporterGltf () - ]; - this.fileList = new OV.FileList (this.importers); - this.model = null; - this.usedFiles = []; - this.missingFiles = []; - } - - LoadFilesFromUrls (fileList, onReady) - { - this.LoadFiles (fileList, OV.FileSource.Url, onReady); + this.importers.push (importer); } - LoadFilesFromFileObjects (fileList, onReady) - { - this.LoadFiles (fileList, OV.FileSource.File, onReady); - } + LoadFilesFromUrls (fileList, onReady) + { + this.LoadFiles (fileList, OV.FileSource.Url, onReady); + } - Import (settings, callbacks) - { - let mainFile = this.fileList.GetMainFile (); - if (mainFile === null || mainFile.file === null || mainFile.file.content === null) { - callbacks.error (new OV.ImportError (OV.ImportErrorCode.NoImportableFile, null)); - return; - } + LoadFilesFromFileObjects (fileList, onReady) + { + this.LoadFiles (fileList, OV.FileSource.File, onReady); + } - this.RevokeModelUrls (); - this.model = null; - this.usedFiles = []; - this.missingFiles = []; - this.usedFiles.push (mainFile.file.name); + Import (settings, callbacks) + { + let mainFile = this.fileList.GetMainFile (); + if (mainFile === null || mainFile.file === null || mainFile.file.content === null) { + callbacks.onError (new OV.ImportError (OV.ImportErrorCode.NoImportableFile, null)); + return; + } - let result = new OV.ImportResult (); - result.mainFile = mainFile.file.name; + this.RevokeModelUrls (); + this.model = null; + this.usedFiles = []; + this.missingFiles = []; + this.usedFiles.push (mainFile.file.name); - let obj = this; - let importer = mainFile.importer; - let buffers = new OV.ImportBuffers (function (fileName) { - let fileBuffer = null; - let file = obj.fileList.FindFileByPath (fileName); - if (file === null || file.content === null) { - obj.missingFiles.push (fileName); - fileBuffer = null; - } else { - fileBuffer = file.content; - obj.usedFiles.push (fileName); - } - return fileBuffer; - }); + let obj = this; + let importer = mainFile.importer; + let buffers = new OV.ImportBuffers (function (fileName) { + let fileBuffer = null; + let file = obj.fileList.FindFileByPath (fileName); + if (file === null || file.content === null) { + obj.missingFiles.push (fileName); + fileBuffer = null; + } else { + fileBuffer = file.content; + obj.usedFiles.push (fileName); + } + return fileBuffer; + }); - importer.Import (mainFile.file.content, mainFile.file.extension, { - getDefaultMaterial : function () { - let material = new OV.Material (); - material.diffuse = settings.defaultColor; - return material; - }, - getFileBuffer : function (filePath) { - return buffers.GetFileBuffer (filePath); - }, - getTextureBuffer : function (filePath) { - return buffers.GetTextureBuffer (filePath); - } - }); + importer.Import (mainFile.file.content, mainFile.file.extension, { + getDefaultMaterial : function () { + let material = new OV.Material (); + material.diffuse = settings.defaultColor; + return material; + }, + getFileBuffer : function (filePath) { + return buffers.GetFileBuffer (filePath); + }, + getTextureBuffer : function (filePath) { + return buffers.GetTextureBuffer (filePath); + }, + onSuccess : function () { + obj.model = importer.GetModel (); + obj.model.SetName (mainFile.file.name); + + let result = new OV.ImportResult (); + result.mainFile = mainFile.file.name; + result.model = obj.model; + result.usedFiles = obj.usedFiles; + result.missingFiles = obj.missingFiles; + result.upVector = importer.GetUpDirection (); + callbacks.onSuccess (result); + }, + onError : function () { + let message = importer.GetMessage (); + callbacks.onError (new OV.ImportError (OV.ImportErrorCode.ImportFailed, message)); + }, + onComplete : function () { + importer.Clear (); + } + }); + } - if (importer.IsError ()) { - let message = importer.GetMessage (); - callbacks.error (new OV.ImportError (OV.ImportErrorCode.ImportFailed, message)); - return; - } + LoadFiles (fileList, fileSource, onReady) + { + let newFileList = new OV.FileList (this.importers); + if (fileSource === OV.FileSource.Url) { + newFileList.FillFromFileUrls (fileList); + } else if (fileSource === OV.FileSource.File) { + newFileList.FillFromFileObjects (fileList); + } + let reset = false; + if (newFileList.HasMainFile ()) { + reset = true; + } else { + let foundMissingFile = false; + for (let i = 0; i < this.missingFiles.length; i++) { + let missingFile = this.missingFiles[i]; + if (newFileList.ContainsFileByPath (missingFile)) { + foundMissingFile = true; + } + } + if (!foundMissingFile) { + reset = true; + } else { + let newFiles = newFileList.GetFiles (); + this.fileList.ExtendFromFileList (newFiles); + reset = false; + } + } + if (reset) { + this.fileList = newFileList; + } + this.fileList.GetContent (function () { + onReady (); + }); + } - this.model = importer.GetModel (); - this.model.SetName (mainFile.file.name); + GetFileList () + { + return this.fileList; + } - result.model = this.model; - result.usedFiles = this.usedFiles; - result.missingFiles = this.missingFiles; - result.upVector = importer.GetUpDirection (); - callbacks.success (result); - } + IsOnlyFileSource (source) + { + return this.fileList.IsOnlySource (source); + } - LoadFiles (fileList, fileSource, onReady) - { - let newFileList = new OV.FileList (this.importers); - if (fileSource === OV.FileSource.Url) { - newFileList.FillFromFileUrls (fileList); - } else if (fileSource === OV.FileSource.File) { - newFileList.FillFromFileObjects (fileList); - } - let reset = false; - if (newFileList.HasMainFile ()) { - reset = true; - } else { - let foundMissingFile = false; - for (let i = 0; i < this.missingFiles.length; i++) { - let missingFile = this.missingFiles[i]; - if (newFileList.ContainsFileByPath (missingFile)) { - foundMissingFile = true; - } - } - if (!foundMissingFile) { - reset = true; - } else { - let newFiles = newFileList.GetFiles (); - this.fileList.ExtendFromFileList (newFiles); - reset = false; - } - } - if (reset) { - this.fileList = newFileList; - } - this.fileList.GetContent (function () { - onReady (); - }); - } - - GetFileList () - { - return this.fileList; - } - - IsOnlyFileSource (source) - { - return this.fileList.IsOnlySource (source); - } - - RevokeModelUrls () - { - if (this.model === null) { - return; - } - for (let i = 0; i < this.model.MaterialCount (); i++) { - let material = this.model.GetMaterial (i); - material.EnumerateTextureMaps (function (texture) { - if (texture.url !== null) { - OV.RevokeObjectUrl (texture.url); - } - }); - } - } + RevokeModelUrls () + { + if (this.model === null) { + return; + } + for (let i = 0; i < this.model.MaterialCount (); i++) { + let material = this.model.GetMaterial (i); + material.EnumerateTextureMaps (function (texture) { + if (texture.url !== null) { + OV.RevokeObjectUrl (texture.url); + } + }); + } + } }; diff --git a/source/import/importer3ds.js b/source/import/importer3ds.js index 2cb9e92..aa9ffae 100644 --- a/source/import/importer3ds.js +++ b/source/import/importer3ds.js @@ -1,682 +1,690 @@ OV.CHUNK3DS = { - MAIN3DS : 0x4D4D, - EDIT3DS : 0x3D3D, - EDIT_MATERIAL : 0xAFFF, - MAT_NAME : 0xA000, - MAT_AMBIENT : 0xA010, - MAT_DIFFUSE : 0xA020, - MAT_SPECULAR : 0xA030, - MAT_SHININESS : 0xA040, - MAT_SHININESS_STRENGTH : 0xA041, - MAT_TRANSPARENCY : 0xA050, - MAT_COLOR_F : 0x0010, - MAT_COLOR : 0x0011, - MAT_LIN_COLOR : 0x0012, - MAT_LIN_COLOR_F : 0x0013, - MAT_TEXMAP : 0xA200, - MAT_TEXMAP_NAME : 0xA300, - MAT_TEXMAP_UOFFSET : 0xA358, - MAT_TEXMAP_VOFFSET : 0xA35A, - MAT_TEXMAP_USCALE : 0xA354, - MAT_TEXMAP_VSCALE : 0xA356, - MAT_TEXMAP_ROTATION : 0xA35C, - PERCENTAGE : 0x0030, - PERCENTAGE_F : 0x0031, - EDIT_OBJECT : 0x4000, - OBJ_TRIMESH : 0x4100, - OBJ_LIGHT : 0x4600, - OBJ_CAMERA : 0x4700, - TRI_VERTEX : 0x4110, - TRI_TEXVERTEX : 0x4140, - TRI_FACE : 0x4120, - TRI_TRANSFORMATION : 0x4160, - TRI_MATERIAL : 0x4130, - TRI_SMOOTH : 0x4150, - KF3DS : 0xB000, - OBJECT_NODE : 0xB002, - OBJECT_HIERARCHY : 0xB010, - OBJECT_INSTANCE_NAME : 0xB011, - OBJECT_PIVOT : 0xB013, - OBJECT_POSITION : 0xB020, - OBJECT_ROTATION : 0xB021, - OBJECT_SCALE : 0xB022, - OBJECT_ID : 0xB030 + MAIN3DS : 0x4D4D, + EDIT3DS : 0x3D3D, + EDIT_MATERIAL : 0xAFFF, + MAT_NAME : 0xA000, + MAT_AMBIENT : 0xA010, + MAT_DIFFUSE : 0xA020, + MAT_SPECULAR : 0xA030, + MAT_SHININESS : 0xA040, + MAT_SHININESS_STRENGTH : 0xA041, + MAT_TRANSPARENCY : 0xA050, + MAT_COLOR_F : 0x0010, + MAT_COLOR : 0x0011, + MAT_LIN_COLOR : 0x0012, + MAT_LIN_COLOR_F : 0x0013, + MAT_TEXMAP : 0xA200, + MAT_TEXMAP_NAME : 0xA300, + MAT_TEXMAP_UOFFSET : 0xA358, + MAT_TEXMAP_VOFFSET : 0xA35A, + MAT_TEXMAP_USCALE : 0xA354, + MAT_TEXMAP_VSCALE : 0xA356, + MAT_TEXMAP_ROTATION : 0xA35C, + PERCENTAGE : 0x0030, + PERCENTAGE_F : 0x0031, + EDIT_OBJECT : 0x4000, + OBJ_TRIMESH : 0x4100, + OBJ_LIGHT : 0x4600, + OBJ_CAMERA : 0x4700, + TRI_VERTEX : 0x4110, + TRI_TEXVERTEX : 0x4140, + TRI_FACE : 0x4120, + TRI_TRANSFORMATION : 0x4160, + TRI_MATERIAL : 0x4130, + TRI_SMOOTH : 0x4150, + KF3DS : 0xB000, + OBJECT_NODE : 0xB002, + OBJECT_HIERARCHY : 0xB010, + OBJECT_INSTANCE_NAME : 0xB011, + OBJECT_PIVOT : 0xB013, + OBJECT_POSITION : 0xB020, + OBJECT_ROTATION : 0xB021, + OBJECT_SCALE : 0xB022, + OBJECT_ID : 0xB030 }; OV.Importer3ds = class extends OV.ImporterBase { - constructor () - { - super (); + constructor () + { + super (); + } - this.materialNameToIndex = null; - this.meshNameToIndex = null; - - this.meshTransformations = null; - this.defaultMaterialIndex = null; - } - - ResetState () - { - this.materialNameToIndex = {}; - this.meshNameToIndex = {}; + CanImportExtension (extension) + { + return extension === '3ds'; + } - this.meshTransformations = []; - this.defaultMaterialIndex = null; - } - - CanImportExtension (extension) - { - return extension === '3ds'; - } - - GetKnownFileFormats () - { - return { - '3ds' : OV.FileFormat.Binary - }; - } - + GetKnownFileFormats () + { + return { + '3ds' : OV.FileFormat.Binary + }; + } + GetUpDirection () { return OV.Direction.Z; + } + + ClearContent () + { + this.materialNameToIndex = null; + this.meshNameToIndex = null; + + this.meshTransformations = null; + this.defaultMaterialIndex = null; } - ImportContent (fileContent) - { + ResetContent () + { + this.materialNameToIndex = {}; + this.meshNameToIndex = {}; + + this.meshTransformations = []; + this.defaultMaterialIndex = null; + } + + ImportContent (fileContent, onFinish) + { this.ProcessBinary (fileContent); - } + onFinish (); + } ProcessBinary (fileContent) - { - let obj = this; + { + let obj = this; let reader = new OV.BinaryReader (fileContent, true); - let endByte = reader.GetByteLength (); - this.ReadChunks (reader, endByte, function (chunkId, chunkLength) { - if (chunkId === OV.CHUNK3DS.MAIN3DS) { - obj.ReadMainChunk (reader, chunkLength); - } else { - obj.SkipChunk (reader, chunkLength); - } - }); + let endByte = reader.GetByteLength (); + this.ReadChunks (reader, endByte, function (chunkId, chunkLength) { + if (chunkId === OV.CHUNK3DS.MAIN3DS) { + obj.ReadMainChunk (reader, chunkLength); + } else { + obj.SkipChunk (reader, chunkLength); + } + }); } - ReadMainChunk (reader, length) - { - let obj = this; - let endByte = this.GetChunkEnd (reader, length); - this.ReadChunks (reader, endByte, function (chunkId, chunkLength) { - if (chunkId === OV.CHUNK3DS.EDIT3DS) { - obj.ReadEditorChunk (reader, chunkLength); - } else if (chunkId === OV.CHUNK3DS.KF3DS) { - obj.ReadKeyFrameChunk (reader, chunkLength); - } else { - obj.SkipChunk (reader, chunkLength); - } - }); - } + ReadMainChunk (reader, length) + { + let obj = this; + let endByte = this.GetChunkEnd (reader, length); + this.ReadChunks (reader, endByte, function (chunkId, chunkLength) { + if (chunkId === OV.CHUNK3DS.EDIT3DS) { + obj.ReadEditorChunk (reader, chunkLength); + } else if (chunkId === OV.CHUNK3DS.KF3DS) { + obj.ReadKeyFrameChunk (reader, chunkLength); + } else { + obj.SkipChunk (reader, chunkLength); + } + }); + } - ReadEditorChunk (reader, length) - { - let obj = this; - let endByte = this.GetChunkEnd (reader, length); - this.ReadChunks (reader, endByte, function (chunkId, chunkLength) { - if (chunkId === OV.CHUNK3DS.EDIT_MATERIAL) { - obj.ReadMaterialChunk (reader, chunkLength); - } else if (chunkId === OV.CHUNK3DS.EDIT_OBJECT) { - obj.ReadObjectChunk (reader, chunkLength); - } else { - obj.SkipChunk (reader, chunkLength); - } - }); - } + ReadEditorChunk (reader, length) + { + let obj = this; + let endByte = this.GetChunkEnd (reader, length); + this.ReadChunks (reader, endByte, function (chunkId, chunkLength) { + if (chunkId === OV.CHUNK3DS.EDIT_MATERIAL) { + obj.ReadMaterialChunk (reader, chunkLength); + } else if (chunkId === OV.CHUNK3DS.EDIT_OBJECT) { + obj.ReadObjectChunk (reader, chunkLength); + } else { + obj.SkipChunk (reader, chunkLength); + } + }); + } - ReadMaterialChunk (reader, length) - { - let obj = this; - let material = new OV.Material (); - let endByte = this.GetChunkEnd (reader, length); - let shininess = null; - let shininessStrength = null; - this.ReadChunks (reader, endByte, function (chunkId, chunkLength) { - if (chunkId === OV.CHUNK3DS.MAT_NAME) { - material.name = obj.ReadName (reader); - } else if (chunkId === OV.CHUNK3DS.MAT_AMBIENT) { - material.ambient = obj.ReadColorChunk (reader, chunkLength); - } else if (chunkId === OV.CHUNK3DS.MAT_DIFFUSE) { - material.diffuse = obj.ReadColorChunk (reader, chunkLength); - } else if (chunkId === OV.CHUNK3DS.MAT_SPECULAR) { - material.specular = obj.ReadColorChunk (reader, chunkLength); - } else if (chunkId === OV.CHUNK3DS.MAT_SHININESS) { - shininess = obj.ReadPercentageChunk (reader, chunkLength); - } else if (chunkId === OV.CHUNK3DS.MAT_SHININESS_STRENGTH) { - shininessStrength = obj.ReadPercentageChunk (reader, chunkLength); - } else if (chunkId === OV.CHUNK3DS.MAT_TRANSPARENCY) { - material.opacity = 1.0 - obj.ReadPercentageChunk (reader, chunkLength); - material.transparent = OV.IsLower (material.opacity, 1.0); - } else if (chunkId === OV.CHUNK3DS.MAT_TEXMAP) { - material.diffuseMap = obj.ReadTextureMapChunk (reader, chunkLength); - } else { - obj.SkipChunk (reader, chunkLength); - } - }); + ReadMaterialChunk (reader, length) + { + let obj = this; + let material = new OV.Material (); + let endByte = this.GetChunkEnd (reader, length); + let shininess = null; + let shininessStrength = null; + this.ReadChunks (reader, endByte, function (chunkId, chunkLength) { + if (chunkId === OV.CHUNK3DS.MAT_NAME) { + material.name = obj.ReadName (reader); + } else if (chunkId === OV.CHUNK3DS.MAT_AMBIENT) { + material.ambient = obj.ReadColorChunk (reader, chunkLength); + } else if (chunkId === OV.CHUNK3DS.MAT_DIFFUSE) { + material.diffuse = obj.ReadColorChunk (reader, chunkLength); + } else if (chunkId === OV.CHUNK3DS.MAT_SPECULAR) { + material.specular = obj.ReadColorChunk (reader, chunkLength); + } else if (chunkId === OV.CHUNK3DS.MAT_SHININESS) { + shininess = obj.ReadPercentageChunk (reader, chunkLength); + } else if (chunkId === OV.CHUNK3DS.MAT_SHININESS_STRENGTH) { + shininessStrength = obj.ReadPercentageChunk (reader, chunkLength); + } else if (chunkId === OV.CHUNK3DS.MAT_TRANSPARENCY) { + material.opacity = 1.0 - obj.ReadPercentageChunk (reader, chunkLength); + material.transparent = OV.IsLower (material.opacity, 1.0); + } else if (chunkId === OV.CHUNK3DS.MAT_TEXMAP) { + material.diffuseMap = obj.ReadTextureMapChunk (reader, chunkLength); + } else { + obj.SkipChunk (reader, chunkLength); + } + }); - if (shininess !== null || shininessStrength !== null) { - material.shininess = shininess * shininessStrength; - } - let materialIndex = this.model.AddMaterial (material); - this.materialNameToIndex[material.name] = materialIndex; - } + if (shininess !== null && shininessStrength !== null) { + material.shininess = shininess * shininessStrength / 10.0; + } + let materialIndex = this.model.AddMaterial (material); + this.materialNameToIndex[material.name] = materialIndex; + } - ReadTextureMapChunk (reader, length) - { - let obj = this; - let texture = new OV.TextureMap (); - let endByte = this.GetChunkEnd (reader, length); - this.ReadChunks (reader, endByte, function (chunkId, chunkLength) { - if (chunkId === OV.CHUNK3DS.MAT_TEXMAP_NAME) { - let textureName = obj.ReadName (reader); - let textureBuffer = obj.callbacks.getTextureBuffer (textureName); - texture.name = textureName; - if (textureBuffer !== null) { - texture.url = textureBuffer.url; - texture.buffer = textureBuffer.buffer; - } - } else if (chunkId === OV.CHUNK3DS.MAT_TEXMAP_UOFFSET) { - texture.offset.x = reader.ReadFloat32 (); - } else if (chunkId === OV.CHUNK3DS.MAT_TEXMAP_VOFFSET) { - texture.offset.y = reader.ReadFloat32 (); - } else if (chunkId === OV.CHUNK3DS.MAT_TEXMAP_USCALE) { - texture.scale.x = reader.ReadFloat32 (); - } else if (chunkId === OV.CHUNK3DS.MAT_TEXMAP_VSCALE) { - texture.scale.y = reader.ReadFloat32 (); - } else if (chunkId === OV.CHUNK3DS.MAT_TEXMAP_ROTATION) { - texture.rotation = reader.ReadFloat32 () * OV.DegRad; - } else { - obj.SkipChunk (reader, chunkLength); - } - }); - return texture; - } + ReadTextureMapChunk (reader, length) + { + let obj = this; + let texture = new OV.TextureMap (); + let endByte = this.GetChunkEnd (reader, length); + this.ReadChunks (reader, endByte, function (chunkId, chunkLength) { + if (chunkId === OV.CHUNK3DS.MAT_TEXMAP_NAME) { + let textureName = obj.ReadName (reader); + let textureBuffer = obj.callbacks.getTextureBuffer (textureName); + texture.name = textureName; + if (textureBuffer !== null) { + texture.url = textureBuffer.url; + texture.buffer = textureBuffer.buffer; + } + } else if (chunkId === OV.CHUNK3DS.MAT_TEXMAP_UOFFSET) { + texture.offset.x = reader.ReadFloat32 (); + } else if (chunkId === OV.CHUNK3DS.MAT_TEXMAP_VOFFSET) { + texture.offset.y = reader.ReadFloat32 (); + } else if (chunkId === OV.CHUNK3DS.MAT_TEXMAP_USCALE) { + texture.scale.x = reader.ReadFloat32 (); + } else if (chunkId === OV.CHUNK3DS.MAT_TEXMAP_VSCALE) { + texture.scale.y = reader.ReadFloat32 (); + } else if (chunkId === OV.CHUNK3DS.MAT_TEXMAP_ROTATION) { + texture.rotation = reader.ReadFloat32 () * OV.DegRad; + } else { + obj.SkipChunk (reader, chunkLength); + } + }); + return texture; + } - ReadColorChunk (reader, length) - { - let obj = this; - let color = new OV.Color (0, 0, 0); - let endByte = this.GetChunkEnd (reader, length); - let hasLinColor = false; - this.ReadChunks (reader, endByte, function (chunkId, chunkLength) { - if (chunkId === OV.CHUNK3DS.MAT_COLOR) { - if (!hasLinColor) { - color.r = reader.ReadUnsignedCharacter8 (); - color.g = reader.ReadUnsignedCharacter8 (); - color.b = reader.ReadUnsignedCharacter8 (); - } - } else if (chunkId === OV.CHUNK3DS.MAT_LIN_COLOR) { - color.r = reader.ReadUnsignedCharacter8 (); - color.g = reader.ReadUnsignedCharacter8 (); - color.b = reader.ReadUnsignedCharacter8 (); - hasLinColor = true; - } else if (chunkId === OV.CHUNK3DS.MAT_COLOR_F) { - if (!hasLinColor) { - color.r = parseInt (reader.ReadFloat32 () * 255.0, 10); - color.g = parseInt (reader.ReadFloat32 () * 255.0, 10); - color.b = parseInt (reader.ReadFloat32 () * 255.0, 10); - } - } else if (chunkId === OV.CHUNK3DS.MAT_LIN_COLOR_F) { - color.r = parseInt (reader.ReadFloat32 () * 255.0, 10); - color.g = parseInt (reader.ReadFloat32 () * 255.0, 10); - color.b = parseInt (reader.ReadFloat32 () * 255.0, 10); - hasLinColor = true; - } else { - obj.SkipChunk (reader, chunkLength); - } - }); - return color; - } + ReadColorChunk (reader, length) + { + let obj = this; + let color = new OV.Color (0, 0, 0); + let endByte = this.GetChunkEnd (reader, length); + let hasLinColor = false; + this.ReadChunks (reader, endByte, function (chunkId, chunkLength) { + if (chunkId === OV.CHUNK3DS.MAT_COLOR) { + if (!hasLinColor) { + color.r = reader.ReadUnsignedCharacter8 (); + color.g = reader.ReadUnsignedCharacter8 (); + color.b = reader.ReadUnsignedCharacter8 (); + } + } else if (chunkId === OV.CHUNK3DS.MAT_LIN_COLOR) { + color.r = reader.ReadUnsignedCharacter8 (); + color.g = reader.ReadUnsignedCharacter8 (); + color.b = reader.ReadUnsignedCharacter8 (); + hasLinColor = true; + } else if (chunkId === OV.CHUNK3DS.MAT_COLOR_F) { + if (!hasLinColor) { + color.r = parseInt (reader.ReadFloat32 () * 255.0, 10); + color.g = parseInt (reader.ReadFloat32 () * 255.0, 10); + color.b = parseInt (reader.ReadFloat32 () * 255.0, 10); + } + } else if (chunkId === OV.CHUNK3DS.MAT_LIN_COLOR_F) { + color.r = parseInt (reader.ReadFloat32 () * 255.0, 10); + color.g = parseInt (reader.ReadFloat32 () * 255.0, 10); + color.b = parseInt (reader.ReadFloat32 () * 255.0, 10); + hasLinColor = true; + } else { + obj.SkipChunk (reader, chunkLength); + } + }); + return color; + } - ReadPercentageChunk (reader, length) - { - let obj = this; - let percentage = 0.0; - let endByte = this.GetChunkEnd (reader, length); - this.ReadChunks (reader, endByte, function (chunkId, chunkLength) { - if (chunkId === OV.CHUNK3DS.PERCENTAGE) { - percentage = reader.ReadUnsignedInteger16 () / 100.0; - } else if (chunkId === OV.CHUNK3DS.PERCENTAGE_F) { - percentage = reader.ReadFloat32 (); - } else { - obj.SkipChunk (reader, chunkLength); - } - }); - return percentage; - } + ReadPercentageChunk (reader, length) + { + let obj = this; + let percentage = 0.0; + let endByte = this.GetChunkEnd (reader, length); + this.ReadChunks (reader, endByte, function (chunkId, chunkLength) { + if (chunkId === OV.CHUNK3DS.PERCENTAGE) { + percentage = reader.ReadUnsignedInteger16 () / 100.0; + } else if (chunkId === OV.CHUNK3DS.PERCENTAGE_F) { + percentage = reader.ReadFloat32 (); + } else { + obj.SkipChunk (reader, chunkLength); + } + }); + return percentage; + } - ReadObjectChunk (reader, length) - { - let obj = this; - let endByte = this.GetChunkEnd (reader, length); - let objectName = this.ReadName (reader); - this.ReadChunks (reader, endByte, function (chunkId, chunkLength) { - if (chunkId === OV.CHUNK3DS.OBJ_TRIMESH) { - obj.ReadMeshChunk (reader, chunkLength, objectName); - } else if (chunkId === OV.CHUNK3DS.OBJ_LIGHT) { - obj.SkipChunk (reader, chunkLength); - } else if (chunkId === OV.CHUNK3DS.OBJ_CAMERA) { - obj.SkipChunk (reader, chunkLength); - } else { - obj.SkipChunk (reader, chunkLength); - } - }); - } + ReadObjectChunk (reader, length) + { + let obj = this; + let endByte = this.GetChunkEnd (reader, length); + let objectName = this.ReadName (reader); + this.ReadChunks (reader, endByte, function (chunkId, chunkLength) { + if (chunkId === OV.CHUNK3DS.OBJ_TRIMESH) { + obj.ReadMeshChunk (reader, chunkLength, objectName); + } else if (chunkId === OV.CHUNK3DS.OBJ_LIGHT) { + obj.SkipChunk (reader, chunkLength); + } else if (chunkId === OV.CHUNK3DS.OBJ_CAMERA) { + obj.SkipChunk (reader, chunkLength); + } else { + obj.SkipChunk (reader, chunkLength); + } + }); + } - ReadMeshChunk (reader, length, objectName) - { - let obj = this; + ReadMeshChunk (reader, length, objectName) + { + let obj = this; - let mesh = new OV.Mesh (); - mesh.SetName (objectName); + let mesh = new OV.Mesh (); + mesh.SetName (objectName); - let endByte = this.GetChunkEnd (reader, length); - let transformation = null; - this.ReadChunks (reader, endByte, function (chunkId, chunkLength) { - if (chunkId === OV.CHUNK3DS.TRI_VERTEX) { - obj.ReadVerticesChunk (mesh, reader); - } else if (chunkId === OV.CHUNK3DS.TRI_TEXVERTEX) { - obj.ReadTextureVerticesChunk (mesh, reader); - } else if (chunkId === OV.CHUNK3DS.TRI_FACE) { - obj.ReadFacesChunk (mesh, reader, chunkLength); - } else if (chunkId === OV.CHUNK3DS.TRI_TRANSFORMATION) { - transformation = obj.ReadTransformationChunk (reader); - } else { - obj.SkipChunk (reader, chunkLength); - } - }); + let endByte = this.GetChunkEnd (reader, length); + let transformation = null; + this.ReadChunks (reader, endByte, function (chunkId, chunkLength) { + if (chunkId === OV.CHUNK3DS.TRI_VERTEX) { + obj.ReadVerticesChunk (mesh, reader); + } else if (chunkId === OV.CHUNK3DS.TRI_TEXVERTEX) { + obj.ReadTextureVerticesChunk (mesh, reader); + } else if (chunkId === OV.CHUNK3DS.TRI_FACE) { + obj.ReadFacesChunk (mesh, reader, chunkLength); + } else if (chunkId === OV.CHUNK3DS.TRI_TRANSFORMATION) { + transformation = obj.ReadTransformationChunk (reader); + } else { + obj.SkipChunk (reader, chunkLength); + } + }); - if (mesh.VertexCount () === mesh.TextureUVCount ()) { - for (let i = 0; i < mesh.TriangleCount (); i++) { - let triangle = mesh.GetTriangle (i); - triangle.SetTextureUVs ( - triangle.v0, - triangle.v1, - triangle.v2 - ); - } - } + if (mesh.VertexCount () === mesh.TextureUVCount ()) { + for (let i = 0; i < mesh.TriangleCount (); i++) { + let triangle = mesh.GetTriangle (i); + triangle.SetTextureUVs ( + triangle.v0, + triangle.v1, + triangle.v2 + ); + } + } - let meshIndex = this.model.AddMesh (mesh); - this.meshNameToIndex[mesh.GetName ()] = meshIndex; - this.meshTransformations.push (new OV.Matrix (transformation)); - } + let meshIndex = this.model.AddMesh (mesh); + this.meshNameToIndex[mesh.GetName ()] = meshIndex; + this.meshTransformations.push (new OV.Matrix (transformation)); + } - ReadVerticesChunk (mesh, reader) - { - let vertexCount = reader.ReadUnsignedInteger16 (); - for (let i = 0; i < vertexCount; i++) { - let x = reader.ReadFloat32 (); - let y = reader.ReadFloat32 (); - let z = reader.ReadFloat32 (); - mesh.AddVertex (new OV.Coord3D (x, y, z)); - } - } + ReadVerticesChunk (mesh, reader) + { + let vertexCount = reader.ReadUnsignedInteger16 (); + for (let i = 0; i < vertexCount; i++) { + let x = reader.ReadFloat32 (); + let y = reader.ReadFloat32 (); + let z = reader.ReadFloat32 (); + mesh.AddVertex (new OV.Coord3D (x, y, z)); + } + } - ReadTextureVerticesChunk (mesh, reader) - { - let texVertexCount = reader.ReadUnsignedInteger16 (); - for (let i = 0; i < texVertexCount; i++) { - let x = reader.ReadFloat32 (); - let y = reader.ReadFloat32 (); - mesh.AddTextureUV (new OV.Coord2D (x, y)); - } - } + ReadTextureVerticesChunk (mesh, reader) + { + let texVertexCount = reader.ReadUnsignedInteger16 (); + for (let i = 0; i < texVertexCount; i++) { + let x = reader.ReadFloat32 (); + let y = reader.ReadFloat32 (); + mesh.AddTextureUV (new OV.Coord2D (x, y)); + } + } - ReadFacesChunk (mesh, reader, length) - { - let endByte = this.GetChunkEnd (reader, length); - let faceCount = reader.ReadUnsignedInteger16 (); - for (let i = 0; i < faceCount; i++) { - let v0 = reader.ReadUnsignedInteger16 (); - let v1 = reader.ReadUnsignedInteger16 (); - let v2 = reader.ReadUnsignedInteger16 (); - reader.ReadUnsignedInteger16 (); // flags - mesh.AddTriangle (new OV.Triangle (v0, v1, v2)); - } + ReadFacesChunk (mesh, reader, length) + { + let endByte = this.GetChunkEnd (reader, length); + let faceCount = reader.ReadUnsignedInteger16 (); + for (let i = 0; i < faceCount; i++) { + let v0 = reader.ReadUnsignedInteger16 (); + let v1 = reader.ReadUnsignedInteger16 (); + let v2 = reader.ReadUnsignedInteger16 (); + reader.ReadUnsignedInteger16 (); // flags + mesh.AddTriangle (new OV.Triangle (v0, v1, v2)); + } - let obj = this; - this.ReadChunks (reader, endByte, function (chunkId, chunkLength) { - if (chunkId === OV.CHUNK3DS.TRI_MATERIAL) { - obj.ReadFaceMaterialsChunk (mesh, reader); - } else if (chunkId === OV.CHUNK3DS.TRI_SMOOTH) { - obj.ReadFaceSmoothingGroupsChunk (mesh, faceCount, reader); - } else { - obj.SkipChunk (reader, chunkLength); - } - }); - } + let obj = this; + this.ReadChunks (reader, endByte, function (chunkId, chunkLength) { + if (chunkId === OV.CHUNK3DS.TRI_MATERIAL) { + obj.ReadFaceMaterialsChunk (mesh, reader); + } else if (chunkId === OV.CHUNK3DS.TRI_SMOOTH) { + obj.ReadFaceSmoothingGroupsChunk (mesh, faceCount, reader); + } else { + obj.SkipChunk (reader, chunkLength); + } + }); + } - ReadFaceMaterialsChunk (mesh, reader) - { - let materialName = this.ReadName (reader); - let materialIndex = this.materialNameToIndex[materialName]; - let faceCount = reader.ReadUnsignedInteger16 (); - for (let i = 0; i < faceCount; i++) { - let faceIndex = reader.ReadUnsignedInteger16 (); - let triangle = mesh.GetTriangle (faceIndex); - if (materialIndex !== undefined) { - triangle.mat = materialIndex; - } - } - } - - ReadFaceSmoothingGroupsChunk (mesh, faceCount, reader) - { - for (let i = 0; i < faceCount; i++) { - let smoothingGroup = reader.ReadUnsignedInteger32 (); - let triangle = mesh.GetTriangle (i); - triangle.curve = smoothingGroup; - } - } + ReadFaceMaterialsChunk (mesh, reader) + { + let materialName = this.ReadName (reader); + let materialIndex = this.materialNameToIndex[materialName]; + let faceCount = reader.ReadUnsignedInteger16 (); + for (let i = 0; i < faceCount; i++) { + let faceIndex = reader.ReadUnsignedInteger16 (); + let triangle = mesh.GetTriangle (faceIndex); + if (materialIndex !== undefined) { + triangle.mat = materialIndex; + } + } + } + + ReadFaceSmoothingGroupsChunk (mesh, faceCount, reader) + { + for (let i = 0; i < faceCount; i++) { + let smoothingGroup = reader.ReadUnsignedInteger32 (); + let triangle = mesh.GetTriangle (i); + triangle.curve = smoothingGroup; + } + } - ReadTransformationChunk (reader) - { - let matrix = []; - for (let i = 0; i < 4; i++) { - for (let j = 0; j < 3; j++) { - matrix.push (reader.ReadFloat32 ()); - } - if (i < 3) { - matrix.push (0); - } else { - matrix.push (1); - } - } - return matrix; - } + ReadTransformationChunk (reader) + { + let matrix = []; + for (let i = 0; i < 4; i++) { + for (let j = 0; j < 3; j++) { + matrix.push (reader.ReadFloat32 ()); + } + if (i < 3) { + matrix.push (0); + } else { + matrix.push (1); + } + } + return matrix; + } - ReadKeyFrameChunk (reader, length) - { - let nodeHierarchy = { - nodes : [], - idToIndex : {}, - meshIndexToNodes : {} - }; + ReadKeyFrameChunk (reader, length) + { + let nodeHierarchy = { + nodes : [], + idToIndex : {}, + meshIndexToNodes : {} + }; - let endByte = this.GetChunkEnd (reader, length); - let obj = this; - this.ReadChunks (reader, endByte, function (chunkId, chunkLength) { - if (chunkId === OV.CHUNK3DS.OBJECT_NODE) { - obj.ReadObjectNodeChunk (nodeHierarchy, reader, chunkLength); - } else { - obj.SkipChunk (reader, chunkLength); - } - }); + let endByte = this.GetChunkEnd (reader, length); + let obj = this; + this.ReadChunks (reader, endByte, function (chunkId, chunkLength) { + if (chunkId === OV.CHUNK3DS.OBJECT_NODE) { + obj.ReadObjectNodeChunk (nodeHierarchy, reader, chunkLength); + } else { + obj.SkipChunk (reader, chunkLength); + } + }); - this.ApplyModelTransformations (nodeHierarchy); - } + this.ApplyModelTransformations (nodeHierarchy); + } - ApplyModelTransformations (nodeHierarchy) - { - function GetNodeTransformation (nodeHierarchy, node) - { - function GetNodePosition (node) - { - if (node.positions.length === 0) { - return [0.0, 0.0, 0.0]; - } - return node.positions[0]; - } - - function GetNodeRotation (node) - { - function GetQuaternionFromAxisAndAngle (rotation) - { - let result = [0.0, 0.0, 0.0, 1.0]; - let length = Math.sqrt (rotation[0] * rotation[0] + rotation[1] * rotation[1] + rotation[2] * rotation[2]); - if (length > 0.0) { - let omega = rotation[3] * -0.5; - let si = Math.sin (omega) / length; - result = [si * rotation[0], si * rotation[1], si * rotation[2], Math.cos (omega)]; - } - return result; - } + ApplyModelTransformations (nodeHierarchy) + { + function GetNodeTransformation (nodeHierarchy, node) + { + function GetNodePosition (node) + { + if (node.positions.length === 0) { + return [0.0, 0.0, 0.0]; + } + return node.positions[0]; + } + + function GetNodeRotation (node) + { + function GetQuaternionFromAxisAndAngle (rotation) + { + let result = [0.0, 0.0, 0.0, 1.0]; + let length = Math.sqrt (rotation[0] * rotation[0] + rotation[1] * rotation[1] + rotation[2] * rotation[2]); + if (length > 0.0) { + let omega = rotation[3] * -0.5; + let si = Math.sin (omega) / length; + result = [si * rotation[0], si * rotation[1], si * rotation[2], Math.cos (omega)]; + } + return result; + } - if (node.rotations.length === 0) { - return [0.0, 0.0, 0.0, 1.0]; - } - - let rotation = node.rotations[0]; - return GetQuaternionFromAxisAndAngle (rotation); - } + if (node.rotations.length === 0) { + return [0.0, 0.0, 0.0, 1.0]; + } + + let rotation = node.rotations[0]; + return GetQuaternionFromAxisAndAngle (rotation); + } - function GetNodeScale (node) - { - if (node.scales.length === 0) { - return [1.0, 1.0, 1.0]; - } - return node.scales[0]; - } - - if (node.matrix !== null) { - return node.matrix; - } - - let matrix = new OV.Matrix (); - matrix.ComposeTRS ( - GetNodePosition (node), - GetNodeRotation (node), - GetNodeScale (node) - ); + function GetNodeScale (node) + { + if (node.scales.length === 0) { + return [1.0, 1.0, 1.0]; + } + return node.scales[0]; + } + + if (node.matrix !== null) { + return node.matrix; + } + + let matrix = new OV.Matrix (); + matrix.ComposeTRS ( + GetNodePosition (node), + GetNodeRotation (node), + GetNodeScale (node) + ); - if (node.userId !== 65535) { - let parentIndex = nodeHierarchy.idToIndex[node.userId]; - if (parentIndex !== undefined) { - let parentNode = nodeHierarchy.nodes[parentIndex]; - let parentMatrix = GetNodeTransformation (nodeHierarchy, parentNode); - matrix = matrix.MultiplyMatrix (parentMatrix); - } - } - - node.matrix = matrix; - return matrix; - } + if (node.userId !== 65535) { + let parentIndex = nodeHierarchy.idToIndex[node.userId]; + if (parentIndex !== undefined) { + let parentNode = nodeHierarchy.nodes[parentIndex]; + let parentMatrix = GetNodeTransformation (nodeHierarchy, parentNode); + matrix = matrix.MultiplyMatrix (parentMatrix); + } + } + + node.matrix = matrix; + return matrix; + } - function ApplyMeshTransformation (model, currentMeshIndex, meshMatrix, nodeHierarchy, node) - { - function GetNodePivotPoint (node) - { - if (node === null) { - return [0.0, 0.0, 0.0]; - } - return node.pivot; - } + function ApplyMeshTransformation (model, currentMeshIndex, meshMatrix, nodeHierarchy, node) + { + function GetNodePivotPoint (node) + { + if (node === null) { + return [0.0, 0.0, 0.0]; + } + return node.pivot; + } - if (!meshMatrix.IsValid ()) { - return; - } + if (!meshMatrix.IsValid ()) { + return; + } - let nodeMatrix = meshMatrix; - if (node !== null) { - nodeMatrix = GetNodeTransformation (nodeHierarchy, node); - } + let nodeMatrix = meshMatrix; + if (node !== null) { + nodeMatrix = GetNodeTransformation (nodeHierarchy, node); + } - let determinant = meshMatrix.Determinant (); - if (OV.IsNegative (determinant)) { - // Mirror by x coordinates - let scaleMatrix = new OV.Matrix ().CreateScale (-1.0, 1.0, 1.0); - meshMatrix = scaleMatrix.MultiplyMatrix (meshMatrix); - } + let mesh = model.GetMesh (currentMeshIndex); + let determinant = meshMatrix.Determinant (); + let mirrorByX = OV.IsNegative (determinant); + if (mirrorByX) { + // Mirror by x coordinates + let scaleMatrix = new OV.Matrix ().CreateScale (-1.0, 1.0, 1.0); + meshMatrix = scaleMatrix.MultiplyMatrix (meshMatrix); + } - let invMeshMatrix = meshMatrix.Invert (); - if (invMeshMatrix === null) { - return; - } - - let pivotPoint = GetNodePivotPoint (node); - let pivotMatrix = new OV.Matrix ().CreateTranslation (-pivotPoint[0], -pivotPoint[1], -pivotPoint[2]); + let invMeshMatrix = meshMatrix.Invert (); + if (invMeshMatrix === null) { + return; + } + + let pivotPoint = GetNodePivotPoint (node); + let pivotMatrix = new OV.Matrix ().CreateTranslation (-pivotPoint[0], -pivotPoint[1], -pivotPoint[2]); - let matrix = nodeMatrix.Clone (); - matrix = pivotMatrix.MultiplyMatrix (matrix); - matrix = invMeshMatrix.MultiplyMatrix (matrix); + let matrix = nodeMatrix.Clone (); + matrix = pivotMatrix.MultiplyMatrix (matrix); + matrix = invMeshMatrix.MultiplyMatrix (matrix); - let transformation = new OV.Transformation (matrix); - let mesh = model.GetMesh (currentMeshIndex); - OV.TransformMesh (mesh, transformation); - } + let transformation = new OV.Transformation (matrix); + if (mirrorByX) { + OV.FlipMeshTrianglesOrientation (mesh); + } + OV.TransformMesh (mesh, transformation); + } - function AddDuplicatedMesh (model, meshIndex, toIndex) - { - let mesh = model.GetMesh (meshIndex); - let clonedMesh = OV.CloneMesh (mesh); - let clonedMeshIndex = model.AddMeshToIndex (clonedMesh, toIndex); - return clonedMeshIndex; - } + function AddDuplicatedMesh (model, meshIndex, toIndex) + { + let mesh = model.GetMesh (meshIndex); + let clonedMesh = OV.CloneMesh (mesh); + let clonedMeshIndex = model.AddMeshToIndex (clonedMesh, toIndex); + return clonedMeshIndex; + } - let newToOldMeshIndexOffset = 0; - for (let meshIndex = 0; meshIndex < this.model.MeshCount (); meshIndex++) { - let currentMeshIndex = meshIndex; - let originalMeshIndex = currentMeshIndex - newToOldMeshIndexOffset; - let meshTransformation = this.meshTransformations[originalMeshIndex]; - let meshNodes = nodeHierarchy.meshIndexToNodes[originalMeshIndex]; - if (meshNodes === undefined) { - ApplyMeshTransformation (this.model, currentMeshIndex, meshTransformation, nodeHierarchy, null); - } else { - for (let nodeIndex = 0; nodeIndex < meshNodes.length; nodeIndex++) { - let currentNode = meshNodes[nodeIndex]; - let transformedMeshIndex = currentMeshIndex; - if (nodeIndex > 0) { - transformedMeshIndex = AddDuplicatedMesh (this.model, currentMeshIndex, currentMeshIndex + nodeIndex); - newToOldMeshIndexOffset += 1; - meshIndex += 1; - } - ApplyMeshTransformation (this.model, transformedMeshIndex, meshTransformation, nodeHierarchy, currentNode); - } - } - } - } + let newToOldMeshIndexOffset = 0; + for (let meshIndex = 0; meshIndex < this.model.MeshCount (); meshIndex++) { + let currentMeshIndex = meshIndex; + let originalMeshIndex = currentMeshIndex - newToOldMeshIndexOffset; + let meshTransformation = this.meshTransformations[originalMeshIndex]; + let meshNodes = nodeHierarchy.meshIndexToNodes[originalMeshIndex]; + if (meshNodes === undefined) { + ApplyMeshTransformation (this.model, currentMeshIndex, meshTransformation, nodeHierarchy, null); + } else { + for (let nodeIndex = 0; nodeIndex < meshNodes.length; nodeIndex++) { + let currentNode = meshNodes[nodeIndex]; + let transformedMeshIndex = currentMeshIndex; + if (nodeIndex > 0) { + transformedMeshIndex = AddDuplicatedMesh (this.model, currentMeshIndex, currentMeshIndex + nodeIndex); + newToOldMeshIndexOffset += 1; + meshIndex += 1; + } + ApplyMeshTransformation (this.model, transformedMeshIndex, meshTransformation, nodeHierarchy, currentNode); + } + } + } + } - ReadObjectNodeChunk (nodeHierarchy, reader, length) - { - function ReadTrackVector (obj, reader, type) - { - let result = []; - reader.Skip (10); - - let keyNum = reader.ReadInteger32 (); - for (let i = 0; i < keyNum; i++) { - reader.ReadInteger32 (); - let flags = reader.ReadUnsignedInteger16 (); - if (flags !== 0) { - reader.ReadFloat32 (); - } - - let current = null; - if (type === OV.CHUNK3DS.OBJECT_ROTATION) { - let tmp = reader.ReadFloat32 (); - current = obj.ReadVector (reader); - current[3] = tmp; - } else { - current = obj.ReadVector (reader); - } - result.push (current); - } + ReadObjectNodeChunk (nodeHierarchy, reader, length) + { + function ReadTrackVector (obj, reader, type) + { + let result = []; + reader.Skip (10); + + let keyNum = reader.ReadInteger32 (); + for (let i = 0; i < keyNum; i++) { + reader.ReadInteger32 (); + let flags = reader.ReadUnsignedInteger16 (); + if (flags !== 0) { + reader.ReadFloat32 (); + } + + let current = null; + if (type === OV.CHUNK3DS.OBJECT_ROTATION) { + let tmp = reader.ReadFloat32 (); + current = obj.ReadVector (reader); + current[3] = tmp; + } else { + current = obj.ReadVector (reader); + } + result.push (current); + } - return result; - } - - let objectNode = { - name : '', - instanceName : '', - nodeId : -1, - flags : -1, - userId : -1, - pivot : [0.0, 0.0, 0.0], - positions : [], - rotations : [], - scales : [], - matrix : null - }; - - let obj = this; - let endByte = this.GetChunkEnd (reader, length); - this.ReadChunks (reader, endByte, function (chunkId, chunkLength) { - if (chunkId === OV.CHUNK3DS.OBJECT_HIERARCHY) { - objectNode.name = obj.ReadName (reader); - objectNode.flags = reader.ReadUnsignedInteger32 (); - objectNode.userId = reader.ReadUnsignedInteger16 (); - } else if (chunkId === OV.CHUNK3DS.OBJECT_INSTANCE_NAME) { - objectNode.instanceName = obj.ReadName (reader); - } else if (chunkId === OV.CHUNK3DS.OBJECT_PIVOT) { - objectNode.pivot = obj.ReadVector (reader); - } else if (chunkId === OV.CHUNK3DS.OBJECT_POSITION) { - objectNode.positions = ReadTrackVector (obj, reader, OV.CHUNK3DS.OBJECT_POSITION); - } else if (chunkId === OV.CHUNK3DS.OBJECT_ROTATION) { - objectNode.rotations = ReadTrackVector (obj, reader, OV.CHUNK3DS.OBJECT_ROTATION); - } else if (chunkId === OV.CHUNK3DS.OBJECT_SCALE) { - objectNode.scales = ReadTrackVector (obj, reader, OV.CHUNK3DS.OBJECT_SCALE); - } else if (chunkId === OV.CHUNK3DS.OBJECT_ID) { - objectNode.nodeId = reader.ReadUnsignedInteger16 (); - } else { - obj.SkipChunk (reader, chunkLength); - } - }); + return result; + } + + let objectNode = { + name : '', + instanceName : '', + nodeId : -1, + flags : -1, + userId : -1, + pivot : [0.0, 0.0, 0.0], + positions : [], + rotations : [], + scales : [], + matrix : null + }; + + let obj = this; + let endByte = this.GetChunkEnd (reader, length); + this.ReadChunks (reader, endByte, function (chunkId, chunkLength) { + if (chunkId === OV.CHUNK3DS.OBJECT_HIERARCHY) { + objectNode.name = obj.ReadName (reader); + objectNode.flags = reader.ReadUnsignedInteger32 (); + objectNode.userId = reader.ReadUnsignedInteger16 (); + } else if (chunkId === OV.CHUNK3DS.OBJECT_INSTANCE_NAME) { + objectNode.instanceName = obj.ReadName (reader); + } else if (chunkId === OV.CHUNK3DS.OBJECT_PIVOT) { + objectNode.pivot = obj.ReadVector (reader); + } else if (chunkId === OV.CHUNK3DS.OBJECT_POSITION) { + objectNode.positions = ReadTrackVector (obj, reader, OV.CHUNK3DS.OBJECT_POSITION); + } else if (chunkId === OV.CHUNK3DS.OBJECT_ROTATION) { + objectNode.rotations = ReadTrackVector (obj, reader, OV.CHUNK3DS.OBJECT_ROTATION); + } else if (chunkId === OV.CHUNK3DS.OBJECT_SCALE) { + objectNode.scales = ReadTrackVector (obj, reader, OV.CHUNK3DS.OBJECT_SCALE); + } else if (chunkId === OV.CHUNK3DS.OBJECT_ID) { + objectNode.nodeId = reader.ReadUnsignedInteger16 (); + } else { + obj.SkipChunk (reader, chunkLength); + } + }); - let nodeIndex = nodeHierarchy.nodes.length; - nodeHierarchy.nodes.push (objectNode); - nodeHierarchy.idToIndex[objectNode.nodeId] = nodeIndex; + let nodeIndex = nodeHierarchy.nodes.length; + nodeHierarchy.nodes.push (objectNode); + nodeHierarchy.idToIndex[objectNode.nodeId] = nodeIndex; - let meshIndex = this.meshNameToIndex[objectNode.name]; - if (meshIndex !== undefined) { - let meshNodes = nodeHierarchy.meshIndexToNodes[meshIndex]; - if (meshNodes === undefined) { - nodeHierarchy.meshIndexToNodes[meshIndex] = []; - } - nodeHierarchy.meshIndexToNodes[meshIndex].push (objectNode); - } - } + let meshIndex = this.meshNameToIndex[objectNode.name]; + if (meshIndex !== undefined) { + let meshNodes = nodeHierarchy.meshIndexToNodes[meshIndex]; + if (meshNodes === undefined) { + nodeHierarchy.meshIndexToNodes[meshIndex] = []; + } + nodeHierarchy.meshIndexToNodes[meshIndex].push (objectNode); + } + } - ReadName (reader) - { - let name = ''; - let char = 0; - let count = 0; - while (count < 64) { - char = reader.ReadCharacter8 (); - if (char === 0) { - break; - } - name = name + String.fromCharCode (char); - count = count + 1; - } - return name; - } + ReadName (reader) + { + let name = ''; + let char = 0; + let count = 0; + while (count < 64) { + char = reader.ReadCharacter8 (); + if (char === 0) { + break; + } + name = name + String.fromCharCode (char); + count = count + 1; + } + return name; + } - ReadVector (reader) - { - let result = [ - reader.ReadFloat32 (), - reader.ReadFloat32 (), - reader.ReadFloat32 () - ]; - return result; - } + ReadVector (reader) + { + let result = [ + reader.ReadFloat32 (), + reader.ReadFloat32 (), + reader.ReadFloat32 () + ]; + return result; + } - ReadChunks (reader, endByte, onChunk) - { - while (reader.GetPosition () <= endByte - 6) { - let chunkId = reader.ReadUnsignedInteger16 (); - let chunkLength = reader.ReadUnsignedInteger32 (); - onChunk (chunkId, chunkLength); - } - } - - GetChunkEnd (reader, length) - { - return reader.GetPosition () + length - 6; - } + ReadChunks (reader, endByte, onChunk) + { + while (reader.GetPosition () <= endByte - 6) { + let chunkId = reader.ReadUnsignedInteger16 (); + let chunkLength = reader.ReadUnsignedInteger32 (); + onChunk (chunkId, chunkLength); + } + } + + GetChunkEnd (reader, length) + { + return reader.GetPosition () + length - 6; + } - SkipChunk (reader, length) - { - reader.Skip (length - 6); - } + SkipChunk (reader, length) + { + reader.Skip (length - 6); + } }; diff --git a/source/import/importerbase.js b/source/import/importerbase.js index ae9e584..f9bb20d 100644 --- a/source/import/importerbase.js +++ b/source/import/importerbase.js @@ -1,57 +1,83 @@ OV.ImporterBase = class { constructor () + { + + } + + Import (content, extension, callbacks) + { + this.Clear (); + + this.extension = extension; + this.callbacks = callbacks; + this.model = new OV.Model (); + this.error = false; + this.message = null; + this.ResetContent (); + + let obj = this; + this.ImportContent (content, function () { + obj.CreateResult (callbacks); + }); + } + + Clear () { this.extension = null; this.callbacks = null; this.model = null; this.error = null; this.message = null; + this.ClearContent (); } - - Import (content, extension, callbacks) - { - this.extension = extension; - this.callbacks = callbacks; - this.model = new OV.Model (); - this.error = false; - this.message = null; - this.ResetState (); - this.ImportContent (content); + CreateResult (callbacks) + { if (this.error) { + callbacks.onError (); + callbacks.onComplete (); return; } if (OV.IsModelEmpty (this.model)) { this.error = true; + callbacks.onError (); + callbacks.onComplete (); return; } OV.FinalizeModel (this.model, this.callbacks.getDefaultMaterial); - } - - ResetState () - { - + callbacks.onSuccess (); + callbacks.onComplete (); } - CanImportExtension (extension) - { - return false; - } + CanImportExtension (extension) + { + return false; + } - GetKnownFileFormats () - { - return {}; - } + GetKnownFileFormats () + { + return {}; + } GetUpDirection () { return OV.Direction.Z; } - ImportContent (content) + ClearContent () + { + + } + + ResetContent () + { + + } + + ImportContent (fileContent, onFinish) { } diff --git a/source/import/importergltf.js b/source/import/importergltf.js index 57cab21..4a24c7a 100644 --- a/source/import/importergltf.js +++ b/source/import/importergltf.js @@ -1,40 +1,40 @@ OV.GltfComponentType = { - BYTE : 5120, - UNSIGNED_BYTE : 5121, - SHORT : 5122, - UNSIGNED_SHORT : 5123, - UNSIGNED_INT : 5125, - FLOAT : 5126 + BYTE : 5120, + UNSIGNED_BYTE : 5121, + SHORT : 5122, + UNSIGNED_SHORT : 5123, + UNSIGNED_INT : 5125, + FLOAT : 5126 }; OV.GltfDataType = { - SCALAR : 0, - VEC2 : 1, - VEC3 : 2, - VEC4 : 3, - MAT2 : 4, - MAT3 : 5, + SCALAR : 0, + VEC2 : 1, + VEC3 : 2, + VEC4 : 3, + MAT2 : 4, + MAT3 : 5, MAT4 : 6 }; OV.GltfRenderMode = { - POINTS : 0, - LINES : 1, - LINE_LOOP : 2, - LINE_STRIP : 3, - TRIANGLES : 4, - TRIANGLE_STRIP : 5, + POINTS : 0, + LINES : 1, + LINE_LOOP : 2, + LINE_STRIP : 3, + TRIANGLES : 4, + TRIANGLE_STRIP : 5, TRIANGLE_FAN : 6 }; OV.GltfConstants = { - GLTF_STRING : 0x46546C67, - JSON_CHUNK_TYPE : 0x4E4F534A, - BINARY_CHUNK_TYPE : 0x004E4942 + GLTF_STRING : 0x46546C67, + JSON_CHUNK_TYPE : 0x4E4F534A, + BINARY_CHUNK_TYPE : 0x004E4942 }; OV.GltfNodeTree = class @@ -345,49 +345,53 @@ OV.GltfExtensions = class OV.ImporterGltf = class extends OV.ImporterBase { - constructor () - { - super (); - - this.bufferContents = null; - this.gltfExtensions = null; - this.imageIndexToTextureParams = null; - } - - ResetState () - { - this.bufferContents = []; - this.gltfExtensions = new OV.GltfExtensions (); - this.imageIndexToTextureParams = {}; - } + constructor () + { + super (); + } - CanImportExtension (extension) - { - return extension === 'gltf' || extension === 'glb'; - } + CanImportExtension (extension) + { + return extension === 'gltf' || extension === 'glb'; + } - GetKnownFileFormats () - { - return { - 'gltf' : OV.FileFormat.Text, + GetKnownFileFormats () + { + return { + 'gltf' : OV.FileFormat.Text, 'glb' : OV.FileFormat.Binary, 'bin' : OV.FileFormat.Binary - }; - } + }; + } GetUpDirection () { return OV.Direction.Y; } - ImportContent (fileContent) - { + ClearContent () + { + this.bufferContents = null; + this.gltfExtensions = null; + this.imageIndexToTextureParams = null; + } + + ResetContent () + { + this.bufferContents = []; + this.gltfExtensions = new OV.GltfExtensions (); + this.imageIndexToTextureParams = {}; + } + + ImportContent (fileContent, onFinish) + { if (this.extension === 'gltf') { this.ProcessGltf (fileContent); } else if (this.extension === 'glb') { this.ProcessBinaryGltf (fileContent); } - } + onFinish (); + } ProcessGltf (fileContent) { @@ -868,7 +872,7 @@ OV.ImporterGltf = class extends OV.ImporterBase let reader = new OV.GltfBufferReader (buffer); reader.SkipBytes (bufferView.byteOffset || 0); let byteStride = bufferView.byteStride; - if (byteStride !== undefined) { + if (byteStride !== undefined && byteStride !== 0) { reader.SetByteStride (byteStride); } diff --git a/source/import/importerobj.js b/source/import/importerobj.js index b2e011f..c0ab107 100644 --- a/source/import/importerobj.js +++ b/source/import/importerobj.js @@ -1,387 +1,391 @@ OV.ImporterObj = class extends OV.ImporterBase { - constructor () - { - super (); + constructor () + { + super (); + } - this.globalVertices = null; - this.globalNormals = null; - this.globalUvs = null; - - this.currentMesh = null; - this.currentMeshData = null; - this.currentMaterial = null; - this.currentMaterialIndex = null; - - this.meshNameToMeshData = null; - this.materialNameToIndex = null; - } - - ResetState () - { - this.globalVertices = []; - this.globalNormals = []; - this.globalUvs = []; + CanImportExtension (extension) + { + return extension === 'obj'; + } + + GetKnownFileFormats () + { + return { + 'obj' : OV.FileFormat.Text, + 'mtl' : OV.FileFormat.Text + }; + } - this.currentMesh = null; - this.currentMeshData = null; - this.currentMaterial = null; - this.currentMaterialIndex = null; - - this.meshNameToMeshData = {}; - this.materialNameToIndex = {}; - } - - CanImportExtension (extension) - { - return extension === 'obj'; - } - - GetKnownFileFormats () - { - return { - 'obj' : OV.FileFormat.Text, - 'mtl' : OV.FileFormat.Text - }; - } - - GetUpDirection () + GetUpDirection () { return OV.Direction.Y; } - - ImportContent (fileContent) - { - let obj = this; - OV.ReadLines (fileContent, function (line) { - if (!obj.IsError ()) { - obj.ProcessLine (line); - } - }); - } - - ProcessLine (line) - { - if (line[0] === '#') { - return; - } + + ClearContent () + { + this.globalVertices = null; + this.globalNormals = null; + this.globalUvs = null; + + this.currentMesh = null; + this.currentMeshData = null; + this.currentMaterial = null; + this.currentMaterialIndex = null; + + this.meshNameToMeshData = null; + this.materialNameToIndex = null; + } - let parameters = OV.ParametersFromLine (line, '#'); - if (parameters.length === 0) { - return; - } - - let keyword = parameters[0].toLowerCase (); - parameters.shift (); + ResetContent () + { + this.globalVertices = []; + this.globalNormals = []; + this.globalUvs = []; - if (this.ProcessMeshParameter (keyword, parameters, line)) { - return; - } + this.currentMesh = null; + this.currentMeshData = null; + this.currentMaterial = null; + this.currentMaterialIndex = null; - if (this.ProcessMaterialParameter (keyword, parameters, line)) { - return; - } - } - - AddNewMesh (name) - { - let meshData = this.meshNameToMeshData[name]; - if (meshData === undefined) { - let mesh = new OV.Mesh (); - if (name !== null) { - mesh.SetName (name); - } - this.model.AddMesh (mesh); - meshData = { - mesh : mesh, - data : { - globalToCurrentVertices : {}, - globalToCurrentNormals : {}, - globalToCurrentUvs : {} - } - }; - this.meshNameToMeshData[name] = meshData; - } - this.currentMesh = meshData.mesh; - this.currentMeshData = meshData.data; - } + this.meshNameToMeshData = {}; + this.materialNameToIndex = {}; + } + + ImportContent (fileContent, onFinish) + { + let obj = this; + OV.ReadLines (fileContent, function (line) { + if (!obj.IsError ()) { + obj.ProcessLine (line); + } + }); + onFinish (); + } + + ProcessLine (line) + { + if (line[0] === '#') { + return; + } - ProcessMeshParameter (keyword, parameters, line) - { - if (keyword === 'g' || keyword === 'o') { - if (parameters.length === 0) { - return true; - } - let name = OV.NameFromLine (line, keyword.length, '#'); - this.AddNewMesh (name); - return true; - } else if (keyword === 'v') { - if (parameters.length < 3) { - return true; - } - this.globalVertices.push (new OV.Coord3D ( - parseFloat (parameters[0]), - parseFloat (parameters[1]), - parseFloat (parameters[2]) - )); - return true; - } else if (keyword === 'vn') { - if (parameters.length < 3) { - return true; - } - this.globalNormals.push (new OV.Coord3D ( - parseFloat (parameters[0]), - parseFloat (parameters[1]), - parseFloat (parameters[2]) - )); - return true; - } else if (keyword === 'vt') { - if (parameters.length < 2) { - return true; - } - this.globalUvs.push (new OV.Coord2D ( - parseFloat (parameters[0]), - parseFloat (parameters[1]) - )); - return true; - } else if (keyword === 'f') { - if (parameters.length < 3) { - return true; - } - this.ProcessFace (parameters); - return true; - } + let parameters = OV.ParametersFromLine (line, '#'); + if (parameters.length === 0) { + return; + } + + let keyword = parameters[0].toLowerCase (); + parameters.shift (); - return false; - } + if (this.ProcessMeshParameter (keyword, parameters, line)) { + return; + } - ProcessMaterialParameter (keyword, parameters, line) - { - function CreateColor (parameters) - { - return new OV.Color ( - parseInt (parseFloat (parameters[0] * 255.0), 10), - parseInt (parseFloat (parameters[1] * 255.0), 10), - parseInt (parseFloat (parameters[2] * 255.0), 10) - ); - } + if (this.ProcessMaterialParameter (keyword, parameters, line)) { + return; + } + } + + AddNewMesh (name) + { + let meshData = this.meshNameToMeshData[name]; + if (meshData === undefined) { + let mesh = new OV.Mesh (); + if (name !== null) { + mesh.SetName (name); + } + this.model.AddMesh (mesh); + meshData = { + mesh : mesh, + data : { + globalToCurrentVertices : {}, + globalToCurrentNormals : {}, + globalToCurrentUvs : {} + } + }; + this.meshNameToMeshData[name] = meshData; + } + this.currentMesh = meshData.mesh; + this.currentMeshData = meshData.data; + } - function CreateTexture (keyword, line, callbacks) - { - let texture = new OV.TextureMap (); - let textureName = OV.NameFromLine (line, keyword.length, '#'); - let textureBuffer = callbacks.getTextureBuffer (textureName); - texture.name = textureName; - if (textureBuffer !== null) { - texture.url = textureBuffer.url; - texture.buffer = textureBuffer.buffer; - } - return texture; - } + ProcessMeshParameter (keyword, parameters, line) + { + if (keyword === 'g' || keyword === 'o') { + if (parameters.length === 0) { + return true; + } + let name = OV.NameFromLine (line, keyword.length, '#'); + this.AddNewMesh (name); + return true; + } else if (keyword === 'v') { + if (parameters.length < 3) { + return true; + } + this.globalVertices.push (new OV.Coord3D ( + parseFloat (parameters[0]), + parseFloat (parameters[1]), + parseFloat (parameters[2]) + )); + return true; + } else if (keyword === 'vn') { + if (parameters.length < 3) { + return true; + } + this.globalNormals.push (new OV.Coord3D ( + parseFloat (parameters[0]), + parseFloat (parameters[1]), + parseFloat (parameters[2]) + )); + return true; + } else if (keyword === 'vt') { + if (parameters.length < 2) { + return true; + } + this.globalUvs.push (new OV.Coord2D ( + parseFloat (parameters[0]), + parseFloat (parameters[1]) + )); + return true; + } else if (keyword === 'f') { + if (parameters.length < 3) { + return true; + } + this.ProcessFace (parameters); + return true; + } - let obj = this; - if (keyword === 'newmtl') { - if (parameters.length === 0) { - return true; - } - - let material = new OV.Material (); - let materialName = OV.NameFromLine (line, keyword.length, '#'); - let materialIndex = this.model.AddMaterial (material); - material.name = materialName; - this.currentMaterial = material; - this.materialNameToIndex[materialName] = materialIndex; - return true; - } else if (keyword === 'usemtl') { - if (parameters.length === 0) { - return true; - } - - let materialName = OV.NameFromLine (line, keyword.length, '#'); - let materialIndex = this.materialNameToIndex[materialName]; - if (materialIndex !== undefined) { - this.currentMaterialIndex = materialIndex; - } - return true; - } else if (keyword === 'mtllib') { - if (parameters.length === 0) { - return true; - } - let fileName = OV.NameFromLine (line, keyword.length, '#'); - let fileBuffer = this.callbacks.getFileBuffer (fileName); - if (fileBuffer !== null) { - OV.ReadLines (fileBuffer, function (line) { - if (!obj.IsError ()) { - obj.ProcessLine (line); - } - }); - } - return true; - } else if (keyword === 'map_kd') { - if (this.currentMaterial === null || parameters.length === 0) { - return true; - } - this.currentMaterial.diffuseMap = CreateTexture (keyword, line, this.callbacks); - return true; - } else if (keyword === 'map_ks') { - if (this.currentMaterial === null || parameters.length === 0) { - return true; - } - this.currentMaterial.specularMap = CreateTexture (keyword, line, this.callbacks); - return true; - } else if (keyword === 'map_bump' || keyword === 'bump') { - if (this.currentMaterial === null || parameters.length === 0) { - return true; - } - this.currentMaterial.bumpMap = CreateTexture (keyword, line, this.callbacks); - return true; - } else if (keyword === 'ka') { - if (this.currentMaterial === null || parameters.length < 3) { - return true; - } - this.currentMaterial.ambient = CreateColor (parameters); - return true; - } else if (keyword === 'kd') { - if (this.currentMaterial === null || parameters.length < 3) { - return true; - } - this.currentMaterial.diffuse = CreateColor (parameters); - return true; - } else if (keyword === 'ks') { - if (this.currentMaterial === null || parameters.length < 3) { - return true; - } - this.currentMaterial.specular = CreateColor (parameters); - return true; - } else if (keyword === 'ns') { - if (this.currentMaterial === null || parameters.length < 1) { - return true; - } - this.currentMaterial.shininess = parseFloat (parameters[0]) / 100.0; - return true; - } else if (keyword === 'tr') { - if (this.currentMaterial === null || parameters.length < 1) { - return true; - } - this.currentMaterial.opacity = 1.0 - parseFloat (parameters[0]); - this.currentMaterial.transparent = OV.IsLower (this.currentMaterial.opacity, 1.0); - return true; - } else if (keyword === 'd') { - if (this.currentMaterial === null || parameters.length < 1) { - return true; - } - this.currentMaterial.opacity = parseFloat (parameters[0]); - this.currentMaterial.transparent = OV.IsLower (this.currentMaterial.opacity, 1.0); - return true; - } + return false; + } - return false; - } + ProcessMaterialParameter (keyword, parameters, line) + { + function CreateColor (parameters) + { + return new OV.Color ( + parseInt (parseFloat (parameters[0] * 255.0), 10), + parseInt (parseFloat (parameters[1] * 255.0), 10), + parseInt (parseFloat (parameters[2] * 255.0), 10) + ); + } - ProcessFace (parameters) - { - function GetRelativeIndex (index, count) - { - if (index > 0) { - return index - 1; - } else { - return count + index; - } - } - - function GetLocalIndex (globalValueArray, globalToCurrentIndices, globalIndex, valueAdderFunc) - { - if (isNaN (globalIndex) || globalIndex < 0 || globalIndex >= globalValueArray.length) { - return null; - } - let result = globalToCurrentIndices[globalIndex]; - if (result === undefined) { - let globalValue = globalValueArray[globalIndex]; - if (globalValue === undefined) { - return null; - } - result = valueAdderFunc (globalValue); - globalToCurrentIndices[globalIndex] = result; - } - return result; - } - - function GetLocalVertexIndex (obj, mesh, globalIndex) - { - return GetLocalIndex (obj.globalVertices, obj.currentMeshData.globalToCurrentVertices, globalIndex, function (val) { - return mesh.AddVertex (new OV.Coord3D (val.x, val.y, val.z)); - }); - } - - function GetLocalNormalIndex (obj, mesh, globalIndex) - { - return GetLocalIndex (obj.globalNormals, obj.currentMeshData.globalToCurrentNormals, globalIndex, function (val) { - return mesh.AddNormal (new OV.Coord3D (val.x, val.y, val.z)); - }); - } - - function GetLocalUVIndex (obj, mesh, globalIndex) - { - return GetLocalIndex (obj.globalUvs, obj.currentMeshData.globalToCurrentUvs, globalIndex, function (val) { - return mesh.AddTextureUV (new OV.Coord2D (val.x, val.y)); - }); - } - - let vertices = []; - let normals = []; - let uvs = []; - - for (let i = 0; i < parameters.length; i++) { - let vertexParams = parameters[i].split ('/'); - vertices.push (GetRelativeIndex (parseInt (vertexParams[0], 10), this.globalVertices.length)); - if (vertexParams.length > 1 && vertexParams[1].length > 0) { - uvs.push (GetRelativeIndex (parseInt (vertexParams[1], 10), this.globalUvs.length)); - } - if (vertexParams.length > 2 && vertexParams[2].length > 0) { - normals.push (GetRelativeIndex (parseInt (vertexParams[2], 10), this.globalNormals.length)); - } - } - - if (this.currentMesh === null) { - this.AddNewMesh (''); - } - - for (let i = 0; i < vertices.length - 2; i++) { - let v0 = GetLocalVertexIndex (this, this.currentMesh, vertices[0]); - let v1 = GetLocalVertexIndex (this, this.currentMesh, vertices[i + 1]); - let v2 = GetLocalVertexIndex (this, this.currentMesh, vertices[i + 2]); - if (v0 === null || v1 === null || v2 === null) { - this.SetError (); - this.SetMessage ('Invalid vertex index.'); - break; - } - let triangle = new OV.Triangle (v0, v1, v2); - if (normals.length === vertices.length) { - let n0 = GetLocalNormalIndex (this, this.currentMesh, normals[0]); - let n1 = GetLocalNormalIndex (this, this.currentMesh, normals[i + 1]); - let n2 = GetLocalNormalIndex (this, this.currentMesh, normals[i + 2]); - if (n0 === null || n1 === null || n2 === null) { - this.SetError (); - this.SetMessage ('Invalid normal index.'); - break; - } - triangle.SetNormals (n0, n1, n2); - } - if (uvs.length === vertices.length) { - let u0 = GetLocalUVIndex (this, this.currentMesh, uvs[0]); - let u1 = GetLocalUVIndex (this, this.currentMesh, uvs[i + 1]); - let u2 = GetLocalUVIndex (this, this.currentMesh, uvs[i + 2]); - if (u0 === null || u1 === null || u2 === null) { - this.SetError (); - this.SetMessage ('Invalid uv index.'); - break; - } - triangle.SetTextureUVs (u0, u1, u2); - } - if (this.currentMaterialIndex !== null) { - triangle.mat = this.currentMaterialIndex; - } - this.currentMesh.AddTriangle (triangle); - } - } + function CreateTexture (keyword, line, callbacks) + { + let texture = new OV.TextureMap (); + let textureName = OV.NameFromLine (line, keyword.length, '#'); + let textureBuffer = callbacks.getTextureBuffer (textureName); + texture.name = textureName; + if (textureBuffer !== null) { + texture.url = textureBuffer.url; + texture.buffer = textureBuffer.buffer; + } + return texture; + } + + let obj = this; + if (keyword === 'newmtl') { + if (parameters.length === 0) { + return true; + } + + let material = new OV.Material (); + let materialName = OV.NameFromLine (line, keyword.length, '#'); + let materialIndex = this.model.AddMaterial (material); + material.name = materialName; + this.currentMaterial = material; + this.materialNameToIndex[materialName] = materialIndex; + return true; + } else if (keyword === 'usemtl') { + if (parameters.length === 0) { + return true; + } + + let materialName = OV.NameFromLine (line, keyword.length, '#'); + let materialIndex = this.materialNameToIndex[materialName]; + if (materialIndex !== undefined) { + this.currentMaterialIndex = materialIndex; + } + return true; + } else if (keyword === 'mtllib') { + if (parameters.length === 0) { + return true; + } + let fileName = OV.NameFromLine (line, keyword.length, '#'); + let fileBuffer = this.callbacks.getFileBuffer (fileName); + if (fileBuffer !== null) { + OV.ReadLines (fileBuffer, function (line) { + if (!obj.IsError ()) { + obj.ProcessLine (line); + } + }); + } + return true; + } else if (keyword === 'map_kd') { + if (this.currentMaterial === null || parameters.length === 0) { + return true; + } + this.currentMaterial.diffuseMap = CreateTexture (keyword, line, this.callbacks); + return true; + } else if (keyword === 'map_ks') { + if (this.currentMaterial === null || parameters.length === 0) { + return true; + } + this.currentMaterial.specularMap = CreateTexture (keyword, line, this.callbacks); + return true; + } else if (keyword === 'map_bump' || keyword === 'bump') { + if (this.currentMaterial === null || parameters.length === 0) { + return true; + } + this.currentMaterial.bumpMap = CreateTexture (keyword, line, this.callbacks); + return true; + } else if (keyword === 'ka') { + if (this.currentMaterial === null || parameters.length < 3) { + return true; + } + this.currentMaterial.ambient = CreateColor (parameters); + return true; + } else if (keyword === 'kd') { + if (this.currentMaterial === null || parameters.length < 3) { + return true; + } + this.currentMaterial.diffuse = CreateColor (parameters); + return true; + } else if (keyword === 'ks') { + if (this.currentMaterial === null || parameters.length < 3) { + return true; + } + this.currentMaterial.specular = CreateColor (parameters); + return true; + } else if (keyword === 'ns') { + if (this.currentMaterial === null || parameters.length < 1) { + return true; + } + this.currentMaterial.shininess = parseFloat (parameters[0]) / 1000.0; + return true; + } else if (keyword === 'tr') { + if (this.currentMaterial === null || parameters.length < 1) { + return true; + } + this.currentMaterial.opacity = 1.0 - parseFloat (parameters[0]); + this.currentMaterial.transparent = OV.IsLower (this.currentMaterial.opacity, 1.0); + return true; + } else if (keyword === 'd') { + if (this.currentMaterial === null || parameters.length < 1) { + return true; + } + this.currentMaterial.opacity = parseFloat (parameters[0]); + this.currentMaterial.transparent = OV.IsLower (this.currentMaterial.opacity, 1.0); + return true; + } + + return false; + } + + ProcessFace (parameters) + { + function GetRelativeIndex (index, count) + { + if (index > 0) { + return index - 1; + } else { + return count + index; + } + } + + function GetLocalIndex (globalValueArray, globalToCurrentIndices, globalIndex, valueAdderFunc) + { + if (isNaN (globalIndex) || globalIndex < 0 || globalIndex >= globalValueArray.length) { + return null; + } + let result = globalToCurrentIndices[globalIndex]; + if (result === undefined) { + let globalValue = globalValueArray[globalIndex]; + if (globalValue === undefined) { + return null; + } + result = valueAdderFunc (globalValue); + globalToCurrentIndices[globalIndex] = result; + } + return result; + } + + function GetLocalVertexIndex (obj, mesh, globalIndex) + { + return GetLocalIndex (obj.globalVertices, obj.currentMeshData.globalToCurrentVertices, globalIndex, function (val) { + return mesh.AddVertex (new OV.Coord3D (val.x, val.y, val.z)); + }); + } + + function GetLocalNormalIndex (obj, mesh, globalIndex) + { + return GetLocalIndex (obj.globalNormals, obj.currentMeshData.globalToCurrentNormals, globalIndex, function (val) { + return mesh.AddNormal (new OV.Coord3D (val.x, val.y, val.z)); + }); + } + + function GetLocalUVIndex (obj, mesh, globalIndex) + { + return GetLocalIndex (obj.globalUvs, obj.currentMeshData.globalToCurrentUvs, globalIndex, function (val) { + return mesh.AddTextureUV (new OV.Coord2D (val.x, val.y)); + }); + } + + let vertices = []; + let normals = []; + let uvs = []; + + for (let i = 0; i < parameters.length; i++) { + let vertexParams = parameters[i].split ('/'); + vertices.push (GetRelativeIndex (parseInt (vertexParams[0], 10), this.globalVertices.length)); + if (vertexParams.length > 1 && vertexParams[1].length > 0) { + uvs.push (GetRelativeIndex (parseInt (vertexParams[1], 10), this.globalUvs.length)); + } + if (vertexParams.length > 2 && vertexParams[2].length > 0) { + normals.push (GetRelativeIndex (parseInt (vertexParams[2], 10), this.globalNormals.length)); + } + } + + if (this.currentMesh === null) { + this.AddNewMesh (''); + } + + for (let i = 0; i < vertices.length - 2; i++) { + let v0 = GetLocalVertexIndex (this, this.currentMesh, vertices[0]); + let v1 = GetLocalVertexIndex (this, this.currentMesh, vertices[i + 1]); + let v2 = GetLocalVertexIndex (this, this.currentMesh, vertices[i + 2]); + if (v0 === null || v1 === null || v2 === null) { + this.SetError (); + this.SetMessage ('Invalid vertex index.'); + break; + } + let triangle = new OV.Triangle (v0, v1, v2); + if (normals.length === vertices.length) { + let n0 = GetLocalNormalIndex (this, this.currentMesh, normals[0]); + let n1 = GetLocalNormalIndex (this, this.currentMesh, normals[i + 1]); + let n2 = GetLocalNormalIndex (this, this.currentMesh, normals[i + 2]); + if (n0 === null || n1 === null || n2 === null) { + this.SetError (); + this.SetMessage ('Invalid normal index.'); + break; + } + triangle.SetNormals (n0, n1, n2); + } + if (uvs.length === vertices.length) { + let u0 = GetLocalUVIndex (this, this.currentMesh, uvs[0]); + let u1 = GetLocalUVIndex (this, this.currentMesh, uvs[i + 1]); + let u2 = GetLocalUVIndex (this, this.currentMesh, uvs[i + 2]); + if (u0 === null || u1 === null || u2 === null) { + this.SetError (); + this.SetMessage ('Invalid uv index.'); + break; + } + triangle.SetTextureUVs (u0, u1, u2); + } + if (this.currentMaterialIndex !== null) { + triangle.mat = this.currentMaterialIndex; + } + this.currentMesh.AddTriangle (triangle); + } + } }; diff --git a/source/import/importeroff.js b/source/import/importeroff.js index 12f0319..30dbef4 100644 --- a/source/import/importeroff.js +++ b/source/import/importeroff.js @@ -3,13 +3,34 @@ OV.ImporterOff = class extends OV.ImporterBase constructor () { super (); + } + + CanImportExtension (extension) + { + return extension === 'off'; + } + + GetKnownFileFormats () + { + return { + 'off' : OV.FileFormat.Text + }; + } + + GetUpDirection () + { + return OV.Direction.Y; + } + + ClearContent () + { this.model = null; this.mesh = null; this.status = null; } - - ResetState () - { + + ResetContent () + { this.mesh = new OV.Mesh (); this.model.AddMesh (this.mesh); this.status = { @@ -18,46 +39,30 @@ OV.ImporterOff = class extends OV.ImporterBase foundVertex : 0, foundFace : 0 }; - } - - CanImportExtension (extension) - { - return extension === 'off'; - } - - GetKnownFileFormats () - { - return { - 'off' : OV.FileFormat.Text - }; - } - - GetUpDirection () - { - return OV.Direction.Y; } - ImportContent (fileContent) - { + ImportContent (fileContent, onFinish) + { let obj = this; - OV.ReadLines (fileContent, function (line) { - if (!obj.IsError ()) { - obj.ProcessLine (line); - } - }); - } - - ProcessLine (line) - { - if (line[0] === '#') { - return; - } + OV.ReadLines (fileContent, function (line) { + if (!obj.IsError ()) { + obj.ProcessLine (line); + } + }); + onFinish (); + } + + ProcessLine (line) + { + if (line[0] === '#') { + return; + } - let parameters = OV.ParametersFromLine (line, '#'); - if (parameters.length === 0) { - return; - } - + let parameters = OV.ParametersFromLine (line, '#'); + if (parameters.length === 0) { + return; + } + if (parameters[0] === 'OFF') { return; } @@ -99,5 +104,5 @@ OV.ImporterOff = class extends OV.ImporterBase } return; } - } + } }; diff --git a/source/import/importerply.js b/source/import/importerply.js index 763e6ae..4de747c 100644 --- a/source/import/importerply.js +++ b/source/import/importerply.js @@ -89,51 +89,55 @@ OV.ImporterPly = class extends OV.ImporterBase constructor () { super (); - this.model = null; - this.mesh = null; } - - ResetState () - { - this.mesh = new OV.Mesh (); - this.model.AddMesh (this.mesh); - } - - CanImportExtension (extension) - { - return extension === 'ply'; - } + + CanImportExtension (extension) + { + return extension === 'ply'; + } GetKnownFileFormats () - { - return { - 'ply' : OV.FileFormat.Binary - }; - } - + { + return { + 'ply' : OV.FileFormat.Binary + }; + } + GetUpDirection () { return OV.Direction.Y; } + + ClearContent () + { + this.model = null; + this.mesh = null; + } - ImportContent (fileContent) - { + ResetContent () + { + this.mesh = new OV.Mesh (); + this.model.AddMesh (this.mesh); + } + + ImportContent (fileContent, onFinish) + { let headerString = this.GetHeaderContent (fileContent); let header = this.ReadHeader (headerString); - if (!header.Check ()) { + if (header.Check ()) { + if (header.format === 'ascii') { + let contentString = OV.ArrayBufferToUtf8String (fileContent); + contentString = contentString.substr (headerString.length); + this.ReadAsciiContent (header, contentString); + } else if (header.format === 'binary_little_endian' || header.format === 'binary_big_endian') { + this.ReadBinaryContent (header, fileContent, headerString.length); + } + } else { this.SetError (); this.SetMessage ('Invalid header information.'); - return; } - - if (header.format === 'ascii') { - let contentString = OV.ArrayBufferToUtf8String (fileContent); - contentString = contentString.substr (headerString.length); - this.ReadAsciiContent (header, contentString); - } else if (header.format === 'binary_little_endian' || header.format === 'binary_big_endian') { - this.ReadBinaryContent (header, fileContent, headerString.length); - } - } + onFinish (); + } GetHeaderContent (fileContent) { @@ -180,7 +184,7 @@ OV.ImporterPly = class extends OV.ImporterBase header.AddSingleFormat (parameters[1], parameters[2]); } } - }); + }); return header; } @@ -231,7 +235,7 @@ OV.ImporterPly = class extends OV.ImporterBase } return; } - }); + }); } ReadBinaryContent (header, fileContent, headerLength) @@ -279,7 +283,7 @@ OV.ImporterPly = class extends OV.ImporterBase return null; } - let materialName = '#' + IntegerToHex (color[0]) + IntegerToHex (color[1]) + IntegerToHex (color[2]) + IntegerToHex (color[3]); + let materialName = 'Color ' + IntegerToHex (color[0]) + IntegerToHex (color[1]) + IntegerToHex (color[2]) + IntegerToHex (color[3]); let materialIndex = colorToMaterial[materialName]; if (materialIndex === undefined) { let material = new OV.Material (); diff --git a/source/import/importerstl.js b/source/import/importerstl.js index 5886551..0141a71 100644 --- a/source/import/importerstl.js +++ b/source/import/importerstl.js @@ -3,36 +3,40 @@ OV.ImporterStl = class extends OV.ImporterBase constructor () { super (); - this.mesh = null; - this.triangle = null; } - - ResetState () - { - this.mesh = new OV.Mesh (); - this.model.AddMesh (this.mesh); - this.triangle = null; - } - CanImportExtension (extension) - { - return extension === 'stl'; - } + CanImportExtension (extension) + { + return extension === 'stl'; + } - GetKnownFileFormats () - { - return { - 'stl' : OV.FileFormat.Binary - }; - } - + GetKnownFileFormats () + { + return { + 'stl' : OV.FileFormat.Binary + }; + } + GetUpDirection () { return OV.Direction.Z; + } + + ClearContent () + { + this.mesh = null; + this.triangle = null; } - ImportContent (fileContent) - { + ResetContent () + { + this.mesh = new OV.Mesh (); + this.model.AddMesh (this.mesh); + this.triangle = null; + } + + ImportContent (fileContent, onFinish) + { if (this.IsBinaryStlFile (fileContent)) { this.ProcessBinary (fileContent); } else { @@ -44,10 +48,11 @@ OV.ImporterStl = class extends OV.ImporterBase } }); } - } + onFinish (); + } - IsBinaryStlFile (fileContent) - { + IsBinaryStlFile (fileContent) + { let byteLength = fileContent.byteLength; if (byteLength < 84) { return false; @@ -64,17 +69,17 @@ OV.ImporterStl = class extends OV.ImporterBase return true; } - ProcessLine (line) - { - if (line[0] === '#') { - return; - } + ProcessLine (line) + { + if (line[0] === '#') { + return; + } - let parameters = OV.ParametersFromLine (line, '#'); - if (parameters.length === 0) { - return; - } - + let parameters = OV.ParametersFromLine (line, '#'); + if (parameters.length === 0) { + return; + } + let keyword = parameters[0]; if (keyword === 'solid') { if (parameters.length > 1) { @@ -132,7 +137,7 @@ OV.ImporterStl = class extends OV.ImporterBase } ProcessBinary (fileContent) - { + { function ReadVector (reader) { let coord = new OV.Coord3D (); diff --git a/source/model/meshbuffer.js b/source/model/meshbuffer.js index d4f019f..a2d0185 100644 --- a/source/model/meshbuffer.js +++ b/source/model/meshbuffer.js @@ -40,6 +40,16 @@ OV.MeshBuffer = class this.primitives = []; } + PrimitiveCount () + { + return this.primitives.length; + } + + GetPrimitive (index) + { + return this.primitives[index]; + } + GetByteLength (indexTypeSize, numberTypeSize) { let byteLength = 0; @@ -53,7 +63,7 @@ OV.MeshBuffer = class OV.ConvertMeshToMeshBuffer = function (mesh) { - function AddVertexToPrimitiveBuffer (mesh, vertexIndex, normalIndex, uvIndex, primitiveBuffer, primitiveMaps) + function AddVertexToPrimitiveBuffer (mesh, vertexIndex, normalIndex, uvIndex, primitiveBuffer, meshToPrimitiveVertices) { function GetUVOrDefault (mesh, uvIndex, forceUVs) { @@ -106,10 +116,10 @@ OV.ConvertMeshToMeshBuffer = function (mesh) return null; } - let primitiveVertices = primitiveMaps.meshToPrimitiveVertices[vertexIndex]; + let primitiveVertices = meshToPrimitiveVertices[vertexIndex]; if (primitiveVertices === undefined) { let primitiveVertex = AddVertex (mesh, vertexIndex, normalIndex, uvIndex, primitiveBuffer); - primitiveMaps.meshToPrimitiveVertices[vertexIndex] = [primitiveVertex]; + meshToPrimitiveVertices[vertexIndex] = [primitiveVertex]; } else { let existingPrimitiveVertex = FindMatchingPrimitiveVertex (mesh, primitiveVertices, normalIndex, uvIndex); if (existingPrimitiveVertex !== null) { @@ -139,21 +149,19 @@ OV.ConvertMeshToMeshBuffer = function (mesh) }); let primitiveBuffer = null; - let primitiveMaps = null; + let meshToPrimitiveVertices = null; for (let i = 0; i < triangleIndices.length; i++) { let triangleIndex = triangleIndices[i]; let triangle = mesh.GetTriangle (triangleIndex); if (primitiveBuffer === null || primitiveBuffer.material !== triangle.mat) { primitiveBuffer = new OV.MeshPrimitiveBuffer (); primitiveBuffer.material = triangle.mat; - primitiveMaps = { - meshToPrimitiveVertices : {} - }; + meshToPrimitiveVertices = {}; meshBuffer.primitives.push (primitiveBuffer); } - AddVertexToPrimitiveBuffer (mesh, triangle.v0, triangle.n0, triangle.u0, primitiveBuffer, primitiveMaps); - AddVertexToPrimitiveBuffer (mesh, triangle.v1, triangle.n1, triangle.u1, primitiveBuffer, primitiveMaps); - AddVertexToPrimitiveBuffer (mesh, triangle.v2, triangle.n2, triangle.u2, primitiveBuffer, primitiveMaps); + AddVertexToPrimitiveBuffer (mesh, triangle.v0, triangle.n0, triangle.u0, primitiveBuffer, meshToPrimitiveVertices); + AddVertexToPrimitiveBuffer (mesh, triangle.v1, triangle.n1, triangle.u1, primitiveBuffer, meshToPrimitiveVertices); + AddVertexToPrimitiveBuffer (mesh, triangle.v2, triangle.n2, triangle.u2, primitiveBuffer, meshToPrimitiveVertices); } return meshBuffer; diff --git a/source/model/modelentities.js b/source/model/modelentities.js index 69cc7ba..e4b873e 100644 --- a/source/model/modelentities.js +++ b/source/model/modelentities.js @@ -25,6 +25,13 @@ OV.Color = class this.b = b; // 0 .. 255 } + Set (r, g, b) + { + this.r = r; + this.g = g; + this.b = b; + } + Clone () { return new OV.Color (this.r, this.g, this.b); diff --git a/source/model/modelutils.js b/source/model/modelutils.js index 9e6a137..1d9f09a 100644 --- a/source/model/modelutils.js +++ b/source/model/modelutils.js @@ -41,6 +41,16 @@ OV.TransformMesh = function (mesh, transformation) } }; +OV.FlipMeshTrianglesOrientation = function (mesh) +{ + for (let i = 0; i < mesh.TriangleCount (); i++) { + let triangle = mesh.GetTriangle (i); + let tmp = triangle.v1; + triangle.v1 = triangle.v2; + triangle.v2 = tmp; + } +}; + OV.GetMeshBoundingBox = function (mesh) { let min = new OV.Coord3D (Infinity, Infinity, Infinity); diff --git a/source/viewer/domviewer.js b/source/viewer/domviewer.js index 1f3f88d..1b16603 100644 --- a/source/viewer/domviewer.js +++ b/source/viewer/domviewer.js @@ -10,7 +10,6 @@ OV.Init3DViewerElements = function () let width = element.clientWidth; let height = element.clientHeight; - console.log (element.clientHeight); viewer.Resize (width, height); let loader = new OV.ThreeModelLoader (); diff --git a/source/viewer/navigation.js b/source/viewer/navigation.js index 5e0167f..1c23886 100644 --- a/source/viewer/navigation.js +++ b/source/viewer/navigation.js @@ -308,6 +308,10 @@ OV.Navigation = class } } + if (newCamera === null) { + return; + } + if (stepCount === 0) { this.SetCamera (newCamera); return; diff --git a/source/viewer/viewer.js b/source/viewer/viewer.js index e5acfe0..abd2798 100644 --- a/source/viewer/viewer.js +++ b/source/viewer/viewer.js @@ -43,7 +43,10 @@ OV.UpVector = class let newEye = oldCamera.center.Clone ().Offset (defaultDir, distance); let newCamera = oldCamera.Clone (); - if (this.direction === OV.Direction.Y) { + if (this.direction === OV.Direction.X) { + newCamera.up = new OV.Coord3D (1.0, 0.0, 0.0); + newCamera.eye = newEye; + } if (this.direction === OV.Direction.Y) { newCamera.up = new OV.Coord3D (0.0, 1.0, 0.0); newCamera.eye = newEye; } else if (this.direction === OV.Direction.Z) { @@ -71,6 +74,64 @@ OV.UpVector = class } }; +OV.ViewerGeometry = class +{ + constructor (scene) + { + this.scene = scene; + this.modelMeshes = []; + } + + AddModelMeshes (meshes) + { + for (let i = 0; i < meshes.length; i++) { + let mesh = meshes[i]; + this.modelMeshes.push (mesh); + this.scene.add (mesh); + } + } + + GetModelMeshes () + { + return this.modelMeshes; + } + + ClearModelMeshes () + { + for (let i = 0; i < this.modelMeshes.length; i++) { + let mesh = this.modelMeshes[i]; + mesh.geometry.dispose (); + this.scene.remove (mesh); + } + this.modelMeshes = []; + } + + EnumerateModelMeshes (enumerator) + { + for (let i = 0; i < this.modelMeshes.length; i++) { + let mesh = this.modelMeshes[i]; + enumerator (mesh); + } + } + + GetModelMeshUnderMouse (mouseCoords, camera, width, height) + { + let raycaster = new THREE.Raycaster (); + let mousePos = new THREE.Vector2 (); + mousePos.x = (mouseCoords.x / width) * 2 - 1; + mousePos.y = -(mouseCoords.y / height) * 2 + 1; + raycaster.setFromCamera (mousePos, camera); + let iSectObjects = raycaster.intersectObjects (this.modelMeshes); + for (let i = 0; i < iSectObjects.length; i++) { + let iSectObject = iSectObjects[i]; + if (iSectObject.object.type === 'Mesh' && iSectObject.object.visible) { + return iSectObject.object; + } + } + return null; + } +}; + OV.Viewer = class { constructor () @@ -78,6 +139,7 @@ OV.Viewer = class this.canvas = null; this.renderer = null; this.scene = null; + this.geometry = null; this.camera = null; this.light = null; this.navigation = null; @@ -101,10 +163,14 @@ OV.Viewer = class }; this.renderer = new THREE.WebGLRenderer (parameters); + if (window.devicePixelRatio) { + this.renderer.setPixelRatio (window.devicePixelRatio); + } this.renderer.setClearColor ('#ffffff', 1.0); this.renderer.setSize (this.canvas.width, this.canvas.height); this.scene = new THREE.Scene (); + this.geometry = new OV.ViewerGeometry (this.scene); this.InitCamera (); this.InitLights (); @@ -136,6 +202,9 @@ OV.Viewer = class ResizeRenderer (width, height) { + if (window.devicePixelRatio) { + this.renderer.setPixelRatio (window.devicePixelRatio); + } this.camera.aspect = width / height; this.camera.updateProjectionMatrix (); this.renderer.setSize (width, height); @@ -227,22 +296,19 @@ OV.Viewer = class AddMeshes (meshes) { - for (let i = 0; i < meshes.length; i++) { - let mesh = meshes[i]; - this.scene.add (mesh); - } + this.geometry.AddModelMeshes (meshes); this.Render (); } Clear () { - this.ClearMeshes (); + this.geometry.ClearModelMeshes (); this.Render (); } SetMeshesVisibility (isVisible) { - this.EnumerateMeshes (function (mesh) { + this.geometry.EnumerateModelMeshes (function (mesh) { let visible = isVisible (mesh.userData); if (mesh.visible !== visible) { mesh.visible = visible; @@ -262,7 +328,7 @@ OV.Viewer = class return highlightMaterials; } - this.EnumerateMeshes (function (mesh) { + this.geometry.EnumerateModelMeshes (function (mesh) { let highlighted = isHighlighted (mesh.userData); if (highlighted) { if (mesh.userData.threeMaterials === null) { @@ -279,28 +345,20 @@ OV.Viewer = class this.Render (); } - GetMeshUnderMouse (mouseCoords) + GetMeshUserDataUnderMouse (mouseCoords) { - let raycaster = new THREE.Raycaster (); - let mousePos = new THREE.Vector2 (); - mousePos.x = (mouseCoords.x / this.canvas.width) * 2 - 1; - mousePos.y = -(mouseCoords.y / this.canvas.height) * 2 + 1; - raycaster.setFromCamera (mousePos, this.camera); - let iSectObjects = raycaster.intersectObjects (this.scene.children); - for (let i = 0; i < iSectObjects.length; i++) { - let iSectObject = iSectObjects[i]; - if (iSectObject.object.type === 'Mesh' && iSectObject.object.visible) { - return iSectObject.object.userData; - } + let mesh = this.geometry.GetModelMeshUnderMouse (mouseCoords, this.camera, this.canvas.width, this.canvas.height); + if (mesh === null) { + return null; } - return null; + return mesh.userData; } GetBoundingBox (needToProcess) { let hasMesh = false; let boundingBox = new THREE.Box3 (); - this.EnumerateMeshes (function (mesh) { + this.geometry.EnumerateModelMeshes (function (mesh) { if (needToProcess (mesh.userData)) { boundingBox.union (new THREE.Box3 ().setFromObject (mesh)); hasMesh = true; @@ -327,31 +385,11 @@ OV.Viewer = class EnumerateMeshesUserData (enumerator) { - this.EnumerateMeshes (function (mesh) { + this.geometry.EnumerateModelMeshes (function (mesh) { enumerator (mesh.userData); }); } - EnumerateMeshes (enumerator) - { - this.scene.traverse (function (object) { - if (object.isMesh) { - enumerator (object); - } - }); - } - - ClearMeshes () - { - for (let i = this.scene.children.length - 1; i >= 0; i--) { - let object = this.scene.children[i]; - if (object.isMesh) { - object.geometry.dispose (); - this.scene.remove (object); - } - } - } - InitCamera () { this.camera = new THREE.PerspectiveCamera (45.0, this.canvas.width / this.canvas.height, 0.1, 1000.0); @@ -378,22 +416,29 @@ OV.Viewer = class this.scene.add (this.light); } + GetImageSize () + { + let originalSize = new THREE.Vector2 (); + this.renderer.getSize (originalSize); + return { + width : parseInt (originalSize.x, 10), + height : parseInt (originalSize.y, 10) + }; + } + GetImageAsDataUrl (width, height) { - let originalSize = null; - if (width && height) { - originalSize = new THREE.Vector2 (); - this.renderer.getSize (originalSize); - this.ResizeRenderer (width, height); + let originalSize = this.GetImageSize (); + let renderWidth = width; + let renderHeight = height; + if (window.devicePixelRatio) { + renderWidth /= window.devicePixelRatio; + renderHeight /= window.devicePixelRatio; } + this.ResizeRenderer (renderWidth, renderHeight); this.Render (); let url = this.renderer.domElement.toDataURL (); - if (originalSize !== null) { - this.ResizeRenderer ( - parseInt (originalSize.x, 10), - parseInt (originalSize.y, 10) - ); - } + this.ResizeRenderer (originalSize.width, originalSize.height); return url; } }; diff --git a/test/tests/exporter_test.js b/test/tests/exporter_test.js index 10b4241..96350e7 100644 --- a/test/tests/exporter_test.js +++ b/test/tests/exporter_test.js @@ -62,308 +62,340 @@ function CreateTestModel () return model; } -describe ('Exporter', function () { - it ('Obj Export', function () { - let model = CreateTestModel (); - let exporter = new OV.Exporter (); - - let result = exporter.Export (model, OV.FileFormat.Text, 'obj'); - assert.strictEqual (result.length, 5); - - let mtlFile = result[0]; - assert.strictEqual (mtlFile.GetName (), 'model.mtl'); - assert.strictEqual (mtlFile.GetContent (), - [ - '# exported by https://3dviewer.net', - 'newmtl TestMaterial1', - 'Ka 0 0 0', - 'Kd 1 0 0', - 'Ks 0.2 0.2 0.2', - 'Ns 0', - 'd 1', - 'map_Kd texture1.png', - 'map_Ks texture2.png', - 'bump texture3.png', - 'newmtl TestMaterial2', - 'Ka 0 0 0', - 'Kd 0 1 0', - 'Ks 0.2 0.2 0.2', - 'Ns 0', - 'd 1', - '' - ].join ('\n')); - let objFile = result[1]; - assert.strictEqual (objFile.GetName (), 'model.obj'); - assert.strictEqual (objFile.GetContent (), - [ - '# exported by https://3dviewer.net', - 'mtllib model.mtl', - 'g TestMesh1', - 'v 0 0 1', - 'v 1 0 1', - 'v 0 1 1', - 'vn 0 0 1', - 'usemtl TestMaterial1', - 'f 1//1 2//1 3//1', - 'g TestMesh2', - 'v 0 0 0', - 'v 1 0 0', - 'v 0 1 0', - 'v -1 0 0', - 'v 0 0 1', - 'vn 0 0 1', - 'vn 0 0 1', - 'vn -1 0 0', - 'f 4//2 5//2 6//2', - 'usemtl TestMaterial2', - 'f 4//3 6//3 7//3', - 'f 4//4 8//4 6//4', - '' - ].join ('\n')); - - let textureFile1 = result[2]; - assert.strictEqual (textureFile1.GetName (), 'texture1.png'); - assert.strictEqual (textureFile1.GetContent ().byteLength, 1); - - let textureFile2 = result[3]; - assert.strictEqual (textureFile2.GetName (), 'texture2.png'); - assert.strictEqual (textureFile2.GetContent ().byteLength, 2); - - let textureFile3 = result[4]; - assert.strictEqual (textureFile3.GetName (), 'texture3.png'); - assert.strictEqual (textureFile3.GetContent ().byteLength, 3); - }); - - it ('Stl Export', function () { - let model = CreateTestModel (); - let exporter = new OV.Exporter (); - - let result = exporter.Export (model, OV.FileFormat.Text, 'stl'); - assert.strictEqual (result.length, 1); - - let stlFile = result[0]; - assert.strictEqual (stlFile.GetName (), 'model.stl'); - assert.strictEqual (stlFile.GetContent (), - [ - 'solid Model', - 'facet normal 0 0 1', - ' outer loop', - ' vertex 0 0 1', - ' vertex 1 0 1', - ' vertex 0 1 1', - ' endloop', - 'endfacet', - 'facet normal 0 0 1', - ' outer loop', - ' vertex 0 0 0', - ' vertex 1 0 0', - ' vertex 0 1 0', - ' endloop', - 'endfacet', - 'facet normal 0 0 1', - ' outer loop', - ' vertex 0 0 0', - ' vertex 0 1 0', - ' vertex -1 0 0', - ' endloop', - 'endfacet', - 'facet normal -1 0 0', - ' outer loop', - ' vertex 0 0 0', - ' vertex 0 0 1', - ' vertex 0 1 0', - ' endloop', - 'endfacet', - 'endsolid Model', - '' - ].join ('\n')); - }); - - it ('Stl Binary Export', function () { - let model = CreateTestModel (); - let exporter = new OV.Exporter (); - - let result = exporter.Export (model, OV.FileFormat.Binary, 'stl'); - assert.strictEqual (result.length, 1); - - let stlFile = result[0]; - assert.strictEqual (stlFile.GetName (), 'model.stl'); - assert.strictEqual (stlFile.GetContent ().byteLength, 284); - - let contentBuffer = stlFile.GetContent (); - let importer = new OV.ImporterStl (); - importer.Import (contentBuffer, 'stl', { - getDefaultMaterial () { - return new OV.Material (); - } - }); - let importedModel = importer.GetModel (); - assert.strictEqual (importedModel.VertexCount (), 12); - assert.strictEqual (importedModel.TriangleCount (), 4); - }); - - it ('Off Export', function () { - let model = CreateTestModel (); - let exporter = new OV.Exporter (); - - let result = exporter.Export (model, OV.FileFormat.Text, 'off'); - assert.strictEqual (result.length, 1); - - let offFile = result[0]; - assert.strictEqual (offFile.GetName (), 'model.off'); - assert.strictEqual (offFile.GetContent (), - [ - 'OFF', - '8 4 0', - '0 0 1', - '1 0 1', - '0 1 1', - '0 0 0', - '1 0 0', - '0 1 0', - '-1 0 0', - '0 0 1', - '3 0 1 2', - '3 3 4 5', - '3 3 5 6', - '3 3 7 5', - '' - ].join ('\n')); - }); - - it ('Ply Export', function () { - let model = CreateTestModel (); - let exporter = new OV.Exporter (); - - let result = exporter.Export (model, OV.FileFormat.Text, 'ply'); - assert.strictEqual (result.length, 1); - - let plyFile = result[0]; - assert.strictEqual (plyFile.GetName (), 'model.ply'); - assert.strictEqual (plyFile.GetContent (), - [ - 'ply', - 'format ascii 1.0', - 'element vertex 8', - 'property float x', - 'property float y', - 'property float z', - 'element face 4', - 'property list uchar int vertex_index', - 'end_header', - '0 0 1', - '1 0 1', - '0 1 1', - '0 0 0', - '1 0 0', - '0 1 0', - '-1 0 0', - '0 0 1', - '3 0 1 2', - '3 3 4 5', - '3 3 5 6', - '3 3 7 5', - '' - ].join ('\n')); - }); - - it ('Ply Binary Export', function () { - let model = CreateTestModel (); - let exporter = new OV.Exporter (); - - let result = exporter.Export (model, OV.FileFormat.Binary, 'ply'); - assert.strictEqual (result.length, 1); - - let plyFile = result[0]; - assert.strictEqual (plyFile.GetName (), 'model.ply'); - assert.strictEqual (plyFile.GetContent ().byteLength, 315); - - let contentBuffer = plyFile.GetContent (); - let importer = new OV.ImporterPly (); - importer.Import (contentBuffer, 'ply', { - getDefaultMaterial () { - return new OV.Material (); - } - }); - let importedModel = importer.GetModel (); - assert.strictEqual (importedModel.VertexCount (), 8); - assert.strictEqual (importedModel.TriangleCount (), 4); - }); - - it ('Gltf Ascii Export', function () { - let model = CreateTestModel (); - let exporter = new OV.Exporter (); - - let result = exporter.Export (model, OV.FileFormat.Text, 'gltf'); - assert.strictEqual (result.length, 3); - - let gltfFile = result[0]; - let binFile = result[1]; - let textureFile = result[2]; - assert.strictEqual (gltfFile.GetName (), 'model.gltf'); - assert.strictEqual (binFile.GetName (), 'model.bin'); - - assert.strictEqual (textureFile.GetName (), 'texture1.png'); - assert.strictEqual (textureFile.GetContent ().byteLength, 1); - - let contentBuffer = gltfFile.GetContent (); - let importer = new OV.ImporterGltf (); - importer.Import (contentBuffer, 'gltf', { - getDefaultMaterial () { - return new OV.Material (); - }, - getFileBuffer (filePath) { - if (filePath == 'model.bin') { - return binFile.GetContent (); - } - return null; - }, - getTextureBuffer (filePath) { - return null; - } - }); - - let importedModel = importer.GetModel (); - assert (OV.CheckModel (importedModel)); - assert.strictEqual (importedModel.MaterialCount (), 2); - assert.strictEqual (importedModel.MeshCount (), 2); - assert.strictEqual (importedModel.GetMesh (0).GetName (), 'TestMesh1'); - assert.strictEqual (importedModel.GetMesh (1).GetName (), 'TestMesh2'); - assert.strictEqual (importedModel.VertexCount (), 12); - assert.strictEqual (importedModel.TriangleCount (), 4); - }); - - it ('Gltf Binary Export', function () { - let model = CreateTestModel (); +function Export (model, format, extension, onReady) +{ let exporter = new OV.Exporter (); - - let result = exporter.Export (model, OV.FileFormat.Binary, 'glb'); - assert.strictEqual (result.length, 1); - - let glbFile = result[0]; - assert.strictEqual (glbFile.GetName (), 'model.glb'); - - let contentBuffer = glbFile.GetContent (); - let importer = new OV.ImporterGltf (); - importer.Import (contentBuffer, 'glb', { - getDefaultMaterial () { - return new OV.Material (); - }, - getFileBuffer (filePath) { - return null; - }, - getTextureBuffer (filePath) { - return null; + exporter.Export (model, format, extension, { + onSuccess : function (files) { + onReady (files); } }); +} - let importedModel = importer.GetModel (); - assert (OV.CheckModel (importedModel)); - assert.strictEqual (importedModel.MaterialCount (), 2); - assert.strictEqual (importedModel.MeshCount (), 2); - assert.strictEqual (importedModel.GetMesh (0).GetName (), 'TestMesh1'); - assert.strictEqual (importedModel.GetMesh (1).GetName (), 'TestMesh2'); - assert.strictEqual (importedModel.VertexCount (), 12); - assert.strictEqual (importedModel.TriangleCount (), 4); - }); +describe ('Exporter', function () { + it ('Exporter Error', function (done) { + let model = CreateTestModel (); + let exporter = new OV.Exporter (); + exporter.Export (model, OV.FileFormat.Text, 'ext', { + onError : function () { + done (); + } + }); + }); + + it ('Obj Export', function (done) { + let model = CreateTestModel (); + Export (model, OV.FileFormat.Text, 'obj', function (result) { + assert.strictEqual (result.length, 5); + + let mtlFile = result[0]; + assert.strictEqual (mtlFile.GetName (), 'model.mtl'); + assert.strictEqual (mtlFile.GetContent (), + [ + '# exported by https://3dviewer.net', + 'newmtl TestMaterial1', + 'Ka 0 0 0', + 'Kd 1 0 0', + 'Ks 0.2 0.2 0.2', + 'Ns 0', + 'd 1', + 'map_Kd texture1.png', + 'map_Ks texture2.png', + 'bump texture3.png', + 'newmtl TestMaterial2', + 'Ka 0 0 0', + 'Kd 0 1 0', + 'Ks 0.2 0.2 0.2', + 'Ns 0', + 'd 1', + '' + ].join ('\n')); + let objFile = result[1]; + assert.strictEqual (objFile.GetName (), 'model.obj'); + assert.strictEqual (objFile.GetContent (), + [ + '# exported by https://3dviewer.net', + 'mtllib model.mtl', + 'g TestMesh1', + 'v 0 0 1', + 'v 1 0 1', + 'v 0 1 1', + 'vn 0 0 1', + 'usemtl TestMaterial1', + 'f 1//1 2//1 3//1', + 'g TestMesh2', + 'v 0 0 0', + 'v 1 0 0', + 'v 0 1 0', + 'v -1 0 0', + 'v 0 0 1', + 'vn 0 0 1', + 'vn 0 0 1', + 'vn -1 0 0', + 'f 4//2 5//2 6//2', + 'usemtl TestMaterial2', + 'f 4//3 6//3 7//3', + 'f 4//4 8//4 6//4', + '' + ].join ('\n')); + + let textureFile1 = result[2]; + assert.strictEqual (textureFile1.GetName (), 'texture1.png'); + assert.strictEqual (textureFile1.GetContent ().byteLength, 1); + + let textureFile2 = result[3]; + assert.strictEqual (textureFile2.GetName (), 'texture2.png'); + assert.strictEqual (textureFile2.GetContent ().byteLength, 2); + + let textureFile3 = result[4]; + assert.strictEqual (textureFile3.GetName (), 'texture3.png'); + assert.strictEqual (textureFile3.GetContent ().byteLength, 3); + + done (); + }); + }); + + it ('Stl Export', function (done) { + let model = CreateTestModel (); + Export (model, OV.FileFormat.Text, 'stl', function (result) { + assert.strictEqual (result.length, 1); + + let stlFile = result[0]; + assert.strictEqual (stlFile.GetName (), 'model.stl'); + assert.strictEqual (stlFile.GetContent (), + [ + 'solid Model', + 'facet normal 0 0 1', + ' outer loop', + ' vertex 0 0 1', + ' vertex 1 0 1', + ' vertex 0 1 1', + ' endloop', + 'endfacet', + 'facet normal 0 0 1', + ' outer loop', + ' vertex 0 0 0', + ' vertex 1 0 0', + ' vertex 0 1 0', + ' endloop', + 'endfacet', + 'facet normal 0 0 1', + ' outer loop', + ' vertex 0 0 0', + ' vertex 0 1 0', + ' vertex -1 0 0', + ' endloop', + 'endfacet', + 'facet normal -1 0 0', + ' outer loop', + ' vertex 0 0 0', + ' vertex 0 0 1', + ' vertex 0 1 0', + ' endloop', + 'endfacet', + 'endsolid Model', + '' + ].join ('\n')); + + done (); + }); + }); + + it ('Stl Binary Export', function (done) { + let model = CreateTestModel (); + Export (model, OV.FileFormat.Binary, 'stl', function (result) { + assert.strictEqual (result.length, 1); + + let stlFile = result[0]; + assert.strictEqual (stlFile.GetName (), 'model.stl'); + assert.strictEqual (stlFile.GetContent ().byteLength, 284); + + let contentBuffer = stlFile.GetContent (); + let importer = new OV.ImporterStl (); + importer.Import (contentBuffer, 'stl', { + getDefaultMaterial () { + return new OV.Material (); + }, + onSuccess () { + let importedModel = importer.GetModel (); + assert.strictEqual (importedModel.VertexCount (), 12); + assert.strictEqual (importedModel.TriangleCount (), 4); + done (); + } + }); + + done (); + }); + }); + + it ('Off Export', function (done) { + let model = CreateTestModel (); + Export (model, OV.FileFormat.Text, 'off', function (result) { + assert.strictEqual (result.length, 1); + + let offFile = result[0]; + assert.strictEqual (offFile.GetName (), 'model.off'); + assert.strictEqual (offFile.GetContent (), + [ + 'OFF', + '8 4 0', + '0 0 1', + '1 0 1', + '0 1 1', + '0 0 0', + '1 0 0', + '0 1 0', + '-1 0 0', + '0 0 1', + '3 0 1 2', + '3 3 4 5', + '3 3 5 6', + '3 3 7 5', + '' + ].join ('\n')); + + done (); + }); + }); + + it ('Ply Export', function (done) { + let model = CreateTestModel (); + Export (model, OV.FileFormat.Text, 'ply', function (result) { + assert.strictEqual (result.length, 1); + + let plyFile = result[0]; + assert.strictEqual (plyFile.GetName (), 'model.ply'); + assert.strictEqual (plyFile.GetContent (), + [ + 'ply', + 'format ascii 1.0', + 'element vertex 8', + 'property float x', + 'property float y', + 'property float z', + 'element face 4', + 'property list uchar int vertex_index', + 'end_header', + '0 0 1', + '1 0 1', + '0 1 1', + '0 0 0', + '1 0 0', + '0 1 0', + '-1 0 0', + '0 0 1', + '3 0 1 2', + '3 3 4 5', + '3 3 5 6', + '3 3 7 5', + '' + ].join ('\n')); + + done (); + }); + }); + + it ('Ply Binary Export', function (done) { + let model = CreateTestModel (); + Export (model, OV.FileFormat.Binary, 'ply', function (result) { + assert.strictEqual (result.length, 1); + + let plyFile = result[0]; + assert.strictEqual (plyFile.GetName (), 'model.ply'); + assert.strictEqual (plyFile.GetContent ().byteLength, 315); + + let contentBuffer = plyFile.GetContent (); + let importer = new OV.ImporterPly (); + importer.Import (contentBuffer, 'ply', { + getDefaultMaterial () { + return new OV.Material (); + }, + onSuccess () { + let importedModel = importer.GetModel (); + assert.strictEqual (importedModel.VertexCount (), 8); + assert.strictEqual (importedModel.TriangleCount (), 4); + done (); + } + }); + }); + }); + + it ('Gltf Ascii Export', function (done) { + let model = CreateTestModel (); + Export (model, OV.FileFormat.Text, 'gltf', function (result) { + assert.strictEqual (result.length, 3); + + let gltfFile = result[0]; + let binFile = result[1]; + let textureFile = result[2]; + assert.strictEqual (gltfFile.GetName (), 'model.gltf'); + assert.strictEqual (binFile.GetName (), 'model.bin'); + + assert.strictEqual (textureFile.GetName (), 'texture1.png'); + assert.strictEqual (textureFile.GetContent ().byteLength, 1); + + let contentBuffer = gltfFile.GetContent (); + let importer = new OV.ImporterGltf (); + importer.Import (contentBuffer, 'gltf', { + getDefaultMaterial () { + return new OV.Material (); + }, + getFileBuffer (filePath) { + if (filePath == 'model.bin') { + return binFile.GetContent (); + } + return null; + }, + getTextureBuffer (filePath) { + return null; + }, + onSuccess () { + let importedModel = importer.GetModel (); + assert (OV.CheckModel (importedModel)); + assert.strictEqual (importedModel.MaterialCount (), 2); + assert.strictEqual (importedModel.MeshCount (), 2); + assert.strictEqual (importedModel.GetMesh (0).GetName (), 'TestMesh1'); + assert.strictEqual (importedModel.GetMesh (1).GetName (), 'TestMesh2'); + assert.strictEqual (importedModel.VertexCount (), 12); + assert.strictEqual (importedModel.TriangleCount (), 4); + done (); + } + }); + }); + }); + + it ('Gltf Binary Export', function (done) { + let model = CreateTestModel (); + Export (model, OV.FileFormat.Binary, 'glb', function (result) { + assert.strictEqual (result.length, 1); + + let glbFile = result[0]; + assert.strictEqual (glbFile.GetName (), 'model.glb'); + + let contentBuffer = glbFile.GetContent (); + let importer = new OV.ImporterGltf (); + importer.Import (contentBuffer, 'glb', { + getDefaultMaterial () { + return new OV.Material (); + }, + getFileBuffer (filePath) { + return null; + }, + getTextureBuffer (filePath) { + return null; + }, + onSuccess () { + let importedModel = importer.GetModel (); + assert (OV.CheckModel (importedModel)); + assert.strictEqual (importedModel.MaterialCount (), 2); + assert.strictEqual (importedModel.MeshCount (), 2); + assert.strictEqual (importedModel.GetMesh (0).GetName (), 'TestMesh1'); + assert.strictEqual (importedModel.GetMesh (1).GetName (), 'TestMesh2'); + assert.strictEqual (importedModel.VertexCount (), 12); + assert.strictEqual (importedModel.TriangleCount (), 4); + done (); + } + }); + }); + }); }); diff --git a/test/tests/importer3ds_test.js b/test/tests/importer3ds_test.js index 365993d..8d1f5fe 100644 --- a/test/tests/importer3ds_test.js +++ b/test/tests/importer3ds_test.js @@ -3,159 +3,167 @@ var testFiles = require ('../utils/testfiles.js'); var testUtils = require ('../utils/testutils.js'); describe ('3ds Importer', function() { - it ('cube_with_materials.obj', function () { - var model = testFiles.Import3dsFile ('cube_with_materials.3ds'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : 'tex' }, - { name : 'red' }, - { name : 'green' }, - { name : 'blue' }, - { name : 'white' } - ], - meshes : [ - { - name : 'cube', - vertexCount : 8, - normalCount : 12, - uvCount : 8, - triangleCount : 12, - boundingBox : { - min : [0, 0, 0], - max : [1, 1, 1] + it ('cube_with_materials.3ds', function (done) { + testFiles.Import3dsFile ('cube_with_materials.3ds', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : 'tex' }, + { name : 'red' }, + { name : 'green' }, + { name : 'blue' }, + { name : 'white' } + ], + meshes : [ + { + name : 'cube', + vertexCount : 8, + normalCount : 12, + uvCount : 8, + triangleCount : 12, + boundingBox : { + min : [0, 0, 0], + max : [1, 1, 1] + } } - } - ] + ] + }); + done (); }); }); - it ('cube_with_texture_transformations.3ds', function () { - var model = testFiles.Import3dsFile ('cube_with_texture_transformations.3ds'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : 'tex' }, - { name : 'red' }, - { name : 'green' }, - { name : 'blue' }, - { name : 'white' } - ], - meshes : [ - { - name : 'cube', - vertexCount : 8, - normalCount : 12, - uvCount : 8, - triangleCount : 12, - boundingBox : { - min : [0, 0, 0], - max : [1, 1, 1] + it ('cube_with_texture_transformations.3ds', function (done) { + testFiles.Import3dsFile ('cube_with_texture_transformations.3ds', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : 'tex' }, + { name : 'red' }, + { name : 'green' }, + { name : 'blue' }, + { name : 'white' } + ], + meshes : [ + { + name : 'cube', + vertexCount : 8, + normalCount : 12, + uvCount : 8, + triangleCount : 12, + boundingBox : { + min : [0, 0, 0], + max : [1, 1, 1] + } } - } - ] + ] + }); + done (); }); }); - it ('cube_two_instances.3ds', function () { - var model = testFiles.Import3dsFile ('cube_two_instances.3ds'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : 'tex' }, - { name : 'red' }, - { name : 'green' }, - { name : 'blue' }, - { name : 'white' } - ], - meshes : [ - { - name : 'cube', - vertexCount : 8, - normalCount : 12, - uvCount : 8, - triangleCount : 12, - boundingBox : { - min : [0, 0, 0], - max : [1, 1, 1] - } - }, - { - name : 'cube', - vertexCount : 8, - normalCount : 12, - uvCount : 8, - triangleCount : 12, - boundingBox : { - min : [2, 0, 0], - max : [3, 1, 1] - } - } - ] + it ('cube_two_instances.3ds', function (done) { + testFiles.Import3dsFile ('cube_two_instances.3ds', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : 'tex' }, + { name : 'red' }, + { name : 'green' }, + { name : 'blue' }, + { name : 'white' } + ], + meshes : [ + { + name : 'cube', + vertexCount : 8, + normalCount : 12, + uvCount : 8, + triangleCount : 12, + boundingBox : { + min : [0, 0, 0], + max : [1, 1, 1] + } + }, + { + name : 'cube', + vertexCount : 8, + normalCount : 12, + uvCount : 8, + triangleCount : 12, + boundingBox : { + min : [2, 0, 0], + max : [3, 1, 1] + } + } + ] + }); + done (); }); }); - it ('cube_four_instances.3ds', function () { - var model = testFiles.Import3dsFile ('cube_four_instances.3ds'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : 'tex' }, - { name : 'red' }, - { name : 'green' }, - { name : 'blue' }, - { name : 'white' } - ], - meshes : [ - { - name : 'cube', - vertexCount : 8, - normalCount : 12, - uvCount : 8, - triangleCount : 12, - boundingBox : { - min : [0, 0, 0], - max : [1, 1, 1] - } - }, - { - name : 'cube', - vertexCount : 8, - normalCount : 12, - uvCount : 8, - triangleCount : 12, - boundingBox : { - min : [2, 0, 0], - max : [3, 1, 1] - } - }, - { - name : 'cube', - vertexCount : 8, - normalCount : 12, - uvCount : 8, - triangleCount : 12, - boundingBox : { - min : [2, 2, 0], - max : [3, 3, 1] - } - }, - { - name : 'cube', - vertexCount : 8, - normalCount : 12, - uvCount : 8, - triangleCount : 12, - boundingBox : { - min : [0, 2, 0], - max : [1, 3, 1] - } - } - ] + it ('cube_four_instances.3ds', function (done) { + testFiles.Import3dsFile ('cube_four_instances.3ds', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : 'tex' }, + { name : 'red' }, + { name : 'green' }, + { name : 'blue' }, + { name : 'white' } + ], + meshes : [ + { + name : 'cube', + vertexCount : 8, + normalCount : 12, + uvCount : 8, + triangleCount : 12, + boundingBox : { + min : [0, 0, 0], + max : [1, 1, 1] + } + }, + { + name : 'cube', + vertexCount : 8, + normalCount : 12, + uvCount : 8, + triangleCount : 12, + boundingBox : { + min : [2, 0, 0], + max : [3, 1, 1] + } + }, + { + name : 'cube', + vertexCount : 8, + normalCount : 12, + uvCount : 8, + triangleCount : 12, + boundingBox : { + min : [2, 2, 0], + max : [3, 3, 1] + } + }, + { + name : 'cube', + vertexCount : 8, + normalCount : 12, + uvCount : 8, + triangleCount : 12, + boundingBox : { + min : [0, 2, 0], + max : [1, 3, 1] + } + } + ] + }); + done (); }); }); }); diff --git a/test/tests/importer_test.js b/test/tests/importer_test.js index b7b9cf5..46c6c39 100644 --- a/test/tests/importer_test.js +++ b/test/tests/importer_test.js @@ -6,10 +6,10 @@ function ImportFilesWithImporter (importer, files, callbacks) importer.LoadFilesFromFileObjects (files, function () { let settings = new OV.ImportSettings (); importer.Import (settings, { - success : function (importResult) { + onSuccess : function (importResult) { callbacks.success (importer, importResult); }, - error : function (importError) { + onError : function (importError) { callbacks.error (importer, importError); } }); @@ -23,7 +23,7 @@ function ImportFiles (files, callbacks) } describe ('Importer Test', function () { - it ('Empty File List', function () { + it ('Empty File List', function (done) { let files = []; ImportFiles (files, { success : function (importer, importResult) { @@ -31,11 +31,12 @@ describe ('Importer Test', function () { }, error : function (importer, importError) { assert.strictEqual (importError.code, OV.ImportErrorCode.NoImportableFile); + done (); } }); }); - it ('Not existing file', function () { + it ('Not existing file', function (done) { let files = [ new FileObject ('obj', 'missing.obj') ]; @@ -45,11 +46,12 @@ describe ('Importer Test', function () { }, error : function (importer, importError) { assert.strictEqual (importError.code, OV.ImportErrorCode.NoImportableFile); + done (); } }); }); - it ('Not imprtable file', function () { + it ('Not imprtable file', function (done) { let files = [ new FileObject ('', 'wrong.ext') ]; @@ -59,11 +61,12 @@ describe ('Importer Test', function () { }, error : function (importer, importError) { assert.strictEqual (importError.code, OV.ImportErrorCode.NoImportableFile); + done (); } }); }); - it ('Wrong file', function () { + it ('Wrong file', function (done) { let files = [ new FileObject ('3ds', 'wrong.3ds') ]; @@ -73,11 +76,12 @@ describe ('Importer Test', function () { }, error : function (importer, importError) { assert.strictEqual (importError.code, OV.ImportErrorCode.ImportFailed); + done (); } }); }); - it ('Single file', function () { + it ('Single file', function (done) { let files = [ new FileObject ('obj', 'single_triangle.obj') ]; @@ -86,6 +90,7 @@ describe ('Importer Test', function () { assert (!OV.IsModelEmpty (importResult.model)); assert.deepStrictEqual (importResult.usedFiles, ['single_triangle.obj']); assert.deepStrictEqual (importResult.missingFiles, []); + done (); }, error : function (importer, importError) { assert.fail (); @@ -93,7 +98,7 @@ describe ('Importer Test', function () { }); }); - it ('Multiple files', function () { + it ('Multiple files', function (done) { let files = [ new FileObject ('obj', 'cube_with_materials.obj'), new FileObject ('obj', 'cube_with_materials.mtl'), @@ -105,7 +110,8 @@ describe ('Importer Test', function () { success : function (importer, importResult) { assert (!OV.IsModelEmpty (importResult.model)); assert.deepStrictEqual (importResult.usedFiles, ['cube_with_materials.obj', 'cube_with_materials.mtl', 'cube_texture.png']); - assert.deepStrictEqual (importResult.missingFiles, []); + assert.deepStrictEqual (importResult.missingFiles, []); + done (); }, error : function (importer, importError) { assert.fail (); @@ -113,7 +119,7 @@ describe ('Importer Test', function () { }); }); - it ('Missing files', function () { + it ('Missing files', function (done) { let files = []; files.push (new FileObject ('obj', 'cube_with_materials.obj')); ImportFiles (files, { @@ -121,36 +127,38 @@ describe ('Importer Test', function () { assert (!OV.IsModelEmpty (importResult.model)); assert.deepStrictEqual (importResult.usedFiles, ['cube_with_materials.obj']); assert.deepStrictEqual (importResult.missingFiles, ['cube_with_materials.mtl']); + files.push (new FileObject ('obj', 'cube_with_materials.mtl')); + ImportFiles (files, { + success : function (importer, importResult) { + assert (!OV.IsModelEmpty (importResult.model)); + assert.deepStrictEqual (importResult.usedFiles, ['cube_with_materials.obj', 'cube_with_materials.mtl']); + assert.deepStrictEqual (importResult.missingFiles, ['cube_texture.png']); + files.push (new FileObject ('obj', 'cube_texture.png')); + ImportFiles (files, { + success : function (importer, importResult) { + assert (!OV.IsModelEmpty (importResult.model)); + assert.deepStrictEqual (importResult.usedFiles, ['cube_with_materials.obj', 'cube_with_materials.mtl', 'cube_texture.png']); + assert.deepStrictEqual (importResult.missingFiles, []); + done (); + }, + error : function (importer, importError) { + assert.fail (); + } + }); + }, + error : function (importer, importError) { + assert.fail (); + } + }); }, error : function (importer, importError) { assert.fail (); } }); - files.push (new FileObject ('obj', 'cube_with_materials.mtl')); - ImportFiles (files, { - success : function (importer, importResult) { - assert (!OV.IsModelEmpty (importResult.model)); - assert.deepStrictEqual (importResult.usedFiles, ['cube_with_materials.obj', 'cube_with_materials.mtl']); - assert.deepStrictEqual (importResult.missingFiles, ['cube_texture.png']); - }, - error : function (importer, importError) { - assert.fail (); - } - }); - files.push (new FileObject ('obj', 'cube_texture.png')); - ImportFiles (files, { - success : function (importer, importResult) { - assert (!OV.IsModelEmpty (importResult.model)); - assert.deepStrictEqual (importResult.usedFiles, ['cube_with_materials.obj', 'cube_with_materials.mtl', 'cube_texture.png']); - assert.deepStrictEqual (importResult.missingFiles, []); - }, - error : function (importer, importError) { - assert.fail (); - } - }); + }); - it ('Missing texture multiple times', function () { + it ('Missing texture multiple times', function (done) { let files = [ new FileObject ('obj', 'two_materials_same_texture.obj'), new FileObject ('obj', 'two_materials_same_texture.mtl'), @@ -160,6 +168,7 @@ describe ('Importer Test', function () { assert (!OV.IsModelEmpty (importResult.model)); assert.deepStrictEqual (importResult.usedFiles, ['two_materials_same_texture.obj', 'two_materials_same_texture.mtl']); assert.deepStrictEqual (importResult.missingFiles, ['texture.png']); + done (); }, error : function (importer, importError) { assert.fail (); @@ -167,7 +176,7 @@ describe ('Importer Test', function () { }); }); - it ('Append Missing files', function () { + it ('Append Missing files', function (done) { let theImporter = new OV.Importer (); ImportFilesWithImporter (theImporter, [new FileObject ('obj', 'cube_with_materials.obj')], { success : function (importer, importResult) { @@ -184,6 +193,7 @@ describe ('Importer Test', function () { assert (!OV.IsModelEmpty (importResult.model)); assert.deepStrictEqual (importResult.usedFiles, ['cube_with_materials.obj', 'cube_with_materials.mtl', 'cube_texture.png']); assert.deepStrictEqual (importResult.missingFiles, []); + done (); }, error : function (importer, importError) { assert.fail (); @@ -201,7 +211,7 @@ describe ('Importer Test', function () { }); }); - it ('Reuse importer', function () { + it ('Reuse importer', function (done) { let files1 = [ new FileObject ('obj', 'cube_with_materials.obj'), new FileObject ('obj', 'cube_with_materials.mtl'), @@ -223,6 +233,7 @@ describe ('Importer Test', function () { assert (!OV.IsModelEmpty (importResult.model)); assert.deepStrictEqual (importResult.usedFiles, ['single_triangle.obj']); assert.deepStrictEqual (importResult.missingFiles, []); + done (); }, error : function (importer, importError) { assert.fail (); @@ -235,7 +246,7 @@ describe ('Importer Test', function () { }); }); - it ('Default color', function () { + it ('Default color', function (done) { let files = [ new FileObject ('stl', 'single_triangle.stl') ]; @@ -244,14 +255,15 @@ describe ('Importer Test', function () { let settings = new OV.ImportSettings (); settings.defaultColor = new OV.Color (200, 0, 0); theImporter.Import (settings, { - success : function (importResult) { + onSuccess : function (importResult) { assert (!OV.IsModelEmpty (importResult.model)); assert.deepStrictEqual (importResult.usedFiles, ['single_triangle.stl']); assert.deepStrictEqual (importResult.missingFiles, []); let material = importResult.model.GetMaterial (0); assert.deepStrictEqual (material.diffuse, new OV.Color (200, 0, 0)); + done (); }, - error : function (importError) { + onError : function (importError) { assert.fail (); } }); diff --git a/test/tests/importergltf_test.js b/test/tests/importergltf_test.js index 23eb451..d6a927d 100644 --- a/test/tests/importergltf_test.js +++ b/test/tests/importergltf_test.js @@ -6,348 +6,384 @@ let testUtils = require ('../utils/testutils.js'); //console.log (util.inspect(testUtils.ModelToObjectSimple (model), {showHidden: false, depth: null})) describe ('Gltf Importer', function () { - it ('Triangle', function () { + it ('Triangle', function (done) { let testFileList = [ ['Triangle/glTF', 'Triangle.gltf'], ['Triangle/glTF-Embedded', 'Triangle.gltf'], ['TriangleWithoutIndices/glTF', 'TriangleWithoutIndices.gltf'], ['TriangleWithoutIndices/glTF-Embedded', 'TriangleWithoutIndices.gltf'] ]; + let processed = 0; for (let i = 0; i < testFileList.length; i++) { let testFile = testFileList[i]; - let model = testFiles.ImportGltfFile (testFile[0], testFile[1]); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - vertexCount : 3, - normalCount : 1, - uvCount : 0, - triangleCount : 1, - boundingBox : { - min : [0.0, 0.0, 0.0], - max : [1.0, 1.0, 0.0] + testFiles.ImportGltfFile (testFile[0], testFile[1], function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + vertexCount : 3, + normalCount : 1, + uvCount : 0, + triangleCount : 1, + boundingBox : { + min : [0.0, 0.0, 0.0], + max : [1.0, 1.0, 0.0] + } } - } - ] - }); + ] + }); + processed += 1; + if (processed == testFileList.length) { + done (); + } + }); } }); - it ('Box', function () { + it ('Box', function (done) { let testFileList = [ ['Box/glTF', 'Box.gltf'], ['Box/glTF-Embedded', 'Box.gltf'], ['Box/glTF-Binary', 'Box.glb'] ]; + let processed = 0; for (let i = 0; i < testFileList.length; i++) { let testFile = testFileList[i]; - let model = testFiles.ImportGltfFile (testFile[0], testFile[1]); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : 'Red' } - ], - meshes : [ - { - name : 'Mesh', - vertexCount : 24, - normalCount : 24, - uvCount : 0, - triangleCount : 12, - boundingBox : { - min : [-0.5, -0.5, -0.5], - max : [0.5, 0.5, 0.5] + testFiles.ImportGltfFile (testFile[0], testFile[1], function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : 'Red' } + ], + meshes : [ + { + name : 'Mesh', + vertexCount : 24, + normalCount : 24, + uvCount : 0, + triangleCount : 12, + boundingBox : { + min : [-0.5, -0.5, -0.5], + max : [0.5, 0.5, 0.5] + } } - } - ] - }); + ] + }); + processed += 1; + if (processed == testFileList.length) { + done (); + } + }); } }); - it ('BoxInterleaved', function () { + it ('BoxInterleaved', function (done) { let testFileList = [ ['BoxInterleaved/glTF', 'BoxInterleaved.gltf'], ['BoxInterleaved/glTF-Embedded', 'BoxInterleaved.gltf'], ['BoxInterleaved/glTF-Binary', 'BoxInterleaved.glb'] ]; + let processed = 0; for (let i = 0; i < testFileList.length; i++) { let testFile = testFileList[i]; - let model = testFiles.ImportGltfFile (testFile[0], testFile[1]); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : 'Mesh', - vertexCount : 24, - normalCount : 24, - uvCount : 0, - triangleCount : 12, - boundingBox : { - min : [-0.5, -0.5, -0.5], - max : [0.5, 0.5, 0.5] + testFiles.ImportGltfFile (testFile[0], testFile[1], function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : 'Mesh', + vertexCount : 24, + normalCount : 24, + uvCount : 0, + triangleCount : 12, + boundingBox : { + min : [-0.5, -0.5, -0.5], + max : [0.5, 0.5, 0.5] + } } - } - ] - }); + ] + }); + processed += 1; + if (processed == testFileList.length) { + done (); + } + }); } }); - it ('BoxTextured', function () { + it ('BoxTextured', function (done) { let testFileList = [ ['BoxTextured/glTF', 'BoxTextured.gltf'], ['BoxTextured/glTF-Embedded', 'BoxTextured.gltf'], ['BoxTextured/glTF-Binary', 'BoxTextured.glb'] ]; + let processed = 0; for (let i = 0; i < testFileList.length; i++) { let testFile = testFileList[i]; - let model = testFiles.ImportGltfFile (testFile[0], testFile[1]); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : 'Texture' } - ], - meshes : [ - { - name : 'Mesh', - vertexCount : 24, - normalCount : 24, - uvCount : 24, - triangleCount : 12, - boundingBox : { - min : [-0.5, -0.5, -0.5], - max : [0.5, 0.5, 0.5] + testFiles.ImportGltfFile (testFile[0], testFile[1], function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : 'Texture' } + ], + meshes : [ + { + name : 'Mesh', + vertexCount : 24, + normalCount : 24, + uvCount : 24, + triangleCount : 12, + boundingBox : { + min : [-0.5, -0.5, -0.5], + max : [0.5, 0.5, 0.5] + } } - } - ] - }); + ] + }); + processed += 1; + if (processed == testFileList.length) { + done (); + } + }); } }); - it ('SimpleMeshes', function () { + it ('SimpleMeshes', function (done) { let testFileList = [ ['SimpleMeshes/glTF', 'SimpleMeshes.gltf'], ['SimpleMeshes/glTF-Embedded', 'SimpleMeshes.gltf'] ]; + let processed = 0; for (let i = 0; i < testFileList.length; i++) { let testFile = testFileList[i]; - let model = testFiles.ImportGltfFile (testFile[0], testFile[1]); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - vertexCount : 3, - normalCount : 3, - uvCount : 0, - triangleCount : 1, - boundingBox : { - min : [0.0, 0.0, 0.0], - max : [1.0, 1.0, 0.0] + testFiles.ImportGltfFile (testFile[0], testFile[1], function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + vertexCount : 3, + normalCount : 3, + uvCount : 0, + triangleCount : 1, + boundingBox : { + min : [0.0, 0.0, 0.0], + max : [1.0, 1.0, 0.0] + } + }, + { + name : '', + vertexCount : 3, + normalCount : 3, + uvCount : 0, + triangleCount : 1, + boundingBox : { + min : [1.0, 0.0, 0.0], + max : [2.0, 1.0, 0.0] + } } - }, - { - name : '', - vertexCount : 3, - normalCount : 3, - uvCount : 0, - triangleCount : 1, - boundingBox : { - min : [1.0, 0.0, 0.0], - max : [2.0, 1.0, 0.0] - } - } - ] - }); + ] + }); + processed += 1; + if (processed == testFileList.length) { + done (); + } + }); } }); - it ('OrientationTest', function () { + it ('OrientationTest', function (done) { let testFileList = [ ['OrientationTest/glTF', 'OrientationTest.gltf'], ['OrientationTest/glTF-Embedded', 'OrientationTest.gltf'], ['OrientationTest/glTF-Binary', 'OrientationTest.glb'], ]; + let processed = 0; for (let i = 0; i < testFileList.length; i++) { let testFile = testFileList[i]; - let model = testFiles.ImportGltfFile (testFile[0], testFile[1]); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : 'BaseMaterial' }, - { name : 'MatX1' }, - { name : 'MatX2' }, - { name : 'MatY1' }, - { name : 'MatY2' }, - { name : 'MatZ1' }, - { name : 'MatZ2' } - ], - meshes : [ - { - name: 'ArrowMeshZ2', - vertexCount: 78, - normalCount: 78, - uvCount: 0, - triangleCount: 38, - boundingBox : { - min: [ -0.6921195564310951, -1.0785199551363698, -5.330651201963446 ], - max: [ 1.0439303242310798, 2.868914373727357, -4.66934876823423 ] + testFiles.ImportGltfFile (testFile[0], testFile[1], function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : 'BaseMaterial' }, + { name : 'MatX1' }, + { name : 'MatX2' }, + { name : 'MatY1' }, + { name : 'MatY2' }, + { name : 'MatZ1' }, + { name : 'MatZ2' } + ], + meshes : [ + { + name: 'ArrowMeshZ2', + vertexCount: 78, + normalCount: 78, + uvCount: 0, + triangleCount: 38, + boundingBox : { + min: [ -0.6921195564310951, -1.0785199551363698, -5.330651201963446 ], + max: [ 1.0439303242310798, 2.868914373727357, -4.66934876823423 ] + } + }, + { + name: 'TargetMeshZ2', + vertexCount: 50, + normalCount: 50, + uvCount: 0, + triangleCount: 26, + boundingBox : { + min: [ 0.8097413778305054, 2.8717148303985596, -5.33065128326416 ], + max: [ 1.4936277866363525, 3.9211390018463135, -4.66934871673584 ] + } + }, + { + name: 'TargetMeshY2', + vertexCount: 50, + normalCount: 50, + uvCount: 0, + triangleCount: 26, + boundingBox : { + min: [ -1.1686336994171143, -5.330650806427002, 2.93727445602417 ], + max: [ -0.46912679076194763, -4.66934871673584, 3.9916374683380127 ] + } + }, + { + name: 'ArrowMeshY2', + vertexCount: 78, + normalCount: 78, + uvCount: 0, + triangleCount: 38, + boundingBox : { + min: [ -0.9557393651589479, -5.330651177643153, -1.06505742884149 ], + max: [ 0.6167901044859734, -4.6693486435429055, 2.934442924096579 ] + } + }, + { + name: 'ArrowMeshX2', + vertexCount: 78, + normalCount: 78, + uvCount: 0, + triangleCount: 38, + boundingBox : { + min: [ -5.330651171390089, -1.0326269494863676, -0.6059335185163844 ], + max: [ -4.669348828609911, 2.9885841671721116, 0.8202131194767724 ] + } + }, + { + name: 'TargetMeshX2', + vertexCount: 54, + normalCount: 54, + uvCount: 0, + triangleCount: 26, + boundingBox : { + min: [ -5.33065128326416, 2.991360902786255, -0.012430161237716675 ], + max: [ -4.66934871673584, 4.039160251617432, 0.6999828815460205 ] + } + }, + { + name: 'TargetMeshZ1', + vertexCount: 52, + normalCount: 52, + uvCount: 0, + triangleCount: 26, + boundingBox : { + min: [ -1.3648574352264404, 2.9005930423736572, 4.66934871673584 ], + max: [ -0.6740907430648804, 3.9529545307159424, 5.33065128326416 ] + } + }, + { + name: 'ArrowMeshZ1', + vertexCount: 74, + normalCount: 74, + uvCount: 0, + triangleCount: 38, + boundingBox : { + min: [ -1.009571011381568, -1.074115497823536, 4.669348895549774 ], + max: [ 0.6625885973069405, 2.8977772707193465, 5.330651104450226 ] + } + }, + { + name: 'TargetMeshX1', + vertexCount: 54, + normalCount: 54, + uvCount: 0, + triangleCount: 26, + boundingBox : { + min: [ 4.66934871673584, 2.4595587253570557, -2.553251266479492 ], + max: [ 5.33065128326416, 3.432579517364502, -1.7226401567459106 ] + } + }, + { + name: 'ArrowMeshX1', + vertexCount: 78, + normalCount: 78, + uvCount: 0, + triangleCount: 38, + boundingBox : { + min: [ 4.669348835945129, -1.0589144181932033, -1.7207290818192755 ], + max: [ 5.330651164054871, 2.4574561383341145, 0.9159925616542917 ] + } + }, + { + name: 'TargetMeshY1', + vertexCount: 52, + normalCount: 52, + uvCount: 0, + triangleCount: 26, + boundingBox : { + min: [ 2.8218495845794678, 4.669349193572998, -1.6833229064941406 ], + max: [ 3.864471435546875, 5.33065128326416, -1.0113166570663452 ] + } + }, + { + name: 'ArrowMeshY1', + vertexCount: 78, + normalCount: 78, + uvCount: 0, + triangleCount: 38, + boundingBox : { + min: [ -1.0826615032554154, 4.669348806142807, -1.093071740019906 ], + max: [ 2.8190779754834807, 5.3306513130664825, 0.7348238365226794 ] + } + }, + { + name: 'BaseCubeMesh', + vertexCount: 272, + normalCount: 272, + uvCount: 0, + triangleCount: 140, + boundingBox : { + min: [ -5.000001907348633, -5, -5.000001907348633 ], + max: [ 5.000002384185791, 5, 5.000002861022949 ] + } } - }, - { - name: 'TargetMeshZ2', - vertexCount: 50, - normalCount: 50, - uvCount: 0, - triangleCount: 26, - boundingBox : { - min: [ 0.8097413778305054, 2.8717148303985596, -5.33065128326416 ], - max: [ 1.4936277866363525, 3.9211390018463135, -4.66934871673584 ] - } - }, - { - name: 'TargetMeshY2', - vertexCount: 50, - normalCount: 50, - uvCount: 0, - triangleCount: 26, - boundingBox : { - min: [ -1.1686336994171143, -5.330650806427002, 2.93727445602417 ], - max: [ -0.46912679076194763, -4.66934871673584, 3.9916374683380127 ] - } - }, - { - name: 'ArrowMeshY2', - vertexCount: 78, - normalCount: 78, - uvCount: 0, - triangleCount: 38, - boundingBox : { - min: [ -0.9557393651589479, -5.330651177643153, -1.06505742884149 ], - max: [ 0.6167901044859734, -4.6693486435429055, 2.934442924096579 ] - } - }, - { - name: 'ArrowMeshX2', - vertexCount: 78, - normalCount: 78, - uvCount: 0, - triangleCount: 38, - boundingBox : { - min: [ -5.330651171390089, -1.0326269494863676, -0.6059335185163844 ], - max: [ -4.669348828609911, 2.9885841671721116, 0.8202131194767724 ] - } - }, - { - name: 'TargetMeshX2', - vertexCount: 54, - normalCount: 54, - uvCount: 0, - triangleCount: 26, - boundingBox : { - min: [ -5.33065128326416, 2.991360902786255, -0.012430161237716675 ], - max: [ -4.66934871673584, 4.039160251617432, 0.6999828815460205 ] - } - }, - { - name: 'TargetMeshZ1', - vertexCount: 52, - normalCount: 52, - uvCount: 0, - triangleCount: 26, - boundingBox : { - min: [ -1.3648574352264404, 2.9005930423736572, 4.66934871673584 ], - max: [ -0.6740907430648804, 3.9529545307159424, 5.33065128326416 ] - } - }, - { - name: 'ArrowMeshZ1', - vertexCount: 74, - normalCount: 74, - uvCount: 0, - triangleCount: 38, - boundingBox : { - min: [ -1.009571011381568, -1.074115497823536, 4.669348895549774 ], - max: [ 0.6625885973069405, 2.8977772707193465, 5.330651104450226 ] - } - }, - { - name: 'TargetMeshX1', - vertexCount: 54, - normalCount: 54, - uvCount: 0, - triangleCount: 26, - boundingBox : { - min: [ 4.66934871673584, 2.4595587253570557, -2.553251266479492 ], - max: [ 5.33065128326416, 3.432579517364502, -1.7226401567459106 ] - } - }, - { - name: 'ArrowMeshX1', - vertexCount: 78, - normalCount: 78, - uvCount: 0, - triangleCount: 38, - boundingBox : { - min: [ 4.669348835945129, -1.0589144181932033, -1.7207290818192755 ], - max: [ 5.330651164054871, 2.4574561383341145, 0.9159925616542917 ] - } - }, - { - name: 'TargetMeshY1', - vertexCount: 52, - normalCount: 52, - uvCount: 0, - triangleCount: 26, - boundingBox : { - min: [ 2.8218495845794678, 4.669349193572998, -1.6833229064941406 ], - max: [ 3.864471435546875, 5.33065128326416, -1.0113166570663452 ] - } - }, - { - name: 'ArrowMeshY1', - vertexCount: 78, - normalCount: 78, - uvCount: 0, - triangleCount: 38, - boundingBox : { - min: [ -1.0826615032554154, 4.669348806142807, -1.093071740019906 ], - max: [ 2.8190779754834807, 5.3306513130664825, 0.7348238365226794 ] - } - }, - { - name: 'BaseCubeMesh', - vertexCount: 272, - normalCount: 272, - uvCount: 0, - triangleCount: 140, - boundingBox : { - min: [ -5.000001907348633, -5, -5.000001907348633 ], - max: [ 5.000002384185791, 5, 5.000002861022949 ] - } - } - ] - }); + ] + }); + processed += 1; + if (processed == testFileList.length) { + done (); + } + }); } }); - it ('MeshPrimitives_4Vertex', function () { + it ('MeshPrimitives_4Vertex', function (done) { let testFileList = [ ['Mesh_PrimitiveMode', 'Mesh_PrimitiveMode_04.gltf'], ['Mesh_PrimitiveMode', 'Mesh_PrimitiveMode_05.gltf'], @@ -355,90 +391,108 @@ describe ('Gltf Importer', function () { ['Mesh_PrimitiveMode', 'Mesh_PrimitiveMode_12.gltf'], ['Mesh_PrimitiveMode', 'Mesh_PrimitiveMode_13.gltf'] ]; + let processed = 0; for (let i = 0; i < testFileList.length; i++) { let testFile = testFileList[i]; - let model = testFiles.ImportGltfFile (testFile[0], testFile[1]); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - vertexCount : 4, - normalCount : 2, - uvCount : 0, - triangleCount : 2, - boundingBox : { - min : [-0.5, -0.5, 0.0], - max : [0.5, 0.5, 0.0] + testFiles.ImportGltfFile (testFile[0], testFile[1], function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + vertexCount : 4, + normalCount : 2, + uvCount : 0, + triangleCount : 2, + boundingBox : { + min : [-0.5, -0.5, 0.0], + max : [0.5, 0.5, 0.0] + } } - } - ] - }); + ] + }); + processed += 1; + if (processed == testFileList.length) { + done (); + } + }); } }); - it ('MeshPrimitives_6Vertex', function () { + it ('MeshPrimitives_6Vertex', function (done) { let testFileList = [ ['Mesh_PrimitiveMode', 'Mesh_PrimitiveMode_06.gltf'] ]; + let processed = 0; for (let i = 0; i < testFileList.length; i++) { let testFile = testFileList[i]; - let model = testFiles.ImportGltfFile (testFile[0], testFile[1]); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - vertexCount : 6, - normalCount : 2, - uvCount : 0, - triangleCount : 2, - boundingBox : { - min : [-0.5, -0.5, 0.0], - max : [0.5, 0.5, 0.0] + testFiles.ImportGltfFile (testFile[0], testFile[1], function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + vertexCount : 6, + normalCount : 2, + uvCount : 0, + triangleCount : 2, + boundingBox : { + min : [-0.5, -0.5, 0.0], + max : [0.5, 0.5, 0.0] + } } - } - ] - }); + ] + }); + processed += 1; + if (processed == testFileList.length) { + done (); + } + }); } }); - it ('SimpleSparseAccessor', function () { + it ('SimpleSparseAccessor', function (done) { let testFileList = [ ['SimpleSparseAccessor/glTF', 'SimpleSparseAccessor.gltf'], ['SimpleSparseAccessor/glTF-Embedded', 'SimpleSparseAccessor.gltf'] ]; + let processed = 0; for (let i = 0; i < testFileList.length; i++) { let testFile = testFileList[i]; - let model = testFiles.ImportGltfFile (testFile[0], testFile[1]); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - vertexCount : 14, - normalCount : 12, - uvCount : 0, - triangleCount : 12, - boundingBox : { - min : [0.0, 0.0, 0.0], - max : [6.0, 4.0, 0.0] + testFiles.ImportGltfFile (testFile[0], testFile[1], function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + vertexCount : 14, + normalCount : 12, + uvCount : 0, + triangleCount : 12, + boundingBox : { + min : [0.0, 0.0, 0.0], + max : [6.0, 4.0, 0.0] + } } - } - ] - }); + ] + }); + processed += 1; + if (processed == testFileList.length) { + done (); + } + }); } }); }); diff --git a/test/tests/importerobj_test.js b/test/tests/importerobj_test.js index c1df2df..6458ac9 100644 --- a/test/tests/importerobj_test.js +++ b/test/tests/importerobj_test.js @@ -2,580 +2,622 @@ var assert = require ('assert'); var testFiles = require ('../utils/testfiles.js'); var testUtils = require ('../utils/testutils.js'); -describe ('Obj Importer', function() { - it ('single_triangle.obj', function () { - var model = testFiles.ImportObjFile ('single_triangle.obj'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - } - ] - } - ] +describe ('Obj Importer', function () { + it ('single_triangle.obj', function (done) { + testFiles.ImportObjFile ('single_triangle.obj', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + } + ] + } + ] + }); + done (); }); }); - it ('two_triangles.obj', function () { - var model = testFiles.ImportObjFile ('two_triangles.obj'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - }, - { - vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - } - ] - } - ] + it ('two_triangles.obj', function (done) { + testFiles.ImportObjFile ('two_triangles.obj', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + }, + { + vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + } + ] + } + ] + }); + done (); }); }); - it ('single_rectangle.obj', function () { - var model = testFiles.ImportObjFile ('single_rectangle.obj'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - }, - { - vertices : [0, 0, 0, 1, 1, 0, 0, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - } - ] - } - ] + it ('single_rectangle.obj', function (done) { + testFiles.ImportObjFile ('single_rectangle.obj', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + }, + { + vertices : [0, 0, 0, 1, 1, 0, 0, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + } + ] + } + ] + }); + done (); }); }); - it ('single_triangle_with_comments.obj', function () { - var model = testFiles.ImportObjFile ('single_triangle_with_comments.obj'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : 'MyMeshName', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - } - ] - } - ] + it ('single_triangle_with_comments.obj', function (done) { + testFiles.ImportObjFile ('single_triangle_with_comments.obj', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : 'MyMeshName', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + } + ] + } + ] + }); + done (); }); }); - it ('single_triangle_negative_indices.obj', function () { - var model = testFiles.ImportObjFile ('single_triangle_negative_indices.obj'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - } - ] - } - ] + it ('single_triangle_negative_indices.obj', function (done) { + testFiles.ImportObjFile ('single_triangle_negative_indices.obj', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + } + ] + } + ] + }); + done (); }); }); - it ('single_triangle_with_normals_and_uvs.obj', function () { - var model = testFiles.ImportObjFile ('single_triangle_with_normals_and_uvs.obj'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [0, 0, 1, 0, 1, 1], - mat : 0 - } - ] - } - ] + it ('single_triangle_with_normals_and_uvs.obj', function (done) { + testFiles.ImportObjFile ('single_triangle_with_normals_and_uvs.obj', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [0, 0, 1, 0, 1, 1], + mat : 0 + } + ] + } + ] + }); + done (); }); }); - it ('single_triangle_in_mesh.obj', function () { - var model = testFiles.ImportObjFile ('single_triangle_in_mesh.obj'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : 'MeshName', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - } - ] - } - ] + it ('single_triangle_in_mesh.obj', function (done) { + testFiles.ImportObjFile ('single_triangle_in_mesh.obj', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : 'MeshName', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + } + ] + } + ] + }); + done (); }); }); - it ('two_triangles_in_meshes.obj', function () { - var model = testFiles.ImportObjFile ('two_triangles_in_meshes.obj'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : 'MeshName1', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - } - ] - }, - { - name : 'MeshName2', - triangles : [ - { - vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - } - ] - } - ] + it ('two_triangles_in_meshes.obj', function (done) { + testFiles.ImportObjFile ('two_triangles_in_meshes.obj', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : 'MeshName1', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + } + ] + }, + { + name : 'MeshName2', + triangles : [ + { + vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + } + ] + } + ] + }); + done (); }); }); - it ('empty_meshes.obj', function () { - var model = testFiles.ImportObjFile ('empty_meshes.obj'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : 'MeshName1', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - } - ] - }, - { - name : 'MeshName2', - triangles : [ - { - vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - } - ] - } - ] + it ('empty_meshes.obj', function (done) { + testFiles.ImportObjFile ('empty_meshes.obj', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : 'MeshName1', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + } + ] + }, + { + name : 'MeshName2', + triangles : [ + { + vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + } + ] + } + ] + }); + done (); }); }); - it ('single_triangle_with_material.obj', function () { - var model = testFiles.ImportObjFile ('single_triangle_with_material.obj'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : 'MaterialName1' }, - { name : 'MaterialName2' } - ], - meshes : [ - { - name : 'MeshName', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - } - ] - } - ] + it ('single_triangle_with_material.obj', function (done) { + testFiles.ImportObjFile ('single_triangle_with_material.obj', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : 'MaterialName1' }, + { name : 'MaterialName2' } + ], + meshes : [ + { + name : 'MeshName', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + } + ] + } + ] + }); + done (); }); }); - it ('two_triangles_with_material.obj', function () { - var model = testFiles.ImportObjFile ('two_triangles_with_material.obj'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : 'MaterialName1' }, - { name : 'MaterialName2' } - ], - meshes : [ - { - name : 'MeshName', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - }, - { - vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 1 - } - ] - } - ] + it ('two_triangles_with_material.obj', function (done) { + testFiles.ImportObjFile ('two_triangles_with_material.obj', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : 'MaterialName1' }, + { name : 'MaterialName2' } + ], + meshes : [ + { + name : 'MeshName', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + }, + { + vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 1 + } + ] + } + ] + }); + done (); }); }); - it ('two_meshes_same_vertices.obj', function () { - var model = testFiles.ImportObjFile ('two_meshes_same_vertices.obj'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : 'MeshName1', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - } - ] - }, - { - name : 'MeshName2', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 0, 0, 1], - normals : [0, -1, 0, 0, -1, 0, 0, -1, 0], - uvs : [], - mat : 0 - } - ] - } - ] + it ('two_meshes_same_vertices.obj', function (done) { + testFiles.ImportObjFile ('two_meshes_same_vertices.obj', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : 'MeshName1', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + } + ] + }, + { + name : 'MeshName2', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 0, 0, 1], + normals : [0, -1, 0, 0, -1, 0, 0, -1, 0], + uvs : [], + mat : 0 + } + ] + } + ] + }); + done (); }); }); - it ('two_meshes_with_same_name.obj', function () { - var model = testFiles.ImportObjFile ('two_meshes_with_same_name.obj'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : 'MeshName', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - }, - { - vertices : [0, 0, 0, 1, 0, 0, 0, 0, 1], - normals : [0, -1, 0, 0, -1, 0, 0, -1, 0], - uvs : [], - mat : 0 - } - ] - } - ] + it ('two_meshes_with_same_name.obj', function (done) { + testFiles.ImportObjFile ('two_meshes_with_same_name.obj', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : 'MeshName', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + }, + { + vertices : [0, 0, 0, 1, 0, 0, 0, 0, 1], + normals : [0, -1, 0, 0, -1, 0, 0, -1, 0], + uvs : [], + mat : 0 + } + ] + } + ] + }); + done (); }); }); - it ('rectangle_with_texture.obj', function () { - var model = testFiles.ImportObjFile ('rectangle_with_texture.obj'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : 'Material' } - ], - meshes : [ - { - name : 'Mesh', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [0, 0, 1, 0, 1, 1], - mat : 0 - }, - { - vertices : [0, 0, 0, 1, 1, 0, 0, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [0, 0, 1, 1, 0, 1], - mat : 0 - } - ] - } - ] + it ('rectangle_with_texture.obj', function (done) { + testFiles.ImportObjFile ('rectangle_with_texture.obj', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : 'Material' } + ], + meshes : [ + { + name : 'Mesh', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [0, 0, 1, 0, 1, 1], + mat : 0 + }, + { + vertices : [0, 0, 0, 1, 1, 0, 0, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [0, 0, 1, 1, 0, 1], + mat : 0 + } + ] + } + ] + }); + done (); }); }); - it ('two_materials_same_texture.obj', function () { - var model = testFiles.ImportObjFile ('two_materials_same_texture.obj'); - assert.strictEqual (model.GetMaterial (0).diffuseMap.url, model.GetMaterial (1).diffuseMap.url); - assert.strictEqual (model.GetMaterial (0).diffuseMap.buffer.byteLength, model.GetMaterial (1).diffuseMap.buffer.byteLength); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : 'Material1' }, - { name : 'Material2' } - ], - meshes : [ - { - name : 'Mesh', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [0, 0, 1, 0, 1, 1], - mat : 0 - }, - { - vertices : [0, 0, 0, 1, 1, 0, 0, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [0, 0, 1, 1, 0, 1], - mat : 1 - } - ] - } - ] + it ('two_materials_same_texture.obj', function (done) { + testFiles.ImportObjFile ('two_materials_same_texture.obj', function (model) { + assert.strictEqual (model.GetMaterial (0).diffuseMap.url, model.GetMaterial (1).diffuseMap.url); + assert.strictEqual (model.GetMaterial (0).diffuseMap.buffer.byteLength, model.GetMaterial (1).diffuseMap.buffer.byteLength); + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : 'Material1' }, + { name : 'Material2' } + ], + meshes : [ + { + name : 'Mesh', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [0, 0, 1, 0, 1, 1], + mat : 0 + }, + { + vertices : [0, 0, 0, 1, 1, 0, 0, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [0, 0, 1, 1, 0, 1], + mat : 1 + } + ] + } + ] + }); + done (); }); }); - it ('cube_with_materials.obj', function () { - var model = testFiles.ImportObjFile ('cube_with_materials.obj'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : 'Red' }, - { name : 'Green' }, - { name : 'Blue' }, - { name : 'White' }, - { name : 'Texture' } - ], - meshes : [ - { - name : 'Cube', - vertexCount : 8, - normalCount : 6, - uvCount : 4, - triangleCount : 12, - boundingBox : { - min : [0, 0, 0], - max : [1, 1, 1] + it ('cube_with_materials.obj', function (done) { + testFiles.ImportObjFile ('cube_with_materials.obj', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : 'Red' }, + { name : 'Green' }, + { name : 'Blue' }, + { name : 'White' }, + { name : 'Texture' } + ], + meshes : [ + { + name : 'Cube', + vertexCount : 8, + normalCount : 6, + uvCount : 4, + triangleCount : 12, + boundingBox : { + min : [0, 0, 0], + max : [1, 1, 1] + } } - } - ] + ] + }); + done (); }); }); - it ('cube_rgb.obj', function () { - var model = testFiles.ImportObjFile ('cube_rgb.obj'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : 'Red' }, - { name : 'Green' }, - { name : 'Blue' }, - { name : 'White' } - ], - meshes : [ - { - name : 'Cube', - vertexCount : 8, - normalCount : 6, - uvCount : 4, - triangleCount : 12, - boundingBox : { - min : [0, 0, 0], - max : [1, 1, 1] + it ('cube_rgb.obj', function (done) { + testFiles.ImportObjFile ('cube_rgb.obj', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : 'Red' }, + { name : 'Green' }, + { name : 'Blue' }, + { name : 'White' } + ], + meshes : [ + { + name : 'Cube', + vertexCount : 8, + normalCount : 6, + uvCount : 4, + triangleCount : 12, + boundingBox : { + min : [0, 0, 0], + max : [1, 1, 1] + } } - } - ] + ] + }); + done (); }); }); - it ('cube_with_materials_comments.obj', function () { - var model = testFiles.ImportObjFile ('cube_with_materials_comments.obj'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : 'Red' }, - { name : 'Green' }, - { name : 'Blue' }, - { name : 'White' }, - { name : 'Texture' } - ], - meshes : [ - { - name : 'Cube', - vertexCount : 8, - normalCount : 6, - uvCount : 4, - triangleCount : 12, - boundingBox : { - min : [0, 0, 0], - max : [1, 1, 1] + it ('cube_with_materials_comments.obj', function (done) { + testFiles.ImportObjFile ('cube_with_materials_comments.obj', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : 'Red' }, + { name : 'Green' }, + { name : 'Blue' }, + { name : 'White' }, + { name : 'Texture' } + ], + meshes : [ + { + name : 'Cube', + vertexCount : 8, + normalCount : 6, + uvCount : 4, + triangleCount : 12, + boundingBox : { + min : [0, 0, 0], + max : [1, 1, 1] + } } - } - ] + ] + }); + done (); }); }); - it ('cube with white spaces.obj', function () { - var model = testFiles.ImportObjFile ('cube with white spaces.obj'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : 'Red Color' }, - { name : 'Green Color' }, - { name : 'Blue Color' }, - { name : 'White Color' }, - { name : 'Texture Color' } - ], - meshes : [ - { - name : 'Cube Mesh', - vertexCount : 8, - normalCount : 6, - uvCount : 4, - triangleCount : 12, - boundingBox : { - min : [0, 0, 0], - max : [1, 1, 1] + it ('cube with white spaces.obj', function (done) { + testFiles.ImportObjFile ('cube with white spaces.obj', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : 'Red Color' }, + { name : 'Green Color' }, + { name : 'Blue Color' }, + { name : 'White Color' }, + { name : 'Texture Color' } + ], + meshes : [ + { + name : 'Cube Mesh', + vertexCount : 8, + normalCount : 6, + uvCount : 4, + triangleCount : 12, + boundingBox : { + min : [0, 0, 0], + max : [1, 1, 1] + } } - } - ] + ] + }); + done (); }); }); - it ('icosahedron.obj', function () { - var model = testFiles.ImportObjFile ('icosahedron.obj'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : 'Blue' } - ], - meshes : [ - { - name : 'Icosahedron', - vertexCount : 12, - normalCount : 20, - uvCount : 0, - triangleCount : 20, - boundingBox : { - min : [-0.85065080835204, -0.85065080835204, -0.85065080835204], - max : [0.85065080835204, 0.85065080835204, 0.85065080835204] + it ('icosahedron.obj', function (done) { + testFiles.ImportObjFile ('icosahedron.obj', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : 'Blue' } + ], + meshes : [ + { + name : 'Icosahedron', + vertexCount : 12, + normalCount : 20, + uvCount : 0, + triangleCount : 20, + boundingBox : { + min : [-0.85065080835204, -0.85065080835204, -0.85065080835204], + max : [0.85065080835204, 0.85065080835204, 0.85065080835204] + } } - } - ] + ] + }); + done (); }); }); - it ('hundred_cubes.obj', function () { - var model = testFiles.ImportObjFile ('hundred_cubes.obj'); - assert (OV.CheckModel (model)); - assert.strictEqual (model.MaterialCount (), 3); - assert.strictEqual (model.MeshCount (), 100); + it ('hundred_cubes.obj', function (done) { + testFiles.ImportObjFile ('hundred_cubes.obj', function (model) { + assert (OV.CheckModel (model)); + assert.strictEqual (model.MaterialCount (), 3); + assert.strictEqual (model.MeshCount (), 100); + done (); + }); }); }); diff --git a/test/tests/importeroff_test.js b/test/tests/importeroff_test.js index b05be9e..d44b443 100644 --- a/test/tests/importeroff_test.js +++ b/test/tests/importeroff_test.js @@ -2,136 +2,147 @@ var assert = require ('assert'); var testFiles = require ('../utils/testfiles.js'); var testUtils = require ('../utils/testutils.js'); -describe ('Off Importer', function() { - it ('single_triangle.off', function () { - var model = testFiles.ImportOffFile ('single_triangle.off'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - } - ] - } - ] +describe ('Off Importer', function () { + it ('single_triangle.off', function (done) { + testFiles.ImportOffFile ('single_triangle.off', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + } + ] + } + ] + }); + done (); }); }); - it ('two_triangles.off', function () { - var model = testFiles.ImportOffFile ('two_triangles.off'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - }, - { - vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - } - ] - } - ] + it ('two_triangles.off', function (done) { + testFiles.ImportOffFile ('two_triangles.off', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + }, + { + vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + } + ] + } + ] + }); + done (); }); }); - it ('single_rectangle.off', function () { - var model = testFiles.ImportOffFile ('single_rectangle.off'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - }, - { - vertices : [0, 0, 0, 1, 1, 0, 0, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - } - ] - } - ] + it ('single_rectangle.off', function (done) { + testFiles.ImportOffFile ('single_rectangle.off', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + }, + { + vertices : [0, 0, 0, 1, 1, 0, 0, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + } + ] + } + ] + }); + done (); }); }); - it ('single_triangle_with_comments.off', function () { - var model = testFiles.ImportOffFile ('single_triangle_with_comments.off'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - } - ] - } - ] + it ('single_triangle_with_comments.off', function (done) { + testFiles.ImportOffFile ('single_triangle_with_comments.off', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + } + ] + } + ] + }); + done (); }); + }); - it ('cube.off', function () { - var model = testFiles.ImportOffFile ('cube.off'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - vertexCount : 8, - normalCount : 12, - uvCount : 0, - triangleCount : 12, - boundingBox : { - min : [0, 0, 0], - max : [1, 1, 1] + it ('cube.off', function (done) { + testFiles.ImportOffFile ('cube.off', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + vertexCount : 8, + normalCount : 12, + uvCount : 0, + triangleCount : 12, + boundingBox : { + min : [0, 0, 0], + max : [1, 1, 1] + } } - } - ] + ] + }); + done (); }); }); }); diff --git a/test/tests/importerply_test.js b/test/tests/importerply_test.js index c9a8b8e..53f8174 100644 --- a/test/tests/importerply_test.js +++ b/test/tests/importerply_test.js @@ -3,210 +3,226 @@ var testFiles = require ('../utils/testfiles.js'); var testUtils = require ('../utils/testutils.js'); describe ('Ply Importer', function() { - it ('single_triangle.ply', function () { - var model = testFiles.ImportPlyFile ('single_triangle.ply'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - } - ] - } - ] + it ('single_triangle.ply', function (done) { + var model = testFiles.ImportPlyFile ('single_triangle.ply', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + } + ] + } + ] + }); + done (); }); }); - it ('two_triangles.ply', function () { - var model = testFiles.ImportPlyFile ('two_triangles.ply'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - }, - { - vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - } - ] - } - ] + it ('two_triangles.ply', function (done) { + var model = testFiles.ImportPlyFile ('two_triangles.ply', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + }, + { + vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + } + ] + } + ] + }); + done (); }); }); - it ('single_rectangle.ply', function () { - var model = testFiles.ImportPlyFile ('single_rectangle.ply'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - }, - { - vertices : [0, 0, 0, 1, 1, 0, 0, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - } - ] - } - ] + it ('single_rectangle.ply', function (done) { + var model = testFiles.ImportPlyFile ('single_rectangle.ply', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + }, + { + vertices : [0, 0, 0, 1, 1, 0, 0, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + } + ] + } + ] + }); + done (); }); }); - it ('single_triangle_with_comments.ply', function () { - var model = testFiles.ImportPlyFile ('single_triangle_with_comments.ply'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 + it ('single_triangle_with_comments.ply', function (done) { + var model = testFiles.ImportPlyFile ('single_triangle_with_comments.ply', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + } + ] + } + ] + }); + done (); + }); + }); + + it ('cube.ply', function (done) { + var model = testFiles.ImportPlyFile ('cube.ply', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + vertexCount : 8, + normalCount : 12, + uvCount : 0, + triangleCount : 12, + boundingBox : { + min : [0, 0, 0], + max : [1, 1, 1] } - ] - } - ] + } + ] + }); + done (); }); }); - it ('cube.ply', function () { - var model = testFiles.ImportPlyFile ('cube.ply'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - vertexCount : 8, - normalCount : 12, - uvCount : 0, - triangleCount : 12, - boundingBox : { - min : [0, 0, 0], - max : [1, 1, 1] + it ('cube_meshlab_ascii.ply', function (done) { + var model = testFiles.ImportPlyFile ('cube_meshlab_ascii.ply', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + vertexCount : 8, + normalCount : 12, + uvCount : 0, + triangleCount : 12, + boundingBox : { + min : [0, 0, 0], + max : [1, 1, 1] + } } - } - ] - }); - }); - - it ('cube_meshlab_ascii.ply', function () { - var model = testFiles.ImportPlyFile ('cube_meshlab_ascii.ply'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - vertexCount : 8, - normalCount : 12, - uvCount : 0, - triangleCount : 12, - boundingBox : { - min : [0, 0, 0], - max : [1, 1, 1] - } - } - ] + ] + }); + done (); }); }); - it ('cube_meshlab_binary.ply', function () { - var model = testFiles.ImportPlyFile ('cube_meshlab_binary.ply'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - vertexCount : 8, - normalCount : 12, - uvCount : 0, - triangleCount : 12, - boundingBox : { - min : [0, 0, 0], - max : [1, 1, 1] + it ('cube_meshlab_binary.ply', function (done) { + var model = testFiles.ImportPlyFile ('cube_meshlab_binary.ply', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + vertexCount : 8, + normalCount : 12, + uvCount : 0, + triangleCount : 12, + boundingBox : { + min : [0, 0, 0], + max : [1, 1, 1] + } } - } - ] + ] + }); + done (); }); }); - it ('cube_rgb_binary.ply', function () { - var model = testFiles.ImportPlyFile ('cube_rgb_binary.ply'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : '#cc0000ff' }, - { name : '#00cc00ff' }, - { name : '#0000ccff' }, - { name : '#cccccc7f' } - ], - meshes : [ - { - name : '', - vertexCount : 8, - normalCount : 12, - uvCount : 0, - triangleCount : 12, - boundingBox : { - min : [0, 0, 0], - max : [1, 1, 1] + it ('cube_rgb_binary.ply', function (done) { + var model = testFiles.ImportPlyFile ('cube_rgb_binary.ply', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : 'Color cc0000ff' }, + { name : 'Color 00cc00ff' }, + { name : 'Color 0000ccff' }, + { name : 'Color cccccc7f' } + ], + meshes : [ + { + name : '', + vertexCount : 8, + normalCount : 12, + uvCount : 0, + triangleCount : 12, + boundingBox : { + min : [0, 0, 0], + max : [1, 1, 1] + } } - } - ] + ] + }); + done (); }); }); }); diff --git a/test/tests/importerstl_test.js b/test/tests/importerstl_test.js index d7f7d5c..f21ca41 100644 --- a/test/tests/importerstl_test.js +++ b/test/tests/importerstl_test.js @@ -3,202 +3,218 @@ var testFiles = require ('../utils/testfiles.js'); var testUtils = require ('../utils/testutils.js'); describe ('Stl Importer', function() { - it ('single_triangle.stl', function () { - var model = testFiles.ImportStlFile ('single_triangle.stl'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : 'MeshName', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - } - ] - } - ] + it ('single_triangle.stl', function (done) { + testFiles.ImportStlFile ('single_triangle.stl', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : 'MeshName', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + } + ] + } + ] + }); + done (); }); }); - it ('single_triangle_with_comments.stl', function () { - var model = testFiles.ImportStlFile ('single_triangle_with_comments.stl'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : 'MeshName', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - } - ] - } - ] + it ('single_triangle_with_comments.stl', function (done) { + testFiles.ImportStlFile ('single_triangle_with_comments.stl', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : 'MeshName', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + } + ] + } + ] + }); + done (); }); }); - it ('single_triangle_no_normal.stl', function () { - var model = testFiles.ImportStlFile ('single_triangle_no_normal.stl'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : 'MeshName', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - } - ] - } - ] + it ('single_triangle_no_normal.stl', function (done) { + testFiles.ImportStlFile ('single_triangle_no_normal.stl', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : 'MeshName', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + } + ] + } + ] + }); + done (); }); }); - it ('two_triangles.stl', function () { - var model = testFiles.ImportStlFile ('two_triangles.stl'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObject (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : 'MeshName', - triangles : [ - { - vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - }, - { - vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1], - normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], - uvs : [], - mat : 0 - } - ] - } - ] + it ('two_triangles.stl', function (done) { + testFiles.ImportStlFile ('two_triangles.stl', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : 'MeshName', + triangles : [ + { + vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + }, + { + vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1], + normals : [0, 0, 1, 0, 0, 1, 0, 0, 1], + uvs : [], + mat : 0 + } + ] + } + ] + }); + done (); }); }); - it ('stl_ascii.stl', function () { - var model = testFiles.ImportStlFile ('stl_ascii.stl'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : 'Untitled-5427e5af', - vertexCount : 1716, - normalCount : 572, - uvCount : 0, - triangleCount : 572, - boundingBox : { - min : [0, -1.10792799192095, 0], - max : [4.94407346265022, 3.31831671830375, 1.2] + it ('stl_ascii.stl', function (done) { + testFiles.ImportStlFile ('stl_ascii.stl', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : 'Untitled-5427e5af', + vertexCount : 1716, + normalCount : 572, + uvCount : 0, + triangleCount : 572, + boundingBox : { + min : [0, -1.10792799192095, 0], + max : [4.94407346265022, 3.31831671830375, 1.2] + } } - } - ] + ] + }); + done (); }); }); - it ('stl_binary.stl', function () { - var model = testFiles.ImportStlFile ('stl_binary.stl'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - vertexCount : 2184, - normalCount : 728, - uvCount : 0, - triangleCount : 728, - boundingBox : { - min : [0, -1.1079280376434326, 0], - max : [5.70156717300415, 3.318316698074341, 1.2000000476837158] + it ('stl_binary.stl', function (done) { + testFiles.ImportStlFile ('stl_binary.stl', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + vertexCount : 2184, + normalCount : 728, + uvCount : 0, + triangleCount : 728, + boundingBox : { + min : [0, -1.1079280376434326, 0], + max : [5.70156717300415, 3.318316698074341, 1.2000000476837158] + } } - } - ] + ] + }); + done (); }); }); - it ('cube_meshlab_ascii.stl', function () { - var model = testFiles.ImportStlFile ('cube_meshlab_ascii.stl'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : 'STL generated by MeshLab', - vertexCount : 36, - normalCount : 12, - uvCount : 0, - triangleCount : 12, - boundingBox : { - min : [0, 0, 0], - max : [1, 1, 1] + it ('cube_meshlab_ascii.stl', function (done) { + testFiles.ImportStlFile ('cube_meshlab_ascii.stl', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : 'STL generated by MeshLab', + vertexCount : 36, + normalCount : 12, + uvCount : 0, + triangleCount : 12, + boundingBox : { + min : [0, 0, 0], + max : [1, 1, 1] + } } - } - ] + ] + }); + done (); }); }); - it ('cube_meshlab_binary.stl', function () { - var model = testFiles.ImportStlFile ('cube_meshlab_binary.stl'); - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - vertexCount : 36, - normalCount : 12, - uvCount : 0, - triangleCount : 12, - boundingBox : { - min : [0, 0, 0], - max : [1, 1, 1] + it ('cube_meshlab_binary.stl', function (done) { + testFiles.ImportStlFile ('cube_meshlab_binary.stl', function (model) { + assert (OV.CheckModel (model)); + assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + vertexCount : 36, + normalCount : 12, + uvCount : 0, + triangleCount : 12, + boundingBox : { + min : [0, 0, 0], + max : [1, 1, 1] + } } - } - ] + ] + }); + done (); }); }); }); diff --git a/test/tests/modelutils_test.js b/test/tests/modelutils_test.js index 953c622..3c33bd1 100644 --- a/test/tests/modelutils_test.js +++ b/test/tests/modelutils_test.js @@ -78,4 +78,62 @@ describe ('Model Utils', function () { ] }); }); + + it ('Mesh Volume Calculation', function () { + function GetTriangleArea (v0, v1, v2) + { + let a = OV.CoordDistance3D (v0, v1); + let b = OV.CoordDistance3D (v1, v2); + let c = OV.CoordDistance3D (v0, v2); + let s = (a + b + c) / 2.0; + let areaSquare = s * (s - a) * (s - b) * (s - c); + if (areaSquare < 0.0) { + return 0.0; + } + return Math.sqrt (areaSquare); + } + + var model = new OV.Model (); + var cube = new OV.Mesh (); + cube.AddVertex (new OV.Coord3D (0.0, 0.0, 0.0)); + cube.AddVertex (new OV.Coord3D (1.0, 0.0, 0.0)); + cube.AddVertex (new OV.Coord3D (1.0, 1.0, 0.0)); + cube.AddVertex (new OV.Coord3D (0.0, 1.0, 0.0)); + cube.AddVertex (new OV.Coord3D (0.0, 0.0, 1.0)); + cube.AddVertex (new OV.Coord3D (1.0, 0.0, 1.0)); + cube.AddVertex (new OV.Coord3D (1.0, 1.0, 1.0)); + cube.AddVertex (new OV.Coord3D (0.0, 1.0, 1.0)); + cube.AddTriangle (new OV.Triangle (0, 1, 5)); + cube.AddTriangle (new OV.Triangle (0, 5, 4)); + cube.AddTriangle (new OV.Triangle (1, 2, 6)); + cube.AddTriangle (new OV.Triangle (1, 6, 5)); + cube.AddTriangle (new OV.Triangle (2, 3, 7)); + cube.AddTriangle (new OV.Triangle (2, 7, 6)); + cube.AddTriangle (new OV.Triangle (3, 0, 4)); + cube.AddTriangle (new OV.Triangle (3, 4, 7)); + cube.AddTriangle (new OV.Triangle (0, 3, 2)); + cube.AddTriangle (new OV.Triangle (0, 2, 1)); + cube.AddTriangle (new OV.Triangle (4, 5, 6)); + cube.AddTriangle (new OV.Triangle (4, 6, 7)); + model.AddMesh (cube); + OV.FinalizeModel (model, function () { + return new OV.Material (); + }); + let surface = 0.0; + let volume = 0.0; + for (let i = 0; i < model.MeshCount (); i++) { + let mesh = model.GetMesh (i); + for (j = 0; j < mesh.TriangleCount (); j++) { + let triangle = mesh.GetTriangle (j); + let v0 = mesh.GetVertex (triangle.v0); + let v1 = mesh.GetVertex (triangle.v1); + let v2 = mesh.GetVertex (triangle.v2); + surface += GetTriangleArea (v0, v1, v2); + let signedVolume = OV.DotVector3D (v0, OV.CrossVector3D (v1, v2)) / 6.0; + volume += signedVolume; + } + } + assert (OV.IsEqual (volume, 1.0)); + assert (OV.IsEqual (surface, 6.0)); + }); }); diff --git a/test/utils/testfiles.js b/test/utils/testfiles.js index 4b87c90..58f2a82 100644 --- a/test/utils/testfiles.js +++ b/test/utils/testfiles.js @@ -2,37 +2,37 @@ var testUtils = require ('./testutils.js'); module.exports = { - ImportObjFile : function (fileName) + ImportObjFile : function (fileName, onReady) { var importer = new OV.ImporterObj (); - return this.ImportFile (importer, OV.FileFormat.Text, 'obj', fileName); + this.ImportFile (importer, OV.FileFormat.Text, 'obj', fileName, onReady); }, - ImportStlFile : function (fileName) + ImportStlFile : function (fileName, onReady) { var importer = new OV.ImporterStl (); - return this.ImportFile (importer, OV.FileFormat.Binary, 'stl', fileName); + this.ImportFile (importer, OV.FileFormat.Binary, 'stl', fileName, onReady); }, - ImportOffFile : function (fileName) + ImportOffFile : function (fileName, onReady) { var importer = new OV.ImporterOff (); - return this.ImportFile (importer, OV.FileFormat.Text, 'off', fileName); + this.ImportFile (importer, OV.FileFormat.Text, 'off', fileName, onReady); }, - ImportPlyFile : function (fileName) + ImportPlyFile : function (fileName, onReady) { var importer = new OV.ImporterPly (); - return this.ImportFile (importer, OV.FileFormat.Binary, 'ply', fileName); + this.ImportFile (importer, OV.FileFormat.Binary, 'ply', fileName, onReady); }, - Import3dsFile : function (fileName) + Import3dsFile : function (fileName, onReady) { var importer = new OV.Importer3ds (); - return this.ImportFile (importer, OV.FileFormat.Binary, '3ds', fileName); + this.ImportFile (importer, OV.FileFormat.Binary, '3ds', fileName, onReady); }, - ImportGltfFile : function (folderName, fileName) + ImportGltfFile : function (folderName, fileName, onReady) { let extension = OV.GetFileExtension (fileName); let format = OV.FileFormat.Text; @@ -40,10 +40,10 @@ module.exports = format = OV.FileFormat.Binary; } var importer = new OV.ImporterGltf (); - return this.ImportFile (importer, format, 'gltf/' + folderName, fileName); + this.ImportFile (importer, format, 'gltf/' + folderName, fileName, onReady); }, - ImportFile : function (importer, format, folder, fileName) + ImportFile : function (importer, format, folder, fileName, onReady) { var content = null; if (format == OV.FileFormat.Text) { @@ -77,9 +77,17 @@ module.exports = }, getTextureBuffer : function (filePath) { return buffers.GetTextureBuffer (filePath); + }, + onSuccess : function () { + let model = importer.GetModel (); + onReady (model); + }, + onError : function () { + onReady (model); + }, + onComplete : function () { + } }); - let model = importer.GetModel (); - return model; } } diff --git a/tools/config.json b/tools/config.json index 7226b92..470cb49 100644 --- a/tools/config.json +++ b/tools/config.json @@ -1,7 +1,8 @@ { "lib_files" : [ "libs/jquery-3.5.1.min.js", - "libs/three.min-126.js" + "libs/three.min-126.js", + "libs/rhino3dm.min.js" ], "importer_files" : [ "source/core/core.js", @@ -40,6 +41,8 @@ "source/export/exporteroff.js", "source/export/exportergltf.js", "source/export/exporter.js", + "source/external/rhino.importer.js", + "source/external/rhino.exporter.js", "source/external/three.converter.js", "source/external/three.model.loader.js", "source/parameters/parameterlist.js", diff --git a/tools/create_package.py b/tools/create_package.py index fc7e663..13a4173 100644 --- a/tools/create_package.py +++ b/tools/create_package.py @@ -19,20 +19,19 @@ def GetVersion (rootDir): return packageJson['version'] def JSHintFolder (folder): - result = Tools.RunCommand (['jshint', folder]) + result = Tools.RunCommand ('jshint', [folder]) if result != 0: return False return True def CompressFiles (inputFiles, outputFile): parameters = [] - parameters.append ('google-closure-compiler') for inputFile in inputFiles: extension = os.path.splitext (inputFile)[1] if extension == '.js': parameters.append ('--js=' + os.path.join ('..', inputFile)) parameters.append ('--js_output_file=' + outputFile) - result = Tools.RunCommand (parameters) + result = Tools.RunCommand ('google-closure-compiler', parameters) if result != 0: return False return True diff --git a/tools/lib/tools_lib.py b/tools/lib/tools_lib.py index c8f8337..9951238 100644 --- a/tools/lib/tools_lib.py +++ b/tools/lib/tools_lib.py @@ -13,13 +13,9 @@ def WriteContentToFile (filePath, content): fileObject.write (content) fileObject.close () -def RunCommand (commands): - process = subprocess.Popen (commands, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True) - out, err = process.communicate () - if process.returncode != 0: - print (out.decode ()) - print (err.decode ()) - return process.returncode +def RunCommand (executable, arguments): + command = executable + ' "' + '" "'.join (arguments) + '"' + return os.system (command) class TokenReplacer: def __init__ (self, filePath, keepToken): diff --git a/tools/optimize_svg_files.py b/tools/optimize_svg_files.py index c6f7c10..33b653a 100644 --- a/tools/optimize_svg_files.py +++ b/tools/optimize_svg_files.py @@ -7,8 +7,7 @@ def Main (argv): currentDir = os.path.dirname (os.path.abspath (__file__)) os.chdir (currentDir) imagesPath = os.path.abspath (os.path.join ('..', 'website', 'assets', 'images')) - for i in range (0, 5): - Tools.RunCommand (['svgo', '-r', imagesPath]) + Tools.RunCommand ('svgo', ['-r', imagesPath]) return 0 sys.exit (Main (sys.argv)) diff --git a/tools/sandbox/embed_selfhost_fullscreen.html b/tools/sandbox/embed_selfhost_fullscreen.html index a0c9465..cbd6f19 100644 --- a/tools/sandbox/embed_selfhost_fullscreen.html +++ b/tools/sandbox/embed_selfhost_fullscreen.html @@ -45,6 +45,8 @@ + + diff --git a/tools/sandbox/embed_selfhost_multiple.html b/tools/sandbox/embed_selfhost_multiple.html index c004498..c4d18c7 100644 --- a/tools/sandbox/embed_selfhost_multiple.html +++ b/tools/sandbox/embed_selfhost_multiple.html @@ -47,6 +47,8 @@ + + diff --git a/tools/sandbox/embed_selfhost_single.html b/tools/sandbox/embed_selfhost_single.html index 19ad383..29276c2 100644 --- a/tools/sandbox/embed_selfhost_single.html +++ b/tools/sandbox/embed_selfhost_single.html @@ -45,6 +45,8 @@ + + diff --git a/website/assets/images/toolbar/embed.svg b/website/assets/images/toolbar/share.svg similarity index 100% rename from website/assets/images/toolbar/embed.svg rename to website/assets/images/toolbar/share.svg diff --git a/website/embed.html b/website/embed.html index bb8f35a..473a291 100644 --- a/website/embed.html +++ b/website/embed.html @@ -14,6 +14,7 @@ + @@ -53,6 +54,8 @@ + + diff --git a/website/index.html b/website/index.html index 18fbd47..12d81c2 100644 --- a/website/index.html +++ b/website/index.html @@ -11,6 +11,7 @@ + @@ -53,6 +54,8 @@ + + @@ -125,12 +128,12 @@
Drag and drop your 3D models here.
- Supported formats: obj, 3ds, stl, ply, gltf, glb, off. + obj, 3ds, stl, ply, gltf, glb, 3dm, off
Or you can use the browse button above.
-
+
Example models:
logo diff --git a/website/info/index.html b/website/info/index.html index 5a994b3..fa22572 100644 --- a/website/info/index.html +++ b/website/info/index.html @@ -24,7 +24,7 @@

This is the user manual for the 3dviewer.net website. The website can open several 3D file formats and visualize the model in your browser. - Supported file formats: obj, 3ds, stl, ply, gltf, glb, and off. + Supported file formats: obj, 3ds, stl, ply, gltf, glb, 3dm, and off.

    @@ -112,6 +112,13 @@ ✓ version 2.0 + + 3dm + binary + ✓ + ✓ + experimental + off text @@ -173,7 +180,7 @@

    Embedding the viewer

    The website allows you to embed a 3D model in your page. It works only if your models are hosted on a web server. - To get the embedding code, click on the embedding button () in the toolbar. + To get the embedding code, click on the share model button () in the toolbar.

    Embedding models hosted on GitHub

    @@ -191,7 +198,7 @@ https://github.com/kovacsv/Online3DViewer/blob/master/test/testfiles/3ds/texture.png
-
  • Click on OK, and if the model is loaded, click on the embed button in the toolbar ().
  • +
  • Click on OK, and if the model is loaded, click on the share button in the toolbar ().
  • @@ -210,7 +217,7 @@ https://www.dropbox.com/s/6dfk1jveevbofxm/texture.png?dl=0
    -
  • Click on OK, and if the model is loaded, click on the embed button in the toolbar ().
  • +
  • Click on OK, and if the model is loaded, click on the share button in the toolbar ().
  • diff --git a/website/o3dv/dialogs.js b/website/o3dv/dialogs.js index 2cb6822..42310f4 100644 --- a/website/o3dv/dialogs.js +++ b/website/o3dv/dialogs.js @@ -74,21 +74,31 @@ OV.ShowOpenUrlDialog = function (onOk) $('
    ').html (text).addClass ('ov_dialog_section').appendTo (contentDiv); urlsTextArea.appendTo (contentDiv); dialog.Show (); + urlsTextArea.focus (); return dialog; }; -OV.ShowEmbeddingDialog = function (importer, importSettings, camera) +OV.ShowSharingDialog = function (importer, importSettings, camera) { - function AddCheckboxLine (parentDiv, text, onChange) + function AddCheckboxLine (parentDiv, text, id, onChange) { let line = $('
    ').addClass ('ov_dialog_table_row').appendTo (parentDiv); - let check = $('').attr ('type', 'checkbox').attr ('checked', 'true').appendTo (line); - $('').html (text).appendTo (line); + let check = $('').attr ('type', 'checkbox').attr ('checked', 'true').addClass ('ov_dialog_checkradio').attr ('id', id).appendTo (line); + $('