@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
<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