UNPKG

@sohale/implisolid

Version:

A Solid Modelling Kernel in Javascript based on Implicit Surfaces, for MP5 file format

1,401 lines (1,132 loc) 50.6 kB
<html> <head> <meta charset="utf-8"/> </head> <style> .stat-panel{ position:fixed; top:0px; right:0px; width:100px; /* z-index:1000; */ } </style> <body> <canvas id="my_canvas"></canvas> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r77/three.js"></script> <!--script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r73/three.js"></script--> <!-- <script type="text/javascript" src="./three-r77.js"></script> --> <!--script type="text/javascript" src="https://raw.githubusercontent.com/mrdoob/three.js/69079243426506ed86d0d0ea71b4fdda9dbb2f88/examples/js/controls/OrbitControls.js"></script --> <!-- Refused to execute script '...' because its MIME type ('text/plain') is not executable, and strict MIME type checking is enabled. --> <!--script type="text/javascript" src="./ww_geometry77.js"></script--> <script type="text/javascript" src="./geometry77.js"></script> <script type="text/javascript" src="./controls/OrbitControls.js"></script> <script type="text/javascript" src="../js_iteration_2/bbox_calculations.js"></script> <!--<body>--> Based on MCC1 <br> <script> 'use strict'; //function d(arg){console.log(" ------- HERE "+arg );} //polygonizer_service.needs_deallocation // Exported var produce_object; var main; //var newProducer; function init_polygonizer() { //too late for pre-run //Module.preRun.push(letmeknow,memoryprofiler_add_hooks, letmeknow = function (){console.log("ok");}); //Module={preRun:[letmeknow, memoryprofiler_add_hooks]}; //main = Module.cwrap('main', 'number', []); // produce_object = Module.cwrap('produce_object_old2', null, ['number', 'number', 'number', 'number', 'number']); var newProducer={}; newProducer.build_geometry = Module.cwrap('build_geometry', null, [ 'string', 'string']); newProducer.get_v_size = Module.cwrap('get_v_size', 'number', []); newProducer.get_f_size = Module.cwrap('get_f_size', 'number', []); newProducer.get_v = Module.cwrap('get_v', null, ['number']); newProducer.get_f = Module.cwrap('get_f', null, ['number']); newProducer.get_v_ptr = Module.cwrap('get_v_ptr', 'number', []); newProducer.get_f_ptr = Module.cwrap('get_f_ptr', 'number', []); newProducer.finish_geometry = Module.cwrap('finish_geometry', null, []); newProducer.set_object = Module.cwrap('set_object', 'number', ['string', 'number']); newProducer.unset_object = Module.cwrap('unset_object', 'number', ['number']); newProducer.set_x = Module.cwrap('set_x', 'number', ['number', 'number']); newProducer.unset_x = Module.cwrap('unset_x', null, []); newProducer.calculate_implicit_values = Module.cwrap('calculate_implicit_values', null, []); newProducer.get_values_ptr = Module.cwrap('get_values_ptr', 'number', []); newProducer.get_values_size = Module.cwrap('get_values_size', 'number', []); newProducer.calculate_implicit_gradients = Module.cwrap('calculate_implicit_gradients', null, []); newProducer.get_gradients_ptr = Module.cwrap('get_gradients_ptr', 'number', []); newProducer.get_gradients_size = Module.cwrap('get_gradients_size', 'number', []); newProducer.about = Module.cwrap('about', null, []); newProducer.init = function(){ newProducer.needs_deallocation = false; } newProducer.finish_with = function (){ //after the last round. if(!polygonizer_service.needs_deallocation) console.error("cannot `finish_geometry()`. Geometry not produced."); //todo: try-catch //d(1); polygonizer_service.finish_geometry(); polygonizer_service.needs_deallocation = false; //todo(sohail): Why polygonizer_service is used here? We should use 'this'. } newProducer.set_vect = function (float32Array){ if (float32Array.length % 3 != 0) {console.error("bad input array");}; var nverts = float32Array.length / 3; var verts_space = Module._malloc(_FLOAT_SIZE*3*nverts); Module.HEAPF32.subarray(verts_space/_FLOAT_SIZE, verts_space/_FLOAT_SIZE + 3*nverts).set(float32Array); var result = this.set_x(verts_space, nverts); console.log("result: "+result); Module._free( verts_space ); } newProducer.update_geometry = function(geometry, ignoreNormals) { var implicit_service = this; const _FLOAT_SIZE = Float32Array.BYTES_PER_ELEMENT; const _INT_SIZE = Uint32Array.BYTES_PER_ELEMENT; const POINTS_PER_FACE = 3; var nverts = implicit_service.get_v_size(); var nfaces = implicit_service.get_f_size(); if(nfaces > 0){ var verts_address = implicit_service.get_v_ptr(); var faces_address = implicit_service.get_f_ptr(); var verts = Module.HEAPF32.subarray( verts_address/_FLOAT_SIZE, verts_address/_FLOAT_SIZE + 3*nverts); var faces = Module.HEAPU32.subarray( faces_address/_INT_SIZE, faces_address/_INT_SIZE + nfaces * POINTS_PER_FACE); } else{ console.log("empty implicit"); var verts = new Float32Array([0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1 ]); var faces = new Uint32Array([0,1,2, 0,2,3, 0,4,5, 0,5,1, 1,5,6, 1,6,2, 2,6,3, 3,6,7, 4,5,6, 5,6,7]); } return geometry.update_geometry1(verts, faces, ignoreNormals, false); }; newProducer.make_normals_into_geometry = function(geom, mp5_str, x, ignore_root_matrix) { implicit_service = newProducer; const _FLOAT_SIZE = Float32Array.BYTES_PER_ELEMENT; implicit_service.set_object(mp5_str, ignore_root_matrix); implicit_service.set_vect(x); // overhead implicit_service.calculate_implicit_gradients(true); // Why TRUE doe snot have any effect? var ptr = implicit_service.get_gradients_ptr(); var ptr_len = implicit_service.get_gradients_size(); var gradients = Module.HEAPF32.subarray(ptr/_FLOAT_SIZE, ptr/_FLOAT_SIZE + ptr_len); //console.log("grad len = " + ptr_len+ " grad = " + gradients); // x 4 //for( var i = 0 ; i < ptr_len; i++) { // gradients[i] += Math.random() * 0.2; //} geom.update_normals_from_array(gradients); implicit_service.unset_x(); implicit_service.unset_object(); }; newProducer.init(); //console.log("ok"); return newProducer; } </script> <script> 'use strict'; //'use asm'; //'use strict'; //Version 1 has flaws: _free()s before returning the verts. var CALL_VERSION = 2; //1 or 2 const VERBOSE = false; var WIREFRAME = false; //const DBLFLOAT_SIZE = 8; const _FLOAT_SIZE = 4; //Float32Array.BYTES_PER_ELEMENT const _INT_SIZE = 4; //int:4, float: 4, long: 4 var global_time = 0; /* old style. This leaves memory footprints (memory leak) */ function do_vf_old(subjective_time) { //var max_verts = 40000; // *2 //var max_faces = 15000; //*5 var max_verts = 16000; // *2 var max_faces = 13000; //*5 var verts_address = Module._malloc(_FLOAT_SIZE*3*max_verts); var nv_address = Module._malloc(_INT_SIZE*1); var faces_address = Module._malloc(_INT_SIZE*3*max_faces) var nf_address = Module._malloc(_INT_SIZE*1); //todo: how to make sure enough space is allocated. /* ************************* */ /* Call C++ */ produce_object(verts_address, nv_address, faces_address, nf_address, subjective_time); /* ************************* */ //Module.HEAPF64 is a Float64Array var nverts = Module.HEAPU32[nv_address/_INT_SIZE]; var nfaces = Module.HEAPU32[nf_address/_INT_SIZE]; var verts = Module.HEAPF32.subarray(verts_address/_FLOAT_SIZE, verts_address/_FLOAT_SIZE + 3*nverts); var faces = Module.HEAPU32.subarray(faces_address/_INT_SIZE, faces_address/_INT_SIZE + 3*nfaces); //what if there is not enough memory? // var result_faces = new Float32Array(dataHeap.buffer, dataHeap.byteOffset, data.length); //verts_address is byteOffset? //second attemtps: (still has problems) var result_verts = new Float32Array(Module.HEAPU32.buffer, Module.HEAPU32.byteOffset + verts_address, 3*nverts * _FLOAT_SIZE); //Thisrd solution: //http://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html var h_len = (Module.HEAPF32.length); var v_end=(verts_address/_FLOAT_SIZE + 3*nverts); var f_end = (faces_address/_INT_SIZE + 3*nfaces); if(h_len <= v_end || h_len <= f_end) console.error("Insufficient heap: "+(h_len - v_end)+ " , "+(h_len - f_end)); else console.info("Heap size OK."); //console.log(Module.HEAPF32.subarray(verts_address/_FLOAT_SIZE, verts_address/_FLOAT_SIZE + 3*2)); //console.log("subarray"); //console.log(verts.subarray(verts.length-100, verts.length)); // **************************** // The actual leak was here ! // **************************** //freeing resources //also see http://kapadia.github.io/emscripten/2013/09/13/emscripten-pointers-and-pointers.html Module._free(verts_address); Module._free(nv_address); Module._free(faces_address); Module._free(nf_address); //BUG! Accessed (returned) after "_Free"ing. // FIXME: FREED before actually copying //console.log(Module.HEAPF32.subarray(verts_address/_FLOAT_SIZE, verts_address/_FLOAT_SIZE + 3*2)); //console.log(result_verts.subarray(0, 3*2)); if(VERBOSE){ console.log("nverts : "+ nverts); console.log("nfaces : "+ nfaces); } return [verts, faces]; //return [result_verts, faces]; } // //third way: // function vf(){ // //function _produce_object($verts,$nv,$faces,$nf,$time){} // // // $verts = $verts|0; // // $nv = $nv|0; // // $faces = $faces|0; // // $nf = $nf|0; // // $time = +$time; // //$254 = $verts.. // //HEAPF32[$254>>2] = $251; // // // } function make_geometry_oldold(subjective_time, re_allocate_buffers) { var startTime = new Date(); //new Date().getTime() vf = do_vf_old(subjective_time); v = vf[0]; f = vf[1]; //This is not used //return new MyGeometry(v, f); var geom = new MyBufferGeometry77(v, f, re_allocate_buffers); var endTime = new Date(); var timeDiff = endTime - startTime; //console.log("TIME: "+timeDiff+ " msec."); report_time(timeDiff); return geom; //This is not used } 'use strict'; /** Asynchronously does a series of calls to the function update_mc(). */ var call_multiple_times = function() { // private: var last_active = 0; var intervals_counter = 0; function _call_multiple_times(polygonizer_service, update_mc) { /** Asynchronously does a series of calls to the function update_mc(). Previous name: update_mc_mul tiple() */ var BURST_COUNT = 5; // 50; var INTERVAL_MSEC = 8-1; //40 // 1 // in Milliseconds // Works well on too small values (Semaphore). // The main algorithm performs much faster when this interval is larger (>100). Becasue of `gc`. //var mc_icounter=0; var already_busy_doing_it=0; // semaphore. (Refractory). Fast x1. var burst_counter = 0; //already_busy_doing_it level1: right now. //already_busy_doing_it: interval (level 2) intervals_counter++; if(intervals_counter>1) //dont start if there is already one running { intervals_counter--; return; } last_active = setInterval ( function() { /* var ls=""; for (var lft=0;lft<100;lft++){ ls+=" "; } console.log(ls.slice(1)); console.log("1msec"); return; */ if(!last_active) console.error("!last_active"); burst_counter++; // mc_icounter if(burst_counter<BURST_COUNT) //This code is amazingly similar to Bursting dyamics in neurons. { if(already_busy_doing_it<1) //removable { already_busy_doing_it++; update_mc(polygonizer_service, 0.2/10.*5 /5. *10); if(already_busy_doing_it>1) console.error(">>>already_busy_doing_it:"+already_busy_doing_it); if(!last_active) console.error("!last_active"); already_busy_doing_it--; }else{ console.log("hit"); } } else { // The interval has finished its job. Time to go. if(!last_active) console.error("!last_active"); clearInterval(last_active); // But then don't we need to wait until the last one is finished? intervals_counter--; // Allow next one in future burst_counter = 0; last_active = 0; } }, INTERVAL_MSEC ); } return _call_multiple_times; }(); /* // MyLiveUpdatableGeometry LiveGeometry = function () { //material_wireframe = ...; THREE.THREE.ImmediateRenderObject.call( this, material_wireframe ); this.setVF = function(verts, faces){ } }; LiveGeometry.prototype = Object.create( THREE.Geometry.prototype ); LiveGeometry.prototype.constructor = LiveGeometry; */ // Keep this method, although it is not used. function make_geometry_old1(polygonizer_service, shape_json, polygonization_json, reusable_geometry, re_allocate_buffers) { var startTime = new Date(); //polygonizer_service.build_geometry( 28, mc_properties_json, "sphere", subjective_time); //polygonizer_service.build_geometry( mp5_json , mc_properties_json); polygonizer_service.build_geometry( shape_json , polygonization_json); //implicit_double_mushroom center will be zero. var nverts = polygonizer_service.get_v_size(); var nfaces = polygonizer_service.get_f_size(); if(VERBOSE){ console.log(nverts); } var verts_address = Module._malloc(_FLOAT_SIZE*3*nverts); var faces_address = Module._malloc(_INT_SIZE*3*nfaces); polygonizer_service.get_v(verts_address, nverts); polygonizer_service.get_f(faces_address, nfaces); var verts = Module.HEAPF32.subarray(verts_address/_FLOAT_SIZE, verts_address/_FLOAT_SIZE + 3*nverts); //console.log(verts); var faces = Module.HEAPU32.subarray(faces_address/_INT_SIZE, faces_address/_INT_SIZE + 3*nfaces); /* if(!reusable_geometry){ //var geom = new MyGeometry(verts, faces); //var geom = new MyBufferGeometry77(verts, faces, re_allocate_buffers); //weird results. But much faster. //best so far: var geom = new WGeometry77(verts, faces); //var geom = UpdatableGeometry77(verts, faces); }else{ geom = reusable_geometry; reusable_geometry.update(verts, faces); } */ var geom = new MyBufferGeometry77(verts, faces, re_allocate_buffers); //weird results. But much faster. // Now you can free the resources. Module._free(verts_address); Module._free(faces_address); //d(1); polygonizer_service.finish_geometry(); polygonizer_service.needs_deallocation = false; if(VERBOSE){ console.log("nverts : "+ nverts); console.log("nfaces : "+ nfaces); } var endTime = new Date(); var timeDiff = endTime - startTime; //console.log("TIME: "+timeDiff); report_time(timeDiff); return geom; } function setShapeMatrix2Eye(shape_matrix) { for(var ii=0; ii<16; ii++) { shape_matrix[0] = 0; } shape_matrix[0] = 1; shape_matrix[5] = 1; shape_matrix[10] = 1; shape_matrix[15] = 1; shape_matrix[3] = 0; shape_matrix[7] = 0; shape_matrix[11] = 0; } const MESH_SCALE = 300/10; const ARROWS_COUNT = 20; var global_mp5 = "***"; function provide_input (subjective_time, update_mode) { // update_mode: 0 => init // update_mode: 1 => update // update_mode: 2 => deprecated (used in make_geometry_old1() ) console.error("update_mode == ", update_mode); // asked for: var shape_json, polygonization_json; if( update_mode == 0) { var r = subjective_time; var mp5_json_0 = JSON.stringify({ type: "egg", //radius: subjective_time, matrix:[ r, 0,0, x0, 0,r, 0, y0, 0,0,r, z0, 0,0,0, 1] }); //global_mp5 = mp5_json_0; if(update_mode == 0) { var sz = 1.; } else { var sz = r; } var HEART = '{"printerSettings":{"name":"test","layerThickness":0.2,"emptyLayer":0,"infillSpace":4,"topThickness":0.6,"paramSamples":75,"speedRate":1000,"circleSpeedRate":1000,"temperature":220,"inAirSpeed":7000,"flowRate":0.035,"criticalLength":35,"retractionSpeed":2400,"retractionLength":5,"shellNumber":3,"material":"PLA 2.85mm","autoZScar":true,"zScarGap":0.5,"critLayerTime":6,"filamentDiameter":2.85},"mp5-version":"0.3","root":{"type":"root","children":[{"type":"Union","protected":false,"children":[{"type":"cylinder","displayColor":{"x":0.9661750055896976,"y":0.8085857086202395,"z":0.41578037212168595},"matrix":[10,0,0,-3.7368777450135866,0,10,0,-1.9559832356144682,0,0,10,1.7323194345664206e-7,0,0,0,1],"index":7575510},{"type":"cube","displayColor":{"x":0.23399071378141634,"y":0.31584816496653323,"z":0.35457351563365425},"matrix":[10,0,0,1.867397834493545,0,10,0,-1.7325527119763677,0,0,10,-9.734106853898084e-10,0,0,0,1],"index":5587759},{"type":"cylinder","displayColor":{"x":0.43814645627496795,"y":0.39556472441055845,"z":0.3415798414286939},"matrix":[10,0,0,1.8694799105200275,0,10,0,3.688535947590836,0,0,10,-1.7225853365943067e-7,0,0,0,1],"index":6657333}],"initialSize":{"x":1,"y":1,"z":1},"displayColor":{"x":0.6470588235294118,"y":0.2784313725490196,"z":0.5882352941176471},"matrix":['+sz+',0,0,82.63768850593796,0,'+sz+',0,126.37324151118989,0,0,'+sz+',5.000000079354265,0,0,0,1],"index":4872526}]}}'; var MOON = '{"printerSettings":{"name":"test","layerThickness":0.2,"emptyLayer":0,"infillSpace":4,"topThickness":0.6,"paramSamples":75,"speedRate":1000,"circleSpeedRate":1000,"temperature":220,"inAirSpeed":7000,"flowRate":0.035,"criticalLength":35,"retractionSpeed":2400,"retractionLength":5,"shellNumber":3,"material":"PLA 2.85mm","autoZScar":true,"zScarGap":0.5,"critLayerTime":6,"filamentDiameter":2.85},"mp5-version":"0.3","root":{"type":"root","children":[{"type":"Difference","protected":false,"children":[{"type":"cylinder","displayColor":{"x":0.7675997200783986,"y":0.03892568708507049,"z":0.1754374135888661},"matrix":[42.583184547062736,0,0,0,0,49.55270399250958,0,0,0,0,10,0,0,0,0,1],"index":652818},{"type":"Difference","protected":false,"children":[{"type":"cylinder","displayColor":{"x":0.8122645344236872,"y":0.657334404743416,"z":0.7357336310755096},"matrix":[10,0,0,0,0,10,0,0,0,0,10,0,0,0,0,1],"index":1272174},{"type":"cylinder","displayColor":{"x":0.11421729990684737,"y":0.07562705374348999,"z":0.6324600862122098},"matrix":[10,0,0,0.658889604636343,0,10,0,6.215549332615993,0,0,10,1.3327027659215673e-7,0,0,0,1],"index":2463576}],"initialSize":{"x":1,"y":1,"z":1},"displayColor":{"x":0.6627450980392157,"y":0.4549019607843137,"z":0.7215686274509804},"matrix":[2.381193509886417,0,0,0.3600215429489424,0,2.381193509886417,0,0.5604901669421452,0,0,2.381193509886417,6.9059681360437395,0,0,0,1],"index":413872}],"initialSize":{"x":1,"y":1,"z":1},"displayColor":{"x":0.5529411764705883,"y":0.06666666666666667,"z":0.11764705882352941},"matrix":[1,0,0,0.32938436512727,0,1,0,0.15604124684634,0,0,1,0.000000000000014,0,0,0,1],"index":6565922}]}}'; var mp5_json_tetrahedron = { type: "tetrahedron", corners: [[0, 2, 0],[0, 8, 1],[10, 1, 0],[1,1,10]], matrix:[ 1, 0,0, 0, 0,1, 0, 0, 0,0,1, 0, 0,0,0, 1] }; var mp5_json = HEART; var mp5_json_dict = JSON.parse(mp5_json).root.children[0]; //var mp5_json_dict = mp5_json_tetrahedron; /* // for heart mp5_json_dict.matrix[3]=0; mp5_json_dict.matrix[7]=0; mp5_json_dict.matrix[11]=0; */ if(false) { setShapeMatrix2Eye(mp5_json_dict.matrix); } //console.log(mp5_json_dict); //var bb = getBoundingBoxForTree(); mp5_json = JSON.stringify(mp5_json_dict); global_mp5 = mp5_json; const BB_SIZE = 9; var x0=0, y0=0, z0=0; //var BB_SIZE = 18; //const BB_SIZE = 9; var mc_properties_json = JSON.stringify({ resolution: 28, box: {xmin: x0-BB_SIZE, xmax: x0+BB_SIZE, ymin: y0-BB_SIZE , ymax: y0+BB_SIZE, zmin: z0-BB_SIZE, zmax: z0+BB_SIZE}, ignore_root_matrix: true, }); shape_json = mp5_json; polygonization_json = mc_properties_json; var tuple = [shape_json, polygonization_json]; return tuple; } //Alternatively, use a growing sphere only. if(update_mode == 1 || update_mode == 2) { //d("2 G."); var x0=0, y0=0, z0=0; const BB_SIZE = 1; var r = subjective_time; //var BB_SIZE = 6.; var mc_properties_json = JSON.stringify({ resolution: 28, box: {xmin: x0-BB_SIZE, xmax: x0+BB_SIZE, ymin: y0-BB_SIZE , ymax: y0+BB_SIZE, zmin: z0-BB_SIZE, zmax: z0+BB_SIZE} }); //polygonizer_service.build_geometry( 28, mc_properties_json, "sphere", subjective_time); var mp5_json = JSON.stringify({ type: "egg", //radius: r, //boudbl_mushroom only matrix:[ r, 0,0, x0, 0,r, 0, y0, 0,0, r, z0, 0,0,0, 1] }); console.error("r=", r); console.log(mp5_json); shape_json = mp5_json; polygonization_json = mc_properties_json; //global_mp5 = mp5_json; var tuple = [shape_json, polygonization_json]; return tuple; } /* if(update_mode == 2) { //not used anymore //console.log(polygonizer_service); //d("2 G.."); var x0=0, y0=0, z0=0; var r = subjective_time; var mc_properties_json = JSON.stringify({ resolution: 28, box: {xmin: x0-1, xmax: x0+1, ymin: y0-1 , ymax: y0+1, zmin: z0-1, zmax: z0+1} }); var mp5_json = JSON.stringify({ type: "egg", //radius: 3.0, //double_mushroom only matrix:[ r, 0,0, x0, 0,r, 0, y0, 0,0,r, z0, 0,0,0, 1] }); shape_json = mp5_json; polygonization_json = mc_properties_json; var tuple = [shape_json, polygonization_json]; return tuple; } */ } /* Three ways: 1- make_geometry_oldold() 2- make_geometry_old1() 3- make_geometry_new2() */ function make_geometry_new2(polygonizer_service, shape_json, polygonization_json, reusable_geometry, re_allocate_buffers) { //console.log(shape_json); //console.log(polygonization_json); // reusable_geometry is not used; var startTime = new Date(); if(polygonizer_service.needs_deallocation) { // Remove data from last round. //console.log("polygonizer_service.needs_deallocation " + polygonizer_service.needs_deallocation); //d(1); polygonizer_service.finish_geometry(); polygonizer_service.needs_deallocation = false; } else{ //console.error("Should not get here"); //polygonizer_service.finish_geometry(); //polygonizer_service.needs_deallocation = false; } //polygonizer_service.finish_geometry(); //d("2 G"); //28*2 --> 27 sec 28->3.75--7 msec? ////////////////////// //var mp5_json = ""; //var mc_properties_json = ""; //polygonizer_service.build_geometry( 28, mc_properties, "sphere", subjective_time); //polygonizer_service.build_geometry( mp5_json , mc_properties_json); polygonizer_service.build_geometry( shape_json , polygonization_json); //implicit_double_mushroom center will be zero. polygonizer_service.needs_deallocation = true; var nverts = polygonizer_service.get_v_size(); var nfaces = polygonizer_service.get_f_size(); if(VERBOSE){ console.log(nverts); } var verts_address = polygonizer_service.get_v_ptr(); var faces_address = polygonizer_service.get_f_ptr(); //no need to free anymore! var verts = Module.HEAPF32.subarray(verts_address/_FLOAT_SIZE, verts_address/_FLOAT_SIZE + 3*nverts); var faces = Module.HEAPU32.subarray(faces_address/_INT_SIZE, faces_address/_INT_SIZE + 3*nfaces); //verts[2] -= 0.1; //verts[2 + nverts*3-3] += 0.3; //var geom = new WGeometry77(verts, faces); var geom = new MyBufferGeometry77(verts, faces, re_allocate_buffers); if(VERBOSE){ console.log("nverts : "+ nverts); console.log("nfaces : "+ nfaces); } var endTime = new Date(); var timeDiff = endTime - startTime; //console.log("Time: "+timeDiff+ " msec."); report_time(timeDiff, function(){hist();}); return geom; } function my_assert(cond, text){if(!cond){console.error("ASSERT FAILED: "); if(text) console.log(text);}} //unload function update_reused_geometry(polygonizer_service, mp5_json, mc_properties_json, geometry) { //console.log(mp5_json); //console.log(mc_properties_json); var startTime = new Date(); //console.log(polygonizer_service.needs_deallocation); if(polygonizer_service.needs_deallocation) { // Remove data from last round. //d(1); polygonizer_service.finish_geometry(); polygonizer_service.needs_deallocation = false; } if(polygonizer_service.needs_deallocation) console.error("not deallocated."); try{ polygonizer_service.build_geometry( mp5_json , mc_properties_json); //implicit_double_mushroom center will be zero. polygonizer_service.needs_deallocation = true; }catch(err){ console.error("An error occured during MCC C++") console.info(err); }finally { } // geometry. update_geometry (polygonizer_service); polygonizer_service. update_geometry (geometry); var endTime = new Date(); var timeDiff = endTime - startTime; //console.log(nv3 + " , " + nf3); //console.log("Time: "+timeDiff+ " msec."); report_time(timeDiff); } 'use strict'; //*************** Arrow Functions **************************** function make_arrow(){ /** * Create an arrow and add it to the scene. */ var dir = new THREE.Vector3( 10, 4, 0); var origin = new THREE.Vector3(0, 0, 0); var length = 10; var hex = 0xffff00; var arrowHelper = new THREE.ArrowHelper(dir, origin, length, hex); scene.add(arrowHelper); console.log("Arrow"); return arrowHelper; } function make_multiple_arrows(n) { /** * Create an arrow and add it to the scene. */ var arrowHelpers = []; for(var i=0;i<n;i++) { var dir = new THREE.Vector3( 10, 4, 0); var origin = new THREE.Vector3(0, 0, 0); var length = 10; var hex = 0xffff00; var arrowHelper = new THREE.ArrowHelper(dir, origin, length, hex); scene.add(arrowHelper); arrowHelpers.push(arrowHelper); console.log("Arrow"); } return arrowHelpers; } function change_arrows(arrows, polygonizer_service, mp5_str, n, ignore_root_matrix) { /** * Update the arrow parameters */ var vlist = []; for(var i=0;i<n;i++) { var x = MESH_SCALE*10 * (Math.random()*2 - 1.); var y = MESH_SCALE*10 * (Math.random()*2 - 1.); var z = MESH_SCALE*10 * (Math.random()*2 - 1.); vlist.push(x); vlist.push(y); vlist.push(z); } //var _verts = new Float32Array([x, y, z]); var _verts = new Float32Array(vlist); polygonizer_service.set_object(mp5_str, ignore_root_matrix); polygonizer_service.set_vect(_verts); polygonizer_service.calculate_implicit_gradients(); var ptr = polygonizer_service.get_gradients_ptr(); var ptr_len = polygonizer_service.get_gradients_size(); var g = Module.HEAPF32.subarray(ptr/_FLOAT_SIZE, ptr/_FLOAT_SIZE + ptr_len); //console.log("grad len = " + ptr_len+ " grad = " + g); // x 4 var dir = null; for(var i=0;i<n;i++) { //if not bush var x = _verts[i*3 + 0]; var y = _verts[i*3 + 1]; var z = _verts[i*3 + 2]; var gx = g[i*3 + 0]; var gy = g[i*3 + 1]; var gz = g[i*3 + 2]; //polygonizer_service.unset_x(); //polygonizer_service.unset_object(); //console.log("*****************************************") //console.log(arrow.position); //console.log("*****************************************") //arrow.setLength(200*Math.random()); var l = Math.sqrt(gx*gx + gy*gy + gz*gz); //l = l * 100/10000; //console.log("l: "+l); var ls = MESH_SCALE*1.5; arrows[i].position.set(x, y, z); arrows[i].setLength(ls); // This can easily get broken. i.e. by multiplying ls. dir = new THREE.Vector3( -gx/l, -gy/l, -gz/l); arrows[i].setDirection(dir); //console.log("change_arrow"); } polygonizer_service.unset_x(); polygonizer_service.unset_object(); } // ************************************************************** // global variables for meshes that are accessed and updated in the render loop, etc. var mesh_solid; var mesh2_tiny_box_wireframe; var materials_list; //, material_f; var material_wireframe; var mesh_wireframe = null; //var last_geometry = null; var global_arrows; const CHOSEN_MATERIAL_INDEX = 7; //3; //1: grayscale boring phong. //2: faceted. (good for debug / shape study) //3: colorful //4: semi opaque (good for debug / shape study) //6: striped //7: rainbow //8 is wireframe //9: plain white? //10: changing peach //11: changing cyan var chosen_matrial; const SHOW_WIREFRAME = true; const SHOW_SOLID = true; function init_scene(polygonizer_service, shape_json, polygonization_json) { scene = new THREE.Scene(); //var WIDTH = 300, HEIGHT = 300; var WIDTH = window.innerWidth, HEIGHT = window.innerHeight - 200; //for memory profiler camera = new THREE.PerspectiveCamera( 75, WIDTH / HEIGHT, 1, 10000 ); camera.position.z = 1000; materials_list = look_nice(scene); chosen_matrial = materials_list[CHOSEN_MATERIAL_INDEX]; //chosen_matrial = new THREE.MeshBasicMaterial( { // color: 0xaaffff, wireframe: false, opacity:0.5, transparent: true, // side:THREE.DoubleSide } ); //THREE.FrontSide or THREE.BackSide or THREE.DoubleSide. material_wireframe = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true, opacity:0.3, transparent: true,} ); // //if(delta_t === undefined) // var delta_t = 0.2; // // Subjective time! // global_time += delta_t; var geometry = null; //geometry = new THREE.BoxGeometry( 200, 200, 200 ); if(CALL_VERSION==1){ //geometry = make_geometry_oldold(global_time); geometry = make_geometry_oldold(shape_json, polygonization_json); } else{ /* for make_geometry_old1() only: var tuple = provide_input(subjective_time, 2); shape_json = tuple[0]; polygonization_json = tuple[1]; // //geometry = make_geometry_old1(polygonizer_service, global_time, polygonization_json, null); geometry = make_geometry_old1(polygonizer_service, shape_json, null); //keep this comment */ //geometry = make_geometry_new2(polygonizer_service, global_time, null, true); geometry = make_geometry_new2(polygonizer_service, shape_json, polygonization_json, null, true); } //last_geometry = geometry; if(SHOW_WIREFRAME){ mesh_wireframe = new THREE.Mesh( geometry, material_wireframe ); mesh_wireframe.position.set( 0, 0, 0 ); mesh_wireframe.scale.set( MESH_SCALE, MESH_SCALE, MESH_SCALE ); scene.add( mesh_wireframe ); } //this.fromBufferGeometry( new THREE.SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) ); //material_f = new THREE.MeshBasicMaterial( { color: 0xffffff, wireframe: false, opacity:0.4, transparent: true } ); if(SHOW_SOLID){ //mesh_solid = new THREE.Mesh( geometry, material_f ); //nice ones: 2, 3, (checked until 4) mesh_solid = new THREE.Mesh( geometry, chosen_matrial ); mesh_solid.position.set( 0, 0, 0 ); mesh_solid.scale.set( MESH_SCALE, MESH_SCALE, MESH_SCALE ); scene.add( mesh_solid ); } var geo2 = new THREE.BoxGeometry( 20, 20, 20 ); mesh2_tiny_box_wireframe = new THREE.Mesh( geo2, material_wireframe ); mesh2_tiny_box_wireframe .position.set( 0, 0, 0 ); scene.add( mesh2_tiny_box_wireframe ); //mesh2_tiny_box_wireframe .scale.set( 10, 10, 10 ); var dirLight = new THREE.DirectionalLight(0xffffff, 1); dirLight.position.set(100, 100, 50); scene.add(dirLight); //var arrow = make_arrow(); //global_arrow = arrow; var arrows = make_multiple_arrows(ARROWS_COUNT); global_arrows = arrows; if(VERBOSE){ console.log("RENDERER"); } var render_canvas = document.getElementById( 'my_canvas' ); console.log(render_canvas); renderer = new THREE.WebGLRenderer( { antialias: true, canvas: render_canvas } ); //renderer.setSize( window.innerWidth, window.innerHeight ); renderer.setSize( WIDTH, HEIGHT ); document.body.appendChild( renderer.domElement ); /* function call_multiple_times() { var mc_icounter=0; setInterval(function(){ if(mc_icounter<10) update_mc(polygonizer_service, 0.2/10.*5); mc_icounter++; }, 30); } */ function doKeyDownListener(event) { if ( event.keyCode == 17 ) { //update_mc(polygonizer_service); call_multiple_times(polygonizer_service, update_mc); //change_arrow(arrow, polygonizer_service, global_mp5); } else console.log(event.keyCode); } window.addEventListener( "keydown", doKeyDownListener, false ); // keydown keypress // CONTROLS //see https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_teapot.html var cameraControls = new THREE.OrbitControls( camera, renderer.domElement ); cameraControls.target.set( 0, 0, 0 ); cameraControls.addEventListener( 'change', function () {;} ); } function update_mc(polygonizer_service, delta_t){ if(delta_t === undefined) delta_t = 0.2; // Subjective time! global_time += delta_t; var tuple = provide_input(global_time, 1); var shape_json = tuple[0]; var polygonization_json = tuple[1]; //Three modes of speed here for (UPDATE_SAME_GEOM_OBJECT, EVEN_REUSE_MESH_OBJECT): // (false, false) // Creates a new Geometry object at each loop iteration. // (true, false) // Keeps geometry object instance // (true, true) // Keeps mesh instance (as well as geometry) var UPDATE_SAME_GEOM_OBJECT = true; //Will not even call the constructor var EVEN_REUSE_MESH_OBJECT = true; if( EVEN_REUSE_MESH_OBJECT && ! UPDATE_SAME_GEOM_OBJECT) console.error("Wrong condition."); if(SHOW_SOLID){ var p1 = [mesh_solid.position, mesh_solid.rotation]; } if(SHOW_WIREFRAME){ var p2 = [mesh_wireframe.position, mesh_wireframe.rotation]; } // g i.e. actual_current_active_geom var g = null; if(SHOW_SOLID){ g = mesh_solid.geometry; } if(SHOW_WIREFRAME){ g = mesh_wireframe.geometry; } my_assert(g, "SHOW_SOLID and SHOW_WIREFRAME cannot be both false."); if(!EVEN_REUSE_MESH_OBJECT){ if(SHOW_SOLID){ scene.remove(mesh_solid); } if(SHOW_WIREFRAME){ scene.remove(mesh_wireframe); } } var reused_last_geom = g; //Not sure about the condision if(!UPDATE_SAME_GEOM_OBJECT){ if(SHOW_SOLID){ g.dispose(); g = null; // reused_last_geom is not null and will remain. It is not recommended to use reused_last_geom. } //mesh_wireframe.geometry.dispose(); // Don't do it twice! } // var reused_last_geom = g; if(!EVEN_REUSE_MESH_OBJECT){ mesh_solid = null; mesh_wireframe = null; } var geometry = null; if(UPDATE_SAME_GEOM_OBJECT) { geometry = g; //update_reused_geometry(polygonizer_service, global_time, geometry); update_reused_geometry(polygonizer_service, shape_json, polygonization_json, geometry); } else { if(CALL_VERSION==1){ //geometry = make_geometry_oldold(global_time); geometry = make_geometry_oldold(shape_json, polygonization_json); } else{ //reused_last_geom = null; //geometry = make_geometry_new2(polygonizer_service, global_time, reused_last_geom, false); //geometry = make_geometry_new2(polygonizer_service, global_time, null, false); //FALSE?? //geometry = make_geometry_new2(polygonizer_service, global_time, null, false); //FALSE?? geometry = make_geometry_new2(polygonizer_service, shape_json, polygonization_json, null, false); //FALSE?? } }; /* ""; for(var i=0;i<10*3;i++){ //geometry.attributes.position.setXYZ( i, x, y, z ); geometry.attributes.position.array[i] += 0.0002 * (i% 2); //geometry.index.array[ i ] += (i % 2)*40 ; var nverts = geometry.attributes.position.count/3; geometry.index.array[ i ] = (geometry.index.array[ i ] % (nverts)); } //geometry.attributes.position.needsUpdate = true; //geometry.index.needsUpdate = true; ""; */ var ignore_root_matrix = false; //change_arrow(global_arrow, polygonizer_service, global_mp5); change_arrows(global_arrows, polygonizer_service, global_mp5, ARROWS_COUNT, ignore_root_matrix); if(!EVEN_REUSE_MESH_OBJECT){ if(SHOW_WIREFRAME){ mesh_wireframe = new THREE.Mesh( geometry, material_wireframe ); mesh_wireframe.scale.set( MESH_SCALE, MESH_SCALE, MESH_SCALE ); //copy so that we dont lose the rotation, position of the meshes. mesh_wireframe.position.copy(p2[0]); mesh_wireframe.rotation.copy(p2[1]); scene.add( mesh_wireframe ); } /*var material1 = new THREE.MeshPhongMaterial( { color: 0xaaaaaa, specular: 0xffffff, shininess: 250, side: THREE.DoubleSide, vertexColors: THREE.VertexColors } ); mesh_solid = new THREE.Mesh( geometry, material1 ); */ if(SHOW_SOLID){ mesh_solid = new THREE.Mesh( geometry, chosen_matrial ); // //mesh_solid.position.set( 0, 0, 0 ); mesh_solid.scale.set( MESH_SCALE, MESH_SCALE, MESH_SCALE ); mesh_solid.position.copy(p1[0]); mesh_solid.rotation.copy(p1[1]); scene.add( mesh_solid ); } } } /** Stuff to make things look pretty. Taken from http://threejs.org/examples/#webgl_materials */ function generateTexture() { var canvas = document.createElement( 'canvas' ); //var canvas = document.getElementById( 'my_canvas' ); canvas.width = 256; canvas.height = 256; var context = canvas.getContext( '2d' ); var image = context.getImageData( 0, 0, 256, 256 ); var x = 0, y = 0; for ( var i = 0, j = 0, l = image.data.length; i < l; i += 4, j ++ ) { x = j % 256; y = x == 0 ? y + 1 : y; image.data[ i ] = 255; image.data[ i + 1 ] = 255; image.data[ i + 2 ] = 255; image.data[ i + 3 ] = Math.floor( x ^ y ); } context.putImageData( image, 0, 0 ); return canvas; } function look_nice(scene){ var materials = []; // Grid var line_material = new THREE.LineBasicMaterial( { color: 0x303030 } ); var _geometry = new THREE.Geometry(); var floor = -75, step = 25; for ( var i = 0; i <= 40; i ++ ) { _geometry.vertices.push( new THREE.Vector3( - 500, floor, i * step - 500 ) ); _geometry.vertices.push( new THREE.Vector3( 500, floor, i * step - 500 ) ); _geometry.vertices.push( new THREE.Vector3( i * step - 500, floor, -500 ) ); _geometry.vertices.push( new THREE.Vector3( i * step - 500, floor, 500 ) ); } var grid_lines = new THREE.LineSegments( _geometry, line_material ); scene.add( grid_lines ); // Materials var texture = new THREE.Texture( generateTexture() ); texture.needsUpdate = true; materials.push( new THREE.MeshLambertMaterial( { map: texture, transparent: true } ) ); materials.push( new THREE.MeshLambertMaterial( { color: 0xdddddd, shading: THREE.FlatShading } ) ); materials.push( new THREE.MeshPhongMaterial( { color: 0xdddddd, specular: 0x009900, shininess: 30, shading: THREE.FlatShading } ) ); materials.push( new THREE.MeshNormalMaterial( ) ); materials.push( new THREE.MeshBasicMaterial( { color: 0xffaa00, transparent: true, blending: THREE.AdditiveBlending } ) ); //materials.push( new THREE.MeshBasicMaterial( { color: 0xff0000, blending: THREE.SubtractiveBlending } ) ); materials.push( new THREE.MeshLambertMaterial( { color: 0xdddddd, shading: THREE.SmoothShading } ) ); materials.push( new THREE.MeshPhongMaterial( { color: 0xdddddd, specular: 0x009900, shininess: 30, shading: THREE.SmoothShading, map: texture, transparent: true } ) ); materials.push( new THREE.MeshNormalMaterial( { shading: THREE.SmoothShading, //opacity:0.5, transparent: true, side:THREE.DoubleSide } )); materials.push( new THREE.MeshBasicMaterial( { color: 0xffaa00, wireframe: true } ) ); materials.push( new THREE.MeshDepthMaterial() ); materials.push( new THREE.MeshLambertMaterial( { color: 0x666666, emissive: 0xff0000, shading: THREE.SmoothShading } ) ); materials.push( new THREE.MeshPhongMaterial( { color: 0x000000, specular: 0x666666, emissive: 0xff0000, shininess: 10, shading: THREE.SmoothShading, opacity: 0.9, transparent: true } ) ); materials.push( new THREE.MeshBasicMaterial( { map: texture, transparent: true } ) ); return materials; } var time_queue = []; var time_queue__last_timeout = 0; function report_time(time_msec, callback){ time_queue.push(time_msec); if(time_queue__last_timeout){ clearTimeout(time_queue__last_timeout); time_queue__last_timeout = 0; } time_queue__last_timeout = setTimeout(function(){ console.log("Time: (msec)"); console.log(time_queue); if(callback) callback(); time_queue = []; time_queue__last_timeout =0; }, 1000); } function animate() { requestAnimationFrame( animate ); //Updating the meshes var SPEED = 3. / 100; if(mesh_wireframe){ mesh_wireframe.rotation.x += 0.01*SPEED; mesh_wireframe.rotation.y += 0.02*SPEED; } if(mesh_solid){ mesh_solid.rotation.x += 0.01*SPEED; mesh_solid.rotation.y += 0.02*SPEED; } mesh2_tiny_box_wireframe .rotation.z += 0.01*SPEED; mesh2_tiny_box_wireframe .rotation.y += 0.02*SPEED; //Updating the matrials //material update callback //materials_list[ materials_list.length - 2 ].emissive.setHSL( 0.54, 1, 0.35 * ( 0.5 + 0.5 * Math.sin( 35 * global_time / 20. ) ) ); //materials_list[ materials_list.length - 3 ].emissive.setHSL( 0.04, 1, 0.35 * ( 0.5 + 0.5 * Math.cos( 35 * global_time / 20.) ) ); renderer.render( scene, camera ); } var scene, camera, renderer; //var geometry; //var polygonizer_service; //no longer global. Hopefully does not affect the performance. window.setTimeout( // function() { // var polygonizer_service = init_polygonizer(); // init_scene(polygonizer_service); // animate(); // }, 3000); </script> <!--script type="text/javascript" src="wwexample1.js"></script--> <script type="text/javascript"> if(0){ //worker example if (window.Worker) { var myWorker = new Worker("wwexample1.js"); myWorker.postMessage({a:3, b:6}); myWorker.postMessage({a:8, b:9}); myWorker.onmessage = function(e) { console.log('I received this from worker'); //console.log(e); console.log(e.data); /* bubbles : false cancelBubble : false cancelable : false currentTarget : Worker data : Object defaultPrevented : false eventPhase : 0 isTrusted : true isTrusted : true lastEventId : "" origin : "" path : Array[0] ports : Array[0] returnValue : true source : null srcElement : Worker target : Worker timeStamp : 1555.6200000000001 type : "message" */ } } else{ console.warning("Your browser does not support WebWorkers. See http://stackoverflow.com/questions/4739916/what-browsers-currently-support-web-workers "); } } </script> <!-- Graph --> <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> <!--<div id="chart_div" style="width: 900px; height: 500px;"></div>--> <script> var ggraph = 0; function show_hist(data_array){ if(ggraph==0){ add_graph_div(); google.charts.load("current", {packages:["corechart"]}); } google.charts.setOnLoadCallback(drawChart); function drawChart() { var data = google.visualization.arrayToDataTable(data_array); var options = { title: 'Time ( Milliseconds )', legend: { position: 'none' }, colors: ['#e7711c'], histogram: { bucketSize: 1, //maxNumBuckets: 200, //minValue: -1, //maxValue: 200 }, //chartArea: { width: 401 }, hAxis: { //ticks: [-1, 0,1,2,3,4,5,6,7,8,9,10,12,14,20,30,40,50,60,80,100,120,140,160,180,200], //ticks: [ -1, 0,1,2,3,4,5,6,7,8,9,10,11,12 ], //Array.from(Array(10).keys()) //[...Array(10).keys()] ticks: (Array.from(Array(30*1.).keys())).map(function(x){return x/1.;}, Number), }, //vAxis: { scaleType: 'mirrorLog' } }; //see https://developers.google.com/chart/interactive/docs/gallery/histogram#controlling-buckets var div_element = document.getElementById('chart_div'); console.log(div_element); var chart = new google.visualization.Histogram(div_element); chart.draw(data, options); } ggraph++; } var global_histogram_accumulator = []; function hist_delayed() { var a = time_queue; //var q = []; if(global_histogram_accumulator.length==0){ global_histogram_accumulator.push(["Time"]); } var UPPER_BOUND = 12; for(var i=0;i<a.length;i++){ if(a[i]<=UPPER_BOUND) global_histogram_accumulator.push([a[i]*1.]); //The precision of the timing is 1 msec :( } show_hist(global_histogram_accumulator); } function hist(){ //hist_delayed(); } //setTimeout(function()}{ function add_graph_div(){ //<div id="chart_div" style="width: 900px; height: 500px;"></div> //var elemDiv = document.createElement('div'); //document.body.appendChild(elemDiv); //not nice: //document.body.innerHTML += "<div id=\"chart_div\" style=\"width: 900px; height: 500px;\"></div>"; } </script> <!-- To show the histogram: Uncomment the following <div> to reveal the histogram graph, also uncomment the line that says: //hist_delayed(); --> <div id="chart_div" class="stat-panel" no_style="width: 900px; height: 500px;"> </div> <script> // The code that runs immediately after finishing loading of the Emscripten-generated js. function set_off() { console.log("ready."); var polygonizer_service = init_polygonizer(); //if(delta_t === undefined) var delta_t = 0.2; // Subjective time! global_time += delta_t; var tuple = provide_input(global_time, 0); var shape_json = tuple[0]; var polygonization_json = tuple[1]; init_scene(polygonizer_service, shape_j