Changeset 22434


Ignore:
Timestamp:
02/20/18 16:27:26 (7 years ago)
Author:
dlcheng
Message:

CHG (JS): Updating js scripts.

Location:
issm/trunk-jpl/src/m/plot
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • issm/trunk-jpl/src/m/plot/applyoptions.js

    r21911 r22434  
    6161                        //}}}
    6262                        //{{{ Draw colorbar gradient
     63                        var position;
     64                        var offset = 1 / (colorbar.length - 1) / 2;
     65                        var scaling = 1 - 2 * offset;
    6366                        for (var i=0; i < colorbar.length; i++) {
    6467                                color = colorbar[colorbar.length-i-1];
    6568                                color = [Math.round(color[0]*255), Math.round(color[1]*255), Math.round(color[2]*255)];
    66                                 cgradient.addColorStop(i/colorbar.length*(cdivisions/(cdivisions+1.0))+(1.0/(cdivisions+1.0)),'rgba('+color.toString()+', 1.0)');
     69                                position = (i / (colorbar.length - 1) * scaling) + offset;
     70                                cgradient.addColorStop(position, 'rgba(' + color.toString() + ', 1.0)');
    6771                        }
    6872                        ccontext.fillStyle=cgradient;
     
    119123        tcontext = tcanvas.getContext('2d');
    120124        tgradient = tcontext.createLinearGradient(0, 0, 0, 256);
    121 
     125       
    122126        var cmap = options.getfieldvalue('colormap','jet');
    123127        var colorbar = colorbars[cmap];
    124         for (var i=0; i < colorbar.length; i++) {
    125                 color = colorbar[colorbar.length-i-1];
    126                 color = [Math.round(color[0]*255), Math.round(color[1]*255), Math.round(color[2]*255)];
    127                 tgradient.addColorStop(i/colorbar.length,'rgba('+color.toString()+', 1.0)');
     128        for (var i = 0; i < colorbar.length; i++) {
     129                color = colorbar[colorbar.length - i - 1];
     130                color = [Math.round(color[0] * 255), Math.round(color[1] * 255), Math.round(color[2] * 255)];
     131                tgradient.addColorStop(i / (colorbar.length - 1), 'rgba(' + color.toString() + ', 1.0)');
    128132        }
    129 
    130133        tcontext.fillStyle = tgradient;
    131134        tcontext.fillRect(0, 0, 256, 256);
     135       
     136        //Allow for special texture colors, drawing each color in equal width vertical rectangles. The last rectanglar section is reserved for the colormap.
     137        if (options.exist('maskregion')) {
     138                var maskObject = options.getfieldvalue('maskregion',{'enabled':false});
     139                if (maskObject.enabled && !VESL.Helpers.isEmptyOrUndefined(maskObject.colors)) {
     140                        var x = 0;
     141                        var sections = Object.keys(maskObject.colors).length + 1;
     142                        var size = 256;
     143                        var width = Math.floor(1 / sections * size);
     144                        for (var color in maskObject.colors) {
     145                                tcontext.fillStyle = maskObject.colors[color];
     146                                tcontext.fillRect(x++ * width, 0, width, size);
     147                        }
     148                }
     149        }
     150       
    132151        tURL = tcanvas.toDataURL();
    133         canvas.unitNode.texture = initTexture(canvas.gl, tURL);
     152        if (options.getfieldvalue('clf','on')=='off') {
     153                canvas.nodes['unit' + (Object.keys(canvas.nodes).length - 1)].texture = initTexture(canvas.gl, tURL);
     154        } else {
     155                canvas.nodes.unit.texture = initTexture(canvas.gl, tURL);
     156        }
    134157        //}}}
    135158        //{{{ text display
    136159        var overlaycanvasid = options.getfieldvalue('overlayid', options.getfieldvalue('canvasid')+'-overlay');
    137160        var overlaycanvas = $('#'+overlaycanvasid)[0];
    138         if (!isEmptyOrUndefined(overlaycanvas)) {
     161        if (!VESL.Helpers.isEmptyOrUndefined(overlaycanvas)) {
    139162                //Get drawing context and save reference on main WebGL canvas
    140163                var ctx = overlaycanvas.getContext('2d');
     
    216239                                // function declared in slr-gfm sim-front-end-controller.js
    217240                                // if labels are behind the globe sphere then skip iteartion and do not display them
    218                                 if (isLabelVisible(textLabel)) {
     241                                if (VESL.UI.isLabelVisible(textLabel)) {
    219242                                        //Transform from world space to viewport space
    220243                                        var screenPoint = vec3.transformMat4(vec3.create(), textLabel.position, canvas.camera.vpMatrix);
     
    272295                        if ('sky' === renderObject && !('sky' in canvas.nodes)) {
    273296                                var mesh = GL.Mesh.icosahedron({size: 6371000 * canvas.atmosphere.scaleHeight, subdivisions: 5});
    274                                 var texture = initTexture(gl, canvas.rootPath + 'textures/TychoSkymapII_t4_2k.jpg');
     297                                var texture = initTexture(gl, canvas.assetsPath + '/textures/TychoSkymapII_t4_2k.jpg');
    275298                                node = new Node(
    276299                                        'canvas', canvas,
     
    287310                        if ('space' === renderObject && !('space' in canvas.nodes)) {
    288311                                var mesh = GL.Mesh.sphere({size: 6371000 * 20});
    289                                 var texture = initTexture(gl, canvas.rootPath + 'textures/TychoSkymapII_t4_2k.jpg');
     312                                var texture = initTexture(gl, canvas.assetsPath + '/textures/TychoSkymapII_t4_2k.jpg');
    290313                                node = new Node(
    291314                                        'canvas', canvas,
     
    301324                                );
    302325                        }
    303                         if ('coastlines' === renderObject && !('coastlines' in canvas.nodes)) {
     326                        if ('coastlines' === renderObject) {
    304327                                node = new Node(
    305328                                        'canvas', canvas,
     
    352375                                        'shaderName', 'Colored',
    353376                                        'drawMode', gl.LINES,
     377                                        'diffuseColor', [1.0, 0.0, 0.0, 1.0],
    354378                                        'lineWidth', options.getfieldvalue('linewidth', 1),
    355379                                        'scale', [object.scale, object.scale, object.scale],
     
    390414                        if ('clouds' === renderObject && !('clouds0' in canvas.nodes)) {
    391415                                //clouds                               
    392                                 var mesh = GL.Mesh.fromURL(canvas.rootPath+'obj/cloud.obj');
     416                                var mesh = GL.Mesh.fromURL(canvas.assetsPath + '/obj/cloud.obj');
    393417                                for (var i = 0; i < object.quantity; i++) {
    394418                                        //TODO: More options, less magic numbers. Add animation. Better shading.
    395                                         var offset = [  translation[0] + (Math.random() - 0.5) * 2 * object.range,
    396                                                                         translation[1] + object.height + (Math.random() - 0.5) * 0.2 * object.range,
    397                                                                         translation[2] + (Math.random() - 0.5) * 2 * object.range];
     419                                        var offset = [randomizeAxis(translation[0], object.range),
     420                                                                                                randomizeCloudHeight(translation[1], object),
     421                                                                                                randomizeAxis(translation[2], object.range)];
     422                                        var randomSize = randomizeCloudSize(object.scale);
     423                                        var randomColor = randomizeCloudColor();
    398424                                        node = new Node(
    399425                                                'canvas', canvas,
     
    402428                                                'name', 'clouds' + i,
    403429                                                'shaderName', 'ColoredDiffuse',
    404                                                 'animation', {'time': Date.now(),'target': translation,'current': translation},
    405                                                 'diffuseColor', [0.7,0.7,0.7,1.0],
    406                                                 'specularColor', [0.0,0.0,0.0,1.0],
     430                                                'diffuseColor', [randomColor, randomColor, randomColor, 1.0],
     431                                                'specularColor', [0.1, 0.1, 0.1, 1.0],
    407432                                                'mesh', mesh,
    408                                                 'scale', [object.scale, object.scale, object.scale],
     433                                                'scale', [randomSize, randomSize, randomSize],
    409434                                                'translation', offset
    410435                                        );
     
    414439        } //}}}
    415440} //}}}
     441
     442function randomizeCloudHeight(canvasGroundHeight, object) {
     443                // -+7000 seems a reasonable range
     444                var maxHeight = object.height + 7000;
     445                var minHeigth = object.height - 7000;
     446                var randomHeight = (Math.random() * (maxHeight - minHeigth)) + minHeigth;
     447               
     448                return canvasGroundHeight + randomHeight;
     449}
     450
     451// assumes that originAxisValue is the mid-value between min and max.
     452function randomizeAxis(originAxisValue, range) {
     453                return originAxisValue + (Math.random() - 0.5) * (range * 2);
     454}
     455
     456function randomizeCloudSize(scale) {
     457        var maxResize = 1.3;
     458        var minResize = 0.5;
     459        var randomizationFactor = Math.random() * (maxResize - minResize) + minResize;
     460        return scale * randomizationFactor;
     461}
     462
     463function randomizeCloudColor() {
     464        var lighestColor = 1;
     465        var darkestColor = 0.9;
     466        var randomColor = Math.random() * (lighestColor - darkestColor) + darkestColor;
     467        return randomColor;
     468}
  • issm/trunk-jpl/src/m/plot/plot_mesh.js

    r21911 r22434  
    3131        }
    3232        else {
    33                 vertices = Node.prototype.scaleVertices(md, x, y, z, elements, options.getfieldvalue('heightscale', 1), options.getfieldvalue('maskscale',{}));
     33                vertices = Node.prototype.scaleVertices(md, x, y, z, elements, options.getfieldvalue('heightscale', 1), options.getfieldvalue('maskregion',{'enabled':false}));
    3434                scale = [1, 1, 1];
    3535        }
  • issm/trunk-jpl/src/m/plot/plot_overlay.js

    r21911 r22434  
    4141        }
    4242        else {
    43                 vertices = Node.prototype.scaleVertices(md, x, y, z, elements, options.getfieldvalue('heightscale', 1), options.getfieldvalue('maskscale',{}));
     43                vertices = Node.prototype.scaleVertices(md, x, y, z, elements, options.getfieldvalue('heightscale', 1), options.getfieldvalue('maskregion',{'enabled':false}));
    4444                scale = [1, 1, 1];
    4545        }
  • issm/trunk-jpl/src/m/plot/plot_quiver.js

    r21911 r22434  
    77        //   See also: PLOTMODEL, PLOT_MANAGER
    88
     9        //Disabling for now, since quivers are "sticky" - once turned on, they won't turn off. This is due to cachenodes, but should find better way to handle it.
     10        return;
     11       
    912        if ('quiver' in  canvas.nodes && noCacheNodesOverride && options.getfieldvalue('cachenodes','on') === 'on') return;
    1013       
     
    2629
    2730        //Only displaying velocity fields for now
    28         var v = isEmptyOrUndefined(md.results) ?  md.initialization.vel : md.results[canvas.animation.frame].Vel;
    29         var vx = isEmptyOrUndefined(md.results) ? md.initialization.vx : md.results[canvas.animation.frame].Vx;
    30         var vy = isEmptyOrUndefined(md.results) ? md.initialization.vy : md.results[canvas.animation.frame].Vy;
     31        var v = VESL.Helpers.isEmptyOrUndefined(md.results) ?  md.initialization.vel : md.results[canvas.animation.frame].Vel;
     32        var vx = VESL.Helpers.isEmptyOrUndefined(md.results) ? md.initialization.vx : md.results[canvas.animation.frame].Vx;
     33        var vy = VESL.Helpers.isEmptyOrUndefined(md.results) ? md.initialization.vy : md.results[canvas.animation.frame].Vy;
    3134
    3235        //Handle heightscale
     
    3740        }
    3841        else {
    39                 vertices = Node.prototype.scaleVertices(md, x, y, z, elements, options.getfieldvalue('heightscale', 1), options.getfieldvalue('maskscale',{}));
     42                vertices = Node.prototype.scaleVertices(md, x, y, z, elements, options.getfieldvalue('heightscale', 1), options.getfieldvalue('maskregion',{'enabled':false}));
    4043                scale = [1, 1, 1];
    4144        }
  • issm/trunk-jpl/src/m/plot/plot_transient_movie.js

    r21768 r22434  
    2121                for (var i in steps) {
    2222                        dataresults = processdata(md, data[i], options);
    23                         range[1] = Math.min(range[0], ArrayMin(dataresults[0]));
    24                         range[2] = Math.max(range[1], ArrayMax(dataresults[0]));
     23                        range[0] = Math.min(range[0], ArrayMin(dataresults[1]));
     24                        range[1] = Math.max(range[1], ArrayMax(dataresults[1]));
    2525                }
    2626                datatype = dataresults[1];
     
    3131        //Create unit node if it does not already exist
    3232        if (!('unit' in canvas.nodes)) {
    33                 var     dataresults = processdata(md, data[i],options);
     33                var     dataresults = processdata(md, data[0],options);
    3434                var     data2 = dataresults[0];
    3535                var     datatype = dataresults[1];
     
    3939        }
    4040       
    41         //display movie
     41        //Setup rendering node
    4242        var node = canvas.nodes.unit;
    4343        node.options = options;
     
    4646        node.enabled = options.getfieldvalue('nodata', 'off') == 'off';
    4747        node.log = options.getfieldvalue('log', false);
    48         canvas.unitMovieData = data;
     48       
     49        //process data
     50        var     dataresults;
     51        var processedData = [];
     52        for (var i in steps) {
     53                dataresults = processdata(md, data[i].slice(), options);
     54                processedData[i] = dataresults[0];
     55        }
     56       
     57        //display movie
     58        canvas.unitMovieData = processedData;
    4959        canvas.animation.frame = 0;
    5060        canvas.animation.handler = setInterval(function () {
     
    5363                if (canvas.animation.play) {
    5464                        if (canvas.animation.increment) {
    55                                 if (frame > steps.length - 1) {
    56                                         if (node.movieLoop) {
     65                                if (frame >= steps.length - 1) {
     66                                        if (canvas.animation.loop) {
    5767                                                frame = 0;
    5868                                        }
     
    6979                //If frame has changed, update unit node and data marker display.
    7080                if (frame !== canvas.animation.lastFrame) {
    71                         node.updateBuffer('Coords', data[frame]);
    72                         canvas.unitData = data[frame];
     81                        node.updateBuffer('Coords', processedData[frame]);
     82                        canvas.unitData = processedData[frame];
    7383                        if (canvas.dataMarkers.enabled) {
    7484                                updateMarker(canvas, false);
    7585                        }
    76                         if (canvas.progressBar) {
    77                                 canvas.progressBar.val(frame).slider('refresh');
     86                        if (canvas.playbackSlider) {
     87                                canvas.playbackSlider.val(frame).slider('refresh');
    7888                        }
    79                         if (canvas.timeLabel) {
    80                                 canvas.timeLabel.html(steps[frame].toFixed(0) + " " + options.getfieldvalue("movietimeunit","yr"));
     89                        if (canvas.playbackTextProgress) {
     90                                canvas.playbackTextProgress.html(steps[frame].toFixed(0) + " " + options.getfieldvalue("movietimeunit","yr"));
    8191                        }
    82                         if (!isEmptyOrUndefined(canvas.nodes.quiver)) {
     92                        if (!VESL.Helpers.isEmptyOrUndefined(canvas.nodes.quiver)) {
    8393                                plot_quiver(md,options,canvas,false);
    8494                        }
     
    91101       
    92102        //Update progress bar with new frame info.
    93         if (canvas.progressBar) {
    94                 canvas.progressBar.val(canvas.animation.frame);
    95                 canvas.progressBar.attr('max', steps.length - 1);
    96                 canvas.progressBar.slider('refresh');
     103        if (canvas.playbackSlider) {
     104                canvas.playbackSlider.val(canvas.animation.frame);
     105                canvas.playbackSlider.attr('max', steps.length - 1);
     106                canvas.playbackSlider.slider('refresh');
    97107        }
    98108                               
  • issm/trunk-jpl/src/m/plot/plot_unit.js

    r21911 r22434  
    77        //   See also: PLOTMODEL, PLOT_MANAGER
    88
    9         //if ('unit' in canvas.nodes) {
    10         //      if (
    11         //      canvas.nodes.unit.updateBuffer('Coords', data);
    12         //      return;
    13         //}
    14         //else {
     9        var name = 'unit';
     10        if ('unit' in canvas.nodes) {
     11                if (options.getfieldvalue('clf','on')=='on') {
     12                        for (var node in canvas.nodes) {
     13                                if (node.startsWith('unit')) {
     14                                        delete canvas.octrees[node];
     15                                        delete canvas.nodes[node];
     16                                }
     17                        }
     18                }
     19                else {
     20                        name = 'unit' + Object.keys(canvas.nodes).length;
     21                }
     22        }
    1523
    1624        //{{{ declare variables:
     
    3745        }
    3846        else {
    39                 vertices = Node.prototype.scaleVertices(md, x, y, z, elements, options.getfieldvalue('heightscale', 1), options.getfieldvalue('maskscale',{}));
     47                vertices = Node.prototype.scaleVertices(md, x, y, z, elements, options.getfieldvalue('heightscale', 1), options.getfieldvalue('maskregion',{'enabled':false}));
    4048                scale = [1, 1, 1];
    4149        }
     
    4452        var edgecolor = options.getfieldvalue('edgecolor', [1.0, 1.0, 1.0 ,1.0]);
    4553        var maskzeros = options.getfieldvalue('maskzeros', {});
     54        var render = options.getfieldvalue('render', {});
     55        var cullFace = ("unit" in render) ? canvas.gl[render.unit.cullFace] : canvas.gl.BACK;
    4656        var node = new Node(
    4757                'canvas', canvas,
    4858                'options', options,
    49                 'name', 'unit',
     59                'name', name,
    5060                'shaderName', 'TexturedDiffuse',
    5161                'alpha', options.getfieldvalue('alpha', 1.0),
    5262                'caxis', options.getfieldvalue('caxis',[ArrayMin(data), ArrayMax(data)]),
    53                 //'center', [(xlim[0] + xlim[1]) / 2, (ylim[0] + ylim[1]) / 2, md.mesh.classname() === 'mesh3dsurface' ? (zlim[0] + zlim[1]) / 2 : zlim[0]],
    5463                'center', [(xlim[0] + xlim[1]) / 2, (ylim[0] + ylim[1]) / 2, (zlim[0] + zlim[1]) / 2],
    55                 'lightingBias', 0.8,
     64                'cullFace', cullFace,
     65                'lightingBias', canvas.view.lightingBias,
    5666                'diffuseColor', edgecolor,
    5767                'specularStrength', 0.0,
    58                 'enabled', options.getfieldvalue('nodata','off') == 'off',
     68                'enabled', options.getfieldvalue('nodata','off') == 'off' || (("unit" in render) && render.unit.enabled),
    5969                'log', options.getfieldvalue('log',false),
    6070                'maskEnabled', options.getfieldvalue('innermask','off') == 'on',
    6171                'maskHeight', options.getfieldvalue('innermaskheight', 150.0) / options.getfieldvalue('heightscale', 1),
    6272                'maskColor', options.getfieldvalue('innermaskcolor',[0.0, 0.0, 1.0, 1.0]),
     73                'maskObject', options.getfieldvalue('maskregion',{'enabled':false}),
    6374                'maskZerosColor', defaultFor(maskzeros.color,[1.0, 1.0, 1.0, 1.0]),
    6475                'maskZerosEnabled', defaultFor(maskzeros.enabled,false),
     
    6677                'maskZerosZeroValue', defaultFor(maskzeros.zeroValue,0.5),
    6778                'rotation', [-90, 0, 0],
    68                 'scale', scale
     79                'scale', ("unit" in render) ? [render.unit.scale, render.unit.scale, render.unit.scale] : scale
    6980        );
    7081        //}
    71         canvas.unitNode = node;
    72         canvas.unitData = data;
     82        if (options.getfieldvalue('clf','on')=='on') {
     83                canvas.unitNode = node;
     84                canvas.unitData = data;
     85        }
    7386        //}}}
    7487        switch(datatype){
  • issm/trunk-jpl/src/m/plot/plotdoc.js

    r21768 r22434  
    3939        console.log('       "datamarkers": object cotaining data marker parameters. See webgl.js for defaults. (ex: {"enabled":true,"format":["<div id="sim-plot"></div>"],"labels":["thickness","velocity","value"],"animated":true})');
    4040        console.log('           "enabled": toggle data marker displays (default true, ex: false)');
    41         console.log('           "image": image used for marking the clicked point (ex: "/textures/data_marker.svg")');
     41        console.log('           "image": image used for marking the clicked point (ex: "/canvas/data-markers/data_marker.svg")');
    4242        console.log('           "labels": when displaying a sim-plot graph, display these model fields. (ex: ["thickness","velocity","value"])');
    4343        console.log('           "font": font to be used for display (ex: "24px "Comic Sans MS", cursive")');
  • issm/trunk-jpl/src/m/plot/plotmodel.js

    r21300 r22434  
    3636                //Reinitialize all canvases
    3737                for (var i=0;i<numberofplots;i++){
    38                         document.getElementById(options.list[i].getfieldvalue('canvasid')).initialized = false;
     38                        if (options.list[i].getfieldvalue('clf','on')!='off') document.getElementById(options.list[i].getfieldvalue('canvasid')).initialized = false;
    3939                }
    4040                //Go through all data plottable and close window if an error occurs
  • issm/trunk-jpl/src/m/plot/webgl.js

    r21911 r22434  
    66        //var canvas = document.getElementById(options.getfieldvalue('canvasid'));
    77        if (!canvas.initialized) {
    8                 if (!isEmptyOrUndefined(canvas.draw) && canvas.draw.handler !== 0)      { window.cancelAnimationFrame(canvas.draw.handler); }
    9                 if (!isEmptyOrUndefined(canvas.animation) && canvas.animation.handler !== 0) { clearInterval(canvas.animation.handler); }
     8                if (!VESL.Helpers.isEmptyOrUndefined(canvas.draw) && canvas.draw.handler !== 0) { window.cancelAnimationFrame(canvas.draw.handler); }
     9                if (!VESL.Helpers.isEmptyOrUndefined(canvas.animation) && canvas.animation.handler !== 0) { clearInterval(canvas.animation.handler); }
    1010                initWebGL(canvas, options);
    1111                draw(canvas);
     
    2020        //Initialize canvas.gl on page load, reusing gl context on additional runs
    2121        var gl = canvas.gl;
    22         if (isEmptyOrUndefined(gl)) {
     22        if (VESL.Helpers.isEmptyOrUndefined(gl)) {
    2323                gl = GL.create({canvas: canvas});
    2424                gl.enable(gl.DEPTH_TEST); // Enable depth testing
     
    2727                gl.enable(gl.CULL_FACE); // Enable face culling
    2828                gl.cullFace(gl.FRONT);
    29                 gl.shaders = loadShaders(gl, options.getfieldvalue('rootpath', '../../../js/')); // Load shaders and store them in gl object
     29                gl.shaders = loadShaders(gl, options.getfieldvalue('rootpath', '/canvas')); // Load shaders and store them in gl object.
    3030                gl.textures = {};
    3131               
     
    5050               
    5151                canvas.gl = gl;
    52                 canvas.rootPath = options.getfieldvalue('rootpath', '../../../js/');
     52                canvas.assetsPath = options.getfieldvalue('rootpath', '/canvas');
    5353                canvas.id = options.getfieldvalue('canvasid', '.sim-canvas');
    5454                canvas.selector = $('#' + canvas.id);
    5555                canvas.textcanvas = null;
    5656                canvas.overlaycanvas = null;
     57                canvas.permalinkUsed = false;
    5758               
    5859                typedArraySliceSupport();
    5960        }
    6061       
    61         //Add context state variables
    62         canvas.render = options.getfieldvalue('render', {});
    63         canvas.controlSensitivity = options.getfieldvalue('controlsensitivity', 1);
    64         canvas.overlayHandlers = {};
    65         var backgroundcolor = new RGBColor(options.getfieldvalue('backgroundcolor', 'lightcyan'));
    66         if (backgroundcolor.ok) { canvas.backgroundcolor = [backgroundcolor.r/255.0, backgroundcolor.g/255.0, backgroundcolor.b/255.0, 1.0]; }
    67         else { throw Error(sprintf('s%s%s\n','initWebGL error message: cound not find out background color for curent canvas ', canvas)); }
    68        
    69         //Property intiialization, using values from options first, then from default values.
    70         var atmosphere = options.getfieldvalue('atmosphere', {});
    71         canvas.atmosphere = {                                                                                           //Default Values
    72                 wavelength_r: defaultFor(atmosphere.wavelength_r,                       0.65),          //0.65          Red wavelength (micrometers)
    73                 wavelength_g: defaultFor(atmosphere.wavelength_g,                       0.57),          //0.57          Green wavelength (micrometers)
    74                 wavelength_b: defaultFor(atmosphere.wavelength_b,                       0.475),         //0.475         Green wavelength (micrometers)
    75                 eSun:   defaultFor(atmosphere.eSun,                                             100.0),         //20.0          Sun intensity   
    76                 kRayleigh: defaultFor(atmosphere.kRayleigh,                             0.0025),        //0.0025        Rayleigh scattering amount
    77                 kMie: defaultFor(atmosphere.kMie,                                                       0.000),         //0.01          Mie scattering amount
    78                 g: defaultFor(atmosphere.g,                                                             -0.99),         //-0.99         Mie phase asymmetry/direction factor
    79                 hdr_exposure: defaultFor(atmosphere.hdr_exposure,                       0.8),           //0.8           High Dynamic Range Exposure
    80                 scaleHeight: defaultFor(atmosphere.scaleHeight,                         1.25),          //1.025         Scale of height of atmosphere to earth radius.
    81                 scaleDepth: defaultFor(atmosphere.scaleDepth,                           0.25),          //0.25          Percentage altitude at which the atmosphere's average density is found
    82                 a: defaultFor(atmosphere.a,                                                             -0.00287),      //-0.00287      Scaling constant a
    83                 b: defaultFor(atmosphere.b,                                                             0.459),         //0.459         Scaling constant b
    84                 c: defaultFor(atmosphere.c,                                                             3.83),          //3.83          Scaling constant c
    85                 d: defaultFor(atmosphere.d,                                                             -6.80),         //-6.80         Scaling constant d
    86                 e: defaultFor(atmosphere.e,                                                             3.6),           //5.25          Scaling constant e. Lower when increasing atmosphere scale.
    87                 attenuation: defaultFor(atmosphere.attenuation,                         0.5)            //0.5           Strength of atmospheric scattering on ground shading.
    88         };
    89         updateAtmosphereParameters(canvas);
    90         var animation = options.getfieldvalue('movies', {});
    91         canvas.animation = {
    92                 frame: defaultFor(animation.frame,                                                      0),
    93                 play: defaultFor(animation.play,                                                        true),
    94                 increment: defaultFor(animation.increment,                                      true),
    95                 fps: defaultFor(animation.fps,                                                          4),
    96                 interval: defaultFor(animation.interval,                                        1000 / defaultFor(animation.fps, 4)),
    97                 loop: defaultFor(animation.loop,                                                        true),
    98                 handler: defaultFor(animation.handler,                                          0)
    99         }
    100         var brush = options.getfieldvalue('brush', {});
    101         canvas.brush = {
    102                 enabled: defaultFor(brush.enabled,                                                      false),
    103                 strength: defaultFor(brush.strength,                                            0.075),
    104                 falloff: defaultFor(brush.falloff,                                                      0.5),
    105                 hit: defaultFor(brush.hit,                                                                      {})
    106         };
    107         var camera = options.getfieldvalue('camera', {});
    108         canvas.camera = {
    109                 position: defaultFor(camera.position,                                           vec3.create()),
    110                 rotation: defaultFor(camera.rotation,                                           quat.create()),
    111                 relativePosition: defaultFor(camera.relativePosition,           vec3.create()),
    112                 direction: defaultFor(camera.direction,                                         vec3.create()),
    113                 near: defaultFor(camera.near,                                                           1e3),
    114                 far: defaultFor(camera.far,                                                             1e10),
    115                 fov: defaultFor(camera.fov,                                                             45),
    116                 vMatrix: defaultFor(camera.vMatrix,                                             mat4.create()),
    117                 pMatrix: defaultFor(camera.pMatrix,                                             mat4.create()),
    118                 vpMatrix: defaultFor(camera.vpMatrix,                                           mat4.create()),
    119                 vInverseMatrix: defaultFor(camera.vInverseMatrix,                       mat4.create()),
    120                 pInverseMatrix: defaultFor(camera.pInverseMatrix,                       mat4.create()),
    121                 vpInverseMatrix: defaultFor(camera.vpInverseMatrix,             mat4.create()),
    122                 ready: defaultFor(camera.ready,                                                         false)
    123         };
    124         var dataMarkers = options.getfieldvalue('datamarkers', {});
    125         canvas.dataMarkers = {
    126                 enabled: defaultFor(dataMarkers.enabled,                                        true),
    127                 values: defaultFor(dataMarkers.values,                                          []),
    128                 image: defaultFor(dataMarkers.image,                                            canvas.rootPath + 'textures/data_marker.svg'),
    129                 size: defaultFor(dataMarkers.size,                                                      [32, 32]),
    130                 format: defaultFor(dataMarkers.format,                                          ['X: %.2e<br>Y: %.2e<br>Z: %.2e<br>Value: %0.1f', 'x', 'y', 'z', 'value']),
    131                 animated: defaultFor(dataMarkers.animated,                                      false),
    132                 labels: defaultFor(dataMarkers.labels,                                          []),
    133                 font: defaultFor(dataMarkers.font,                                                      ''),
    134                 marker: defaultFor(dataMarkers.marker,                                          document.getElementById('sim-data-marker-' + canvas.id)),
    135                 reposition: defaultFor(dataMarkers.reposition,                          true)
    136         };
    137         var draw = options.getfieldvalue('draw', {});
    138         canvas.draw = {
    139                 ready: defaultFor(draw.ready,                                                           false),
    140                 handler: defaultFor(draw.handler,                                                       null)
    141         };
    142         var view = options.getfieldvalue('view', {});
    143         canvas.view = {
    144                 position: defaultFor(view.position,                                             [0.0, 0.0, 0.0]),
    145                 rotation: defaultFor(view.rotation,                                             [0, 90]),
    146                 zoom: defaultFor(view.zoom,                                                             1.0),
    147                 zoomLimits: defaultFor(view.zoomLimits,                                         [0.001, 100.0]),
    148                 lastZoom: defaultFor(view.lastZoom,                                             1.0),
    149                 azimuthLimits: defaultFor(view.azimuthLimits,                           [0, 360]),
    150                 elevationLimits: defaultFor(view.elevationLimits,                       [-180, 180]),
    151                 panningEnabled: defaultFor(view.panningEnabled,                         false),
    152                 preventDefaultOnPan: defaultFor(view.preventDefaultOnPan,       false),
    153                 twod: defaultFor(view.twod,                                                             false)
    154         };
    155 
    156         //Override with parameters from URL, if any
    157         //TODO: Make permalinks more robust and less interdependent on UI
    158         if (!canvas.usedparemters) {
    159                 var parameters = {};
    160                 location.search.substr(1).split('&').forEach(function(part) {
    161                         var item = part.split('=');
    162                         parameters[item[0]] = decodeURIComponent(item[1]);
    163                 });
    164 
    165                 if (parameters['pos']) { canvas.view.position = JSON.parse(parameters['pos']); }
    166                 if (parameters['rot']) { canvas.view.rotation = JSON.parse(parameters['rot']); }
    167                 if (parameters['zoom']) { canvas.view.zoom = JSON.parse(parameters['zoom']); }
    168                 if (parameters['twod']) { canvas.view.twod = JSON.parse(parameters['twod']); }
    169                 if (parameters['initial']) {
    170                         initial = JSON.parse(parameters['initial']);
    171                         if (!initial) {
    172                                 if (typeof SolveGlacier === 'function') {
    173                                         SolveGlacier();
    174                                 }
    175                                 if (typeof SolveSlr === 'function') {
    176                                         SolveSlr();
    177                                 }
    178                         }
     62        if (options.getfieldvalue('clf','on')=='on') {
     63                //Add context state variables
     64                canvas.render = options.getfieldvalue('render', {});
     65                canvas.controlSensitivity = options.getfieldvalue('controlsensitivity', 1);
     66                if (options.getfieldvalue('clf','on')=='on') canvas.overlayHandlers = {};
     67                var backgroundcolor = new RGBColor(options.getfieldvalue('backgroundcolor', 'lightcyan'));
     68                if (backgroundcolor.ok) { canvas.backgroundcolor = [backgroundcolor.r/255.0, backgroundcolor.g/255.0, backgroundcolor.b/255.0, 1.0]; }
     69                else { throw Error(sprintf('s%s%s\n','initWebGL error message: cound not find out background color for current canvas ', canvas)); }
     70               
     71                //Property intiialization, using values from options first, then from default values.
     72                var atmosphere = options.getfieldvalue('atmosphere', {});
     73                canvas.atmosphere = {                                                                                                           //Default Values
     74                        wavelength_r: defaultFor(atmosphere.wavelength_r,                       0.65),          //0.65          Red wavelength (micrometers)
     75                        wavelength_g: defaultFor(atmosphere.wavelength_g,                       0.57),          //0.57          Green wavelength (micrometers)
     76                        wavelength_b: defaultFor(atmosphere.wavelength_b,                       0.475),         //0.475         Green wavelength (micrometers)
     77                        eSun:   defaultFor(atmosphere.eSun,                                             100.0),         //20.0          Sun intensity   
     78                        kRayleigh: defaultFor(atmosphere.kRayleigh,                             0.0025),        //0.0025        Rayleigh scattering amount
     79                        kMie: defaultFor(atmosphere.kMie,                                                       0.000),         //0.01          Mie scattering amount
     80                        g: defaultFor(atmosphere.g,                                                             -0.99),         //-0.99         Mie phase asymmetry/direction factor
     81                        hdr_exposure: defaultFor(atmosphere.hdr_exposure,                       0.8),           //0.8           High Dynamic Range Exposure
     82                        scaleHeight: defaultFor(atmosphere.scaleHeight,                         1.25),          //1.025         Scale of height of atmosphere to earth radius.
     83                        scaleDepth: defaultFor(atmosphere.scaleDepth,                           0.25),          //0.25          Percentage altitude at which the atmosphere's average density is found
     84                        a: defaultFor(atmosphere.a,                                                             -0.00287),      //-0.00287      Scaling constant a
     85                        b: defaultFor(atmosphere.b,                                                             0.459),         //0.459         Scaling constant b
     86                        c: defaultFor(atmosphere.c,                                                             3.83),          //3.83          Scaling constant c
     87                        d: defaultFor(atmosphere.d,                                                             -6.80),         //-6.80         Scaling constant d
     88                        e: defaultFor(atmosphere.e,                                                             3.6),           //5.25          Scaling constant e. Lower when increasing atmosphere scale.
     89                        attenuation: defaultFor(atmosphere.attenuation,                         0.5)            //0.5           Strength of atmospheric scattering on ground shading.
     90                };
     91                updateAtmosphereParameters(canvas);
     92                       
     93                var animation = options.getfieldvalue('movies', {});
     94                canvas.animation = {
     95                        frame: defaultFor(animation.frame,                                                      0),
     96                        play: defaultFor(animation.play,                                                        true),
     97                        increment: defaultFor(animation.increment,                                      true),
     98                        fps: defaultFor(animation.fps,                                                          4),
     99                        interval: defaultFor(animation.interval,                                        1000 / defaultFor(animation.fps, 4)),
     100                        loop: defaultFor(animation.loop,                                                        true),
     101                        handler: defaultFor(animation.handler,                                          0)
    179102                }
    180                 canvas.usedparemters = true;
    181         }
    182 } //}}}
    183 function generatePermalink() { //{{{
    184         var permalink = window.location.origin + window.location.pathname + '?'
    185         + '&pos=' + encodeURIComponent(JSON.stringify(canvas.view.position))
    186         + '&rot=' + encodeURIComponent(JSON.stringify(canvas.view.rotation))
    187         + '&zoom=' + encodeURIComponent(JSON.stringify(canvas.view.zoom))
    188         + '&twod=' + encodeURIComponent(JSON.stringify(canvas.view.twod));
    189         window.prompt('Share this simulation: ', permalink);
    190 } //}}}
    191 function loadShaders(gl, rootPath) { //{{{
     103                var brush = options.getfieldvalue('brush', {});
     104                canvas.brush = {
     105                        enabled: defaultFor(brush.enabled,                                                      false),
     106                        strength: defaultFor(brush.strength,                                            0.075),
     107                        falloff: defaultFor(brush.falloff,                                                      0.5),
     108                        hit: defaultFor(brush.hit,                                                                      {})
     109                };
     110                var camera = options.getfieldvalue('camera', {});
     111                canvas.camera = {
     112                        position: defaultFor(camera.position,                                           vec3.create()),
     113                        rotation: defaultFor(camera.rotation,                                           quat.create()),
     114                        relativePosition: defaultFor(camera.relativePosition,           vec3.create()),
     115                        direction: defaultFor(camera.direction,                                         vec3.create()),
     116                        near: defaultFor(camera.near,                                                           1e3),
     117                        far: defaultFor(camera.far,                                                             1e10),
     118                        fov: defaultFor(camera.fov,                                                             45),
     119                        vMatrix: defaultFor(camera.vMatrix,                                             mat4.create()),
     120                        pMatrix: defaultFor(camera.pMatrix,                                             mat4.create()),
     121                        vpMatrix: defaultFor(camera.vpMatrix,                                           mat4.create()),
     122                        vInverseMatrix: defaultFor(camera.vInverseMatrix,                       mat4.create()),
     123                        pInverseMatrix: defaultFor(camera.pInverseMatrix,                       mat4.create()),
     124                        vpInverseMatrix: defaultFor(camera.vpInverseMatrix,             mat4.create()),
     125                        ready: defaultFor(camera.ready,                                                         false)
     126                };
     127                var dataMarkers = options.getfieldvalue('datamarkers', {});
     128                canvas.dataMarkers = {
     129                        enabled: defaultFor(dataMarkers.enabled,                                        true),
     130                        values: defaultFor(dataMarkers.values,                                          []),
     131                        image: defaultFor(dataMarkers.image,                                            canvas.assetsPath + '/data-markers/data_marker.svg'),
     132                        size: defaultFor(dataMarkers.size,                                                      [32, 32]),
     133                        format: defaultFor(dataMarkers.format,                                          ['X: %.2em<br>Y: %.2em<br>Z: %.2em<br>Value: %0.1f']),
     134                        animated: defaultFor(dataMarkers.animated,                                      false),
     135                        labels: defaultFor(dataMarkers.labels,                                          ['x', 'y', 'z', 'value']),
     136                        font: defaultFor(dataMarkers.font,                                                      ''),
     137                        marker: defaultFor(dataMarkers.marker,                                          document.getElementById('sim-data-marker-' + canvas.id)),
     138                        reposition: defaultFor(dataMarkers.reposition,                          true)
     139                };
     140                var draw = options.getfieldvalue('draw', {});
     141                canvas.draw = {
     142                        ready: defaultFor(draw.ready,                                                           false),
     143                        handler: defaultFor(draw.handler,                                                       null)
     144                };
     145                var view = options.getfieldvalue('view', {});
     146                canvas.view = {
     147                        position: defaultFor(view.position,                                             [0.0, 0.0, 0.0]),
     148                        rotation: defaultFor(view.rotation,                                             [0, 90]),
     149                        zoom: defaultFor(view.zoom,                                                             1.0),
     150                        zoomLimits: defaultFor(view.zoomLimits,                                         [0.001, 100.0]),
     151                        lastZoom: defaultFor(view.lastZoom,                                             1.0),
     152                        lightingBias: defaultFor(view.lightingBias,                             0.75),
     153                        azimuthLimits: defaultFor(view.azimuthLimits,                           [0, 360]),
     154                        elevationLimits: defaultFor(view.elevationLimits,                       [-180, 180]),
     155                        panningEnabled: defaultFor(view.panningEnabled,                         false),
     156                        preventDefaultOnPan: defaultFor(view.preventDefaultOnPan,       false),
     157                        twod: defaultFor(view.twod,                                                             false)
     158                };
     159
     160                // Override with parameters from URL, if any
     161                VESL.UI.parsePermalinkCanvas(canvas);
     162        }
     163} //}}}
     164function loadShaders(gl, assetsPath) { //{{{
    192165        var shaders = {};
    193         shaders.Colored = new GL.Shader.fromURL(rootPath+'shaders/Colored.vsh', rootPath+'shaders/Colored.fsh', null, gl);
    194         shaders.ColoredDiffuse = new GL.Shader.fromURL(rootPath+'shaders/ColoredDiffuse.vsh', rootPath+'shaders/ColoredDiffuse.fsh', null, gl);
    195         shaders.Textured = new GL.Shader.fromURL(rootPath+'shaders/Textured.vsh', rootPath+'shaders/Textured.fsh', null, gl);
    196         shaders.TexturedDiffuse = new GL.Shader.fromURL(rootPath+'shaders/TexturedDiffuse.vsh', rootPath+'shaders/TexturedDiffuse.fsh', null, gl);
    197         shaders.SkyFromSpace = new GL.Shader.fromURL(rootPath+'shaders/SkyFromSpace.vert', rootPath+'shaders/SkyFromSpace.frag', null, gl);
    198         shaders.GroundFromSpace = new GL.Shader.fromURL(rootPath+'shaders/GroundFromSpace.vert', rootPath+'shaders/GroundFromSpace.frag', null, gl);
     166        // NOTE: Consider changing fromURL() to XMLHttpRequest with responseType = 'text' to avoid XML Parsing Error (shader files are not encoded as XML).
     167        shaders.Colored = new GL.Shader.fromURL(assetsPath + '/shaders/Colored.vsh', assetsPath + '/shaders/Colored.fsh', null, gl);
     168        shaders.ColoredDiffuse = new GL.Shader.fromURL(assetsPath + '/shaders/ColoredDiffuse.vsh', assetsPath + '/shaders/ColoredDiffuse.fsh', null, gl);
     169        shaders.Textured = new GL.Shader.fromURL(assetsPath + '/shaders/Textured.vsh', assetsPath + '/shaders/Textured.fsh', null, gl);
     170        shaders.TexturedDiffuse = new GL.Shader.fromURL(assetsPath + '/shaders/TexturedDiffuse.vsh', assetsPath + '/shaders/TexturedDiffuse.fsh', null, gl);
     171        shaders.SkyFromSpace = new GL.Shader.fromURL(assetsPath + '/shaders/SkyFromSpace.vert', assetsPath + '/shaders/SkyFromSpace.frag', null, gl);
     172        shaders.GroundFromSpace = new GL.Shader.fromURL(assetsPath + '/shaders/GroundFromSpace.vert', assetsPath + '/shaders/GroundFromSpace.frag', null, gl);
    199173        return shaders;
    200174} //}}}
    201175function initTexture(gl, imageSource) { //{{{
    202176        //Initialize textures, or load from memory if they already exist.
    203         if (isEmptyOrUndefined(gl.textures[imageSource])) {
     177        if (VESL.Helpers.isEmptyOrUndefined(gl.textures[imageSource])) {
    204178                gl.textures[imageSource] = GL.Texture.fromURL(imageSource, {minFilter: gl.LINEAR_MIPMAP_LINEAR, magFilter: gl.LINEAR}, null, gl);
    205179        }
     
    230204        return typeof name !== 'undefined' ? name : value;
    231205} //}}}
    232 function isEmptyOrUndefined(object) { //{{{
    233         return object === undefined || isEmpty(object);
    234 } //}}}
    235 function isEmpty(object) { //{{{
    236         for (var key in object) {
    237                 return false;
    238         }
    239         return true;
    240 } //}}}
    241206function recover(canvasid, name, value) { //{{{
    242207        //Traverse canvas object tree for property defined by dot delimited string, returning it, or a default value if it is not found.
     
    245210        for (var i = 0; i < properties.length; i++) {
    246211                object = object[properties[i]];
    247                 if (isEmptyOrUndefined(object)) { break; }
     212                if (VESL.Helpers.isEmptyOrUndefined(object)) { break; }
    248213    }
    249214        return defaultFor(object, value);
    250 } //}}}
    251 function typedArraySliceSupport() { //{{{
    252         //TypedArray compatibility for Safari/IE
    253         if (typeof Int8Array !== 'undefined') {
    254                 if (!Int8Array.prototype.fill) { Int8Array.prototype.fill = Array.prototype.fill; }
    255                 if (!Int8Array.prototype.slice) { Int8Array.prototype.slice = Array.prototype.slice; }
    256         }
    257         if (typeof Uint8Array !== 'undefined') {
    258                 if (!Uint8Array.prototype.fill) { Uint8Array.prototype.fill = Array.prototype.fill; }
    259                 if (!Uint8Array.prototype.slice) { Uint8Array.prototype.slice = Array.prototype.slice; }
    260         }
    261         if (typeof Uint8ClampedArray !== 'undefined') {
    262                 if (!Uint8ClampedArray.prototype.fill) { Uint8ClampedArray.prototype.fill = Array.prototype.fill; }
    263                 if (!Uint8ClampedArray.prototype.slice) { Uint8ClampedArray.prototype.slice = Array.prototype.slice; }
    264         }
    265         if (typeof Int16Array !== 'undefined') {
    266                 if (!Int16Array.prototype.fill) { Int16Array.prototype.fill = Array.prototype.fill; }
    267                 if (!Int16Array.prototype.slice) { Int16Array.prototype.slice = Array.prototype.slice; }
    268         }
    269         if (typeof Uint16Array !== 'undefined') {
    270                 if (!Uint16Array.prototype.fill) { Uint16Array.prototype.fill = Array.prototype.fill; }
    271                 if (!Uint16Array.prototype.slice) { Uint16Array.prototype.slice = Array.prototype.slice; }
    272         }
    273         if (typeof Int32Array !== 'undefined') {
    274                 if (!Int32Array.prototype.fill) { Int32Array.prototype.fill = Array.prototype.fill; }
    275                 if (!Int32Array.prototype.slice) { Int32Array.prototype.slice = Array.prototype.slice; }
    276         }
    277         if (typeof Uint32Array !== 'undefined') {
    278                 if (!Uint32Array.prototype.fill) { Uint32Array.prototype.fill = Array.prototype.fill; }
    279                 if (!Uint32Array.prototype.slice) { Uint32Array.prototype.slice = Array.prototype.slice; }
    280         }
    281         if (typeof Float32Array !== 'undefined') {
    282                 if (!Float32Array.prototype.fill) { Float32Array.prototype.fill = Array.prototype.fill; }
    283                 if (!Float32Array.prototype.slice) { Float32Array.prototype.slice = Array.prototype.slice; }
    284         }
    285         if (typeof Float64Array !== 'undefined') {
    286                 if (!Float64Array.prototype.fill) { Float64Array.prototype.fill = Array.prototype.fill; }
    287                 if (!Float64Array.prototype.slice) { Float64Array.prototype.slice = Array.prototype.slice; }
    288         }
    289         if (typeof TypedArray !== 'undefined') {
    290                 if (!TypedArray.prototype.fill) { TypedArray.prototype.fill = Array.prototype.fill; }
    291                 if (!TypedArray.prototype.slice) { TypedArray.prototype.slice = Array.prototype.slice; }
    292         }
    293215} //}}}
    294216//}}}
     
    356278        ev.preventDefault();
    357279        if (ev.type === 'pinchstart') { canvas.view.lastZoom = canvas.view.zoom; }
    358         else { modifyZoom(ev.scale * canvas.view.lastZoom, canvas, displaylog, ev, 0); }
     280        else {
     281                canvas.view.zoom = ev.scale * canvas.view.lastZoom;
     282                if (displaylog) { console.log(canvas.view.zoom); }
     283        }
    359284} //}}}
    360285function onZoom(ev, canvas, displaylog) { //{{{
     
    364289} //}}}
    365290function modifyZoom(value, canvas, displaylog, ev, duration) { //{{{
    366         if (isEmptyOrUndefined(duration)) duration = 200;
     291        if (VESL.Helpers.isEmptyOrUndefined(duration)) duration = 200;
    367292        var targetZoom = clamp(value, canvas.view.zoomLimits[0], canvas.view.zoomLimits[1]);
    368293        var currentZoom = canvas.view.zoom;
     
    371296                1.0,
    372297                duration,
     298                'swing',
    373299                function(value, info) {
    374300                        canvas.view.zoom = currentZoom * (1 - value) + targetZoom * value;
     
    382308function toggleMoviePlay(canvas) { //{{{
    383309        canvas.animation.play = !canvas.animation.play;
    384         if (canvas.animation.play){
    385                 canvas.playButton.find('span').removeClass('fa-play');
    386                 canvas.playButton.find('span').addClass('fa-pause');
    387         }
    388         else{
    389                 canvas.playButton.find('span').removeClass('fa-pause');
    390                 canvas.playButton.find('span').addClass('fa-play');
    391         }
    392310} //}}}
    393311function screenToWorldPoint(canvas, x, y) { //{{{
     
    403321        var origin = vec3.transformMat4(vec3.create(), [viewportX, viewportY, 0], inverseMVPMatrix);
    404322        var far = vec3.transformMat4(vec3.create(), [viewportX, viewportY, 1.0], inverseMVPMatrix);
    405         var direction = vec3.subtract(vec3.create(), far, origin);
     323        var direction = vec3.normalize(vec3.create(), vec3.subtract(vec3.create(), far, origin));
    406324        return {'origin':origin, 'direction':direction};
    407325} //}}}
     
    420338        return hit;
    421339} //}}}
    422 function raycastXY(canvas, x, y, node) { //{{{
     340function raycastXY(canvas, x, y, node, faceWinding) { //{{{
    423341        //Performs raycast on given node using x and y screenspace coordinates.
    424342        //Returns hit objects with hit position, normals, barycentric coordinates, element number, and indices of ray-triangle intersection.
     
    427345        return raycast(canvas, ray.origin, ray.direction, node);
    428346} //}}}
    429 function animateValue(current, target, duration, stepCallback, doneCallback) { //{{{
    430         //Animates scalar value for length duration, calling callback each step.
    431         //TODO: Specify lerp easing as option (cubic, linear, cosine).
     347function animateValue(current, target, duration, easing, stepCallback, doneCallback) { //{{{
     348        //Animates scalar value for length duration, calling callback each step. Specify smooth easing as a string ('swing', 'linear').
    432349        $({'value':current}).animate({'value':target}, {
    433350                duration: duration,
     351                easing: easing,
    434352                step: stepCallback,
    435353                done: doneCallback
     
    581499        canvas.gl.viewport(0, 0, canvas.width, canvas.height);
    582500       
    583         if (!isEmptyOrUndefined(canvas.overlaycanvas)) {
     501        if (!VESL.Helpers.isEmptyOrUndefined(canvas.overlaycanvas)) {
    584502                rect = canvas.overlaycanvas.getBoundingClientRect();
    585503                canvas.overlaycanvas.width  = rect.width;
  • issm/trunk-jpl/src/m/plot/webgl_node.js

    r21911 r22434  
    3333        this.lightingBias = options.getfieldvalue('lightingBias',                                       0.0);                                                                   //Controls width of gl lines. No reliable support across windows platforms.
    3434        this.log = options.getfieldvalue('log',                                                                         false);                                                                 //Controls logarithmic color axis scaling for texturing.
     35        this.maskAll = options.getfieldvalue('maskAll',                                                         []);                                                                    //Masking array used for marking all region elements.
     36        this.maskBoundary = options.getfieldvalue('maskBoundary',                                       []);                                                                    //Masking array used for marking region boundary edges.
    3537        this.maskColor = options.getfieldvalue('maskColor',                                             vec4.fromValues(0.0, 0.0, 1.0, 1.0));   //ISSM shader uniform controlling ocean masking color.
    3638        this.maskEnabled = options.getfieldvalue('maskEnabled',                                         false);                                                                 //ISSM shader uniform toggling ocean masking.
    3739        this.maskHeight = options.getfieldvalue('maskHeight',                                           150.0);                                                                 //ISSM shader uniform controlling height at which ocean masking is cut off.
     40        this.maskObject = options.getfieldvalue('maskObject',                                           {'enabled':false});                                             //Masking array options object.
    3841        this.maskZerosColor = options.getfieldvalue('maskZerosColor',                           [1.0, 1.0, 1.0, 1.0]);                                  //ISSM shader uniform controlling value masking color.
    3942        this.maskZerosEnabled = options.getfieldvalue('maskZerosEnabled',                       false);                                                                 //ISSM shader uniform toggling value masking.
     
    168171        var scale = options.getfieldvalue('scale', undefined);
    169172       
    170         if (!isEmptyOrUndefined(translation)) this.translation = translation;
    171         if (!isEmptyOrUndefined(rotation)) this.rotation = rotation;
    172         if (!isEmptyOrUndefined(scale)) this.scale = scale;
     173        if (!VESL.Helpers.isEmptyOrUndefined(translation)) this.translation = translation;
     174        if (!VESL.Helpers.isEmptyOrUndefined(rotation)) this.rotation = rotation;
     175        if (!VESL.Helpers.isEmptyOrUndefined(scale)) this.scale = scale;
    173176        this.updateModelMatrix();
    174177} //}}}
     
    194197        this.diffuseColor = edgeColor;
    195198        this.updateDiffuseColor();
     199        this.computeMasks();
    196200       
    197201        this.patchVertices(faceVertexCData, faces, vertices);
     
    208212        var face;
    209213       
    210         if (isEmptyOrUndefined(faceVertexCData)) {
     214        if (VESL.Helpers.isEmptyOrUndefined(faceVertexCData)) {
    211215                vertexArray = new Float32Array(vertices[0].length * 3);
    212216                for(var i = 0, v = 0; i < vertices[0].length; i++) {   
     
    285289        var face;
    286290       
    287         if (isEmptyOrUndefined(faceVertexCData)) { return; }
     291        if (VESL.Helpers.isEmptyOrUndefined(faceVertexCData)) { return; }
    288292       
    289293        //Use logarithmic scaling if it is valid
     
    308312                                        }
    309313                                        else {
    310                                                 coordArray[t++] = 0.5;
     314                                                coordArray[t++] = this.queryCoordMask(i); //Account for special texturing
    311315                                                coordArray[t++] = clamp((faceVertexCData[i] - caxis[0]) / crange, 0.0, 1.0);
    312316                                        }
     
    325329                                }
    326330                                else {
    327                                         coordArray[t++] = 0.5;
     331                                        coordArray[t++] = this.queryCoordMask(i); //Account for special texturing
    328332                                        coordArray[t++] = clamp((faceVertexCData[i] - caxis[0]) / crange, 0.0, 1.0);
    329333                                }
     
    364368        }
    365369       
    366         if (this.computeIndices === true && !isEmptyOrUndefined(faces)) {
    367                 if (!isEmptyOrUndefined(faces[0])) { //Check for 2D format and process if needed
     370        if (this.computeIndices === true && !VESL.Helpers.isEmptyOrUndefined(faces)) {
     371                if (!VESL.Helpers.isEmptyOrUndefined(faces[0])) { //Check for 2D format and process if needed
    368372                        if (faceColor !== 'none') { //Check for triangle rendering
    369373                                indexArray = new Uint16Array(faces.length * 3);
     
    399403        var args = Array.prototype.slice.call(arguments);
    400404        var options = new pairoptions(args.slice(0,args.length));
    401 
     405       
    402406        var coords = options.getfieldvalue('Coords', undefined);
    403         var cacheIndex = options.getfieldvalue('CacheIndex', false);
    404        
    405         if (!isEmptyOrUndefined(coords)) {
     407        if (!VESL.Helpers.isEmptyOrUndefined(coords)) {
    406408                this.patchCoords(coords, this.faces, this.vertices);
    407409                var buffer = this.mesh.getBuffer("coords");
     
    413415        //Computes and caches octrees for a node.
    414416        var octree = this.canvas.octrees[this.name];
    415         if (isEmptyOrUndefined(octree)) {
     417        if (VESL.Helpers.isEmptyOrUndefined(octree)) {
    416418                octree = new GL.Octree(this.mesh);
    417419        }
     
    439441                        var coordinateObject = vertices[i];
    440442                        var j = 0;
    441                         if (isEmptyOrUndefined(indices)) {
     443                        if (VESL.Helpers.isEmptyOrUndefined(indices)) {
    442444                                for (var key in coordinateObject) {
    443445                                        console.log(key);
     
    483485Node.prototype.scaleVertices = function(md, x, y, z, elements, scale, maskObject) { //{{{
    484486        //Scales and returns vertices x, y, and z by factor scale. Uses md.geometry.scale for heightscaling in 3d meshes.
     487        var region = maskObject.region;
     488        var mask = maskObject.enabled ? maskObject.heightmask[region] : [];
     489        var maskScale = maskObject.enabled ? maskObject.scale : 1;
     490       
     491        //The maskScaleField is the height scaling array. Use one if provided by maskObject.field, otherwise use md.geometry.surface
     492        var maskScaleField = !VESL.Helpers.isEmptyOrUndefined(maskObject.scaleField) ? maskObject.scaleField : md.geometry.surface;
     493        //If md.geometry.surface was empty and was used as maskScaleField, assign an empty array to both.
     494        if (!maskScaleField) {
     495                md.geometry.surface = NewArrayFill(md.mesh.x.length,0);
     496                maskScaleField = md.geometry.surface;
     497        }
     498       
     499        //Scale in 3D if using globe model, or in 2D otherwise.
    485500        if (md.mesh.classname() === 'mesh3dsurface') {
    486                 if (!maskObject.enabled) {
    487                         var xyz, magnitude;
    488                         x = x.slice();
    489                         y = y.slice();
    490                         z = z.slice();
    491                         for(var i = 0; i < x.length; i++) {
    492                                 xyz = vec3.fromValues(x[i], y[i], z[i]);
    493                                 magnitude = 1 + md.geometry.surface[i] * scale / vec3.length(xyz);
    494                                 vec3.scale(xyz, xyz, magnitude);
    495                                 x[i] = xyz[0];
    496                                 y[i] = xyz[1];
    497                                 z[i] = xyz[2];
    498                         }
    499                 }
    500                 else {
    501                         var mask = maskObject.mask;
    502                         var maskScale = maskObject.scale;
    503                         var element;
    504                         for (var i = 0; i < mask.length; i++) {
    505                                 if (mask[i] === 1) {
     501                var element;
     502                if (x.length === md.mesh.numberofelements) { //element plot
     503                        for (var i = 0; i < x.length; i++) {
     504                                if (maskObject.enabled) { //Scale the element if mask is not enabled, or if it is, only if it is also in the mask
    506505                                        element = elements[i];
    507506                                        for (var j = 0; j < 3; j++) {
    508507                                                xyz = vec3.fromValues(x[element[j] - 1], y[element[j] - 1], z[element[j] - 1]);
    509                                                 magnitude = 1 + md.geometry.surface[element[j] - 1] * scale * maskScale / vec3.length(xyz);
     508                                                magnitude = 1 + maskScaleField[element[j] - 1] * mask[i] * scale * maskScale / vec3.length(xyz);
    510509                                                vec3.scale(xyz, xyz, magnitude);
    511510                                                x[element[j] - 1] = xyz[0];
     
    517516                        }
    518517                }
     518                else if (x.length === md.mesh.numberofvertices) { //node plot
     519                        for (var i = 0; i < x.length; i++) {
     520                                if (!maskObject.enabled || mask[i] === 1) { //Scale the node if mask is not enabled, or if it is, only if it is also in the mask
     521                                        xyz = vec3.fromValues(x[i], y[i], z[i]);
     522                                        magnitude = 1 + maskScaleField[i] * scale * maskScale / vec3.length(xyz);
     523                                        vec3.scale(xyz, xyz, magnitude);
     524                                        x[i] = xyz[0];
     525                                        y[i] = xyz[1];
     526                                        z[i] = xyz[2];
     527                                }
     528                        }
     529                }
     530        } else {
     531                z = z.slice();
     532                var zMin = ArrayMin(maskScaleField);
     533                for(var i = 0; i < z.length; i++) {
     534                        if (!maskObject.enabled || mask[i] === 1) { //Scale the element if mask is not enabled, or if it is, only if it is also in the mask
     535                                z[i] = (z[i] - zMin) * scale + zMin;
     536                        }
     537                }
     538        }
     539        return [x, y, z];
     540} //}}}
     541Node.prototype.computeMasks = function() { //{{{
     542        //NOTE: Since sets are not yet widely supported, use array with binary values to represent if object is in set.
     543        //NOTE: Only support element wise masks for now.
     544        var maskObject = this.maskObject;
     545        if (!maskObject.enabled) { return; }
     546        var region = maskObject.region;
     547        var mask = maskObject.mask[region];
     548        var maskRegion = []; //new Set()
     549        var maskAdjacency = []; //new Set()
     550        var adjacentElements;
     551        var adjacentElements2;
     552        var adjacentNodes;
     553        var adjacentNodes2;
     554        var adjacencyLength; //length of connectivity array - 3 for elements, many for nodes
     555        var index;
     556        //For each element in the mask elements array,
     557        if (mask.length === md.mesh.numberofelements) { //element plot
     558                if (md.mesh.elementconnectivity) {
     559                        var adjacencyLength = 3;
     560                        for (var i = 0; i < mask.length; i++) {
     561                                //Determine if element is in the mask
     562                                if (mask[i] === 1) {
     563                                        //Then add each element to the adjacency set and mask region set
     564                                        adjacentElements = md.mesh.elementconnectivity[i];
     565                                        for (var j = 0; j < adjacencyLength; j++) {
     566                                                index = adjacentElements[j] - 1;
     567                                                maskAdjacency[index] = true;
     568                                               
     569                                                //Get second level of adjacent elemnents to form solid boundary (first layer look like this: /\/\/\/\/\; second layer looks like this \/\/\/\/\/; combined = |       |
     570                                                adjacentElements2 = md.mesh.elementconnectivity[index];
     571                                                for (var k = 0; k < adjacencyLength; k++) {
     572                                                        index = adjacentElements2[k] - 1;
     573                                                        maskAdjacency[index] = true;
     574                                                }
     575                                        }
     576                                        maskRegion[i] = true;
     577                                }
     578                        }
     579                }
     580        }
     581        else if (mask.length === md.mesh.numberofvertices) { //node plot
     582                if (md.mesh.nodeconnectivity) {
     583                        var adjacencyLength = md.mesh.nodeconnectivity[0].length;
     584                        for (var i = 0; i < mask.length; i++) {
     585                                //Determine if node is in the mask
     586                                if (mask[i] === 1) {
     587                                        //Then add each node to the adjacency set and mask region set
     588                                        adjacentNodes = md.mesh.nodeconnectivity[i];
     589                                        for (var j = 0; j < adjacencyLength; j++) {
     590                                                index = adjacentNode[j];
     591                                                maskAdjacency[index] = true;
     592                                               
     593                                                //Get second level of adjacent elemnents to form solid boundary (first layer look like this: /\/\/\/\/\; second layer looks like this \/\/\/\/\/; combined = |       |
     594                                                adjacentNodes2 = md.mesh.nodeconnectivity[index];
     595                                                for (var k = 0; k < adjacencyLength; k++) {
     596                                                        index = adjacentNodes2[k];
     597                                                        maskAdjacency[index] = true;
     598                                                }
     599                                        }
     600                                        maskRegion[i] = true;
     601                                }
     602                        }
     603                }
     604        }
     605       
     606        //Then subtract the mask elements array from the mask adjacency array.
     607        var maskBoundary = [];
     608        for (var i in maskAdjacency) {
     609                if (!(i in maskRegion)) {
     610                        maskBoundary[i] = true;
     611                }
     612        }
     613        this.maskBoundary = maskBoundary;
     614       
     615        //For each element not in any mask region (default to mask[0] in slr-gfm), change color to mask color.
     616        var maskAll = maskObject.mask[0];
     617        this.maskAll = maskAll;
     618} //}}}
     619Node.prototype.queryCoordMask = function(index) { //{{{
     620        //Calculate UV coordinate offsets for special color texture lookup.
     621        if (!this.maskObject.enabled) {
     622                return 1.0
    519623        }
    520624        else {
    521                 z = z.slice();
    522                 var zMin = ArrayMin(md.geometry.surface);
    523                 for(var i = 0; i < z.length; i++) {
    524                         z[i] = (z[i] - zMin) * scale + zMin;
    525                 }
    526         }
    527         return [x, y, z];
     625                //var sections = 3; //Object.keys(maskObject.colors).length + 1
     626                //var boundaryCoord = 0.5 / sections;
     627                //var maskCoord = 1.5 / sections;
     628                //var textureCoord = 2.5 / sections;
     629                if (index in this.maskBoundary) {
     630                        return 0.166666667; //boundaryCoord - edge color
     631                }
     632                else if (this.maskAll[index] === 0) {
     633                        return 0.5; //maskCoord - masked color
     634                }
     635                else {
     636                        return 0.833333333; //textureCoord - default colormap
     637                }
     638        }
    528639} //}}}
    529640Node.prototype.mergeVertices = function(x1, y1, z1, elements1, x2, y2, z2, elements2) { //{{{
Note: See TracChangeset for help on using the changeset viewer.