Best Python code snippet using autotest_python
PhiloGL.js
Source:PhiloGL.js  
1/**2@preserve3Copyright (c) 2011 Sencha Labs - Author: Nicolas Garcia Belmonte (http://philogb.github.com/)4Permission is hereby granted, free of charge, to any person obtaining a copy5of this software and associated documentation files (the "Software"), to deal6in the Software without restriction, including without limitation the rights7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell8copies of the Software, and to permit persons to whom the Software is9furnished to do so, subject to the following conditions:10The above copyright notice and this permission notice shall be included in11all copies or substantial portions of the Software.12THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR13IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,14FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE15AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER16LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,17OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN18THE SOFTWARE.19*/20(function() { 21//core.js22//Provides general utility methods, module unpacking methods and the PhiloGL app creation method.23//Global24this.PhiloGL = null;25//Creates a single application object asynchronously26//with a gl context, a camera, a program, a scene, and an event system.27(function () {28  PhiloGL = function(canvasId, opt) {29    opt = $.merge({30      context: {31        /*32         debug: true33        */34      },35      camera: {36        fov: 45,37        near: 0.1,38        far: 50039      },40      program: {41        from: 'defaults', //(defaults|ids|sources|uris)42        vs: 'Default',43        fs: 'Default'44      },45      scene: {46        /*47         All the scene.js options:48         lights: { ... }49        */50      },51      textures: {52        src: []53      },54      events: {55        /*56         All the events.js options:57         onClick: fn,58         onTouchStart: fn...59        */60      },61      onLoad: $.empty,62      onError: $.empty63    }, opt || {});64    var optContext = opt.context,65        optCamera = opt.camera,66        optEvents = opt.events,67        optTextures = opt.textures,68        optProgram = $.splat(opt.program),69        optScene = opt.scene;70    //get Context global to all framework71    gl = PhiloGL.WebGL.getContext(canvasId, optContext);72    if (!gl) {73        opt.onError("The WebGL context couldn't been initialized");74        return null;75    }76    //get Program77    var popt = {78      'defaults': 'fromDefaultShaders',79      'ids': 'fromShaderIds',80      'sources': 'fromShaderSources',81      'uris': 'fromShaderURIs'82    };83    var programLength = optProgram.length,84        programCallback = (function() {85          var count = programLength,86              programs = {},87              error = false;88          return {89            onSuccess: function(p, popt) {90              programs[popt.id || (programLength - count)] = p;91              count--;92              if (count === 0 && !error) {93                loadProgramDeps(gl, programLength == 1? p : programs, function(app) {94                  opt.onLoad(app);95                });96              }97            },98            onError: function(p) {99              count--;100              opt.onError(p);101              error = true;102            }103          };104        })();105    optProgram.forEach(function(optProgram, i) {106      var pfrom = optProgram.from, program;107      for (var p in popt) {108        if (pfrom == p) {109          try {110            program = PhiloGL.Program[popt[p]]($.extend(programCallback, optProgram));111          } catch(e) {112            programCallback.onError(e);113          }114          break;115        }116      }117      if (program) {118        programCallback.onSuccess(program, optProgram);119      }120    });121    function loadProgramDeps(gl, program, callback) {122      //get Camera123      var canvas = gl.canvas,124          camera = new PhiloGL.Camera(optCamera.fov,125                                      canvas.width / canvas.height,126                                      optCamera.near,127                                      optCamera.far, optCamera);128      camera.update();129      //get Scene130      var scene = new PhiloGL.Scene(program, camera, optScene);131      //make app instance global to all framework132      app = new PhiloGL.WebGL.Application({133        gl: gl,134        canvas: canvas,135        program: program,136        scene: scene,137        camera: camera138      });139      //Use program140      if (program.$$family == 'program') {141        program.use();142      }143      //get Events144      if (optEvents) {145        PhiloGL.Events.create(app, $.extend(optEvents, {146          bind: app147        }));148      }149      //load Textures150      if (optTextures.src.length) {151        new PhiloGL.IO.Textures($.extend(optTextures, {152          onComplete: function() {153            callback(app);154          }155        }));156      } else {157        callback(app);158      }159    }160  };161})();162//Unpacks the submodules to the global space.163PhiloGL.unpack = function(branch) {164  branch = branch || globalContext;165  ['Vec3', 'Mat4', 'Quat', 'Camera', 'Program', 'WebGL', 'O3D',166   'Scene', 'Shaders', 'IO', 'Events', 'WorkerGroup', 'Fx', 'Media'].forEach(function(module) {167      branch[module] = PhiloGL[module];168  });169  branch.gl = gl;170  branch.Utils = $;171};172//Version173PhiloGL.version = '1.5.2';174//Holds the 3D context, holds the application175var gl, app, globalContext = this;176//Utility functions177function $(d) {178  return document.getElementById(d);179}180$.empty = function() {};181$.time = Date.now;182$.uid = (function() {183  var t = $.time();184  return function() {185    return t++;186  };187})();188$.extend = function(to, from) {189  for (var p in from) {190    to[p] = from[p];191  }192  return to;193};194$.type = (function() {195  var oString = Object.prototype.toString,196      type = function(e) {197        var t = oString.call(e);198        return t.substr(8, t.length - 9).toLowerCase();199      };200  return function(elem) {201    var elemType = type(elem);202    if (elemType != 'object') {203      return elemType;204    }205    if (elem.$$family) return elem.$$family;206    return (elem && elem.nodeName && elem.nodeType == 1) ? 'element' : elemType;207  };208})();209(function() {210  function detach(elem) {211    var type = $.type(elem), ans;212    if (type == 'object') {213      ans = {};214      for (var p in elem) {215        ans[p] = detach(elem[p]);216      }217      return ans;218    } else if (type == 'array') {219      ans = [];220      for (var i = 0, l = elem.length; i < l; i++) {221        ans[i] = detach(elem[i]);222      }223      return ans;224    } else {225      return elem;226    }227  }228  $.merge = function() {229    var mix = {};230    for (var i = 0, l = arguments.length; i < l; i++){231        var object = arguments[i];232        if ($.type(object) != 'object') continue;233        for (var key in object){234            var op = object[key], mp = mix[key];235            if (mp && $.type(op) == 'object' && $.type(mp) == 'object') {236              mix[key] = $.merge(mp, op);237            } else{238              mix[key] = detach(op);239            }240        }241    }242    return mix;243  };244})();245$.splat = (function() {246  var isArray = Array.isArray;247  return function(a) {248    return isArray(a) && a || [a];249  };250})();251//webgl.js252//Checks if WebGL is enabled and creates a context for using WebGL.253(function () {254  var WebGL = {255    getContext: function(canvas, opt) {256      var canvas = typeof canvas == 'string'? $(canvas) : canvas, ctx;257      ctx = canvas.getContext('experimental-webgl', opt);258      if (!ctx) {259        ctx = canvas.getContext('webgl', opt);260      }261      //Set as debug handler262      if (ctx && opt && opt.debug) {263        gl = {};264        for (var m in ctx) {265          var f = ctx[m];266          if (typeof f == 'function') {267            gl[m] = (function(k, v) {268              return function() {269                console.log(k, Array.prototype.join.call(arguments), Array.prototype.slice.call(arguments));270                try {271                  var ans = v.apply(ctx, arguments);272                } catch (e) {273                  throw k + " " + e;274                }275                var errorStack = [], error;276                while((error = ctx.getError()) !== ctx.NO_ERROR) {277                  errorStack.push(error);278                }279                if (errorStack.length) {280                  throw errorStack.join();281                }282                return ans;283              };284            })(m, f);285          } else {286            gl[m] = f;287          }288        }289      } else {290        gl = ctx;291      }292      //add a get by name param293      if (gl) {294        gl.get = function(name) {295          return typeof name == 'string'? gl[name] : name;296        };297      }298      return gl;299    }300  };301  function Application(options) {302    //copy program, scene, camera, etc.303    for (var prop in options) {304      this[prop] = options[prop];305    }306    //handle buffers307    this.buffers = {};308    this.bufferMemo = {};309    //handle framebuffers310    this.frameBuffers = {};311    this.frameBufferMemo = {};312    //handle renderbuffers313    this.renderBuffers = {};314    this.renderBufferMemo = {};315    //handle textures316    this.textures = {};317    this.textureMemo = {};318  }319  Application.prototype = {320    $$family: 'application',321    setBuffer: function(program, name, opt) {322      //unbind buffer323      if (opt === false || opt === null) {324        opt = this.bufferMemo[name];325        //reset buffer326        if(opt) {327          gl.bindBuffer(opt.bufferType, null);328        }329        //disable vertex attrib array if the buffer maps to an attribute.330        var attributeName = opt && opt.attribute || name,331            loc = program.attributes[attributeName];332        //disable the attribute array333        if (loc !== undefined) {334          gl.disableVertexAttribArray(loc);335        }336        return;337      }338      //set defaults339      opt = $.extend(this.bufferMemo[name] || {340        bufferType: gl.ARRAY_BUFFER,341        size: 1,342        dataType: gl.FLOAT,343        stride: 0,344        offset: 0,345        drawType: gl.STATIC_DRAW346      }, opt || {});347      var attributeName = opt.attribute || name,348          bufferType = opt.bufferType,349          hasBuffer = name in this.buffers,350          buffer = hasBuffer? this.buffers[name] : gl.createBuffer(),351          hasValue = 'value' in opt,352          value = opt.value,353          size = opt.size,354          dataType = opt.dataType,355          stride = opt.stride,356          offset = opt.offset,357          drawType = opt.drawType,358          loc = program.attributes[attributeName],359          isAttribute = loc !== undefined;360      if (!hasBuffer) {361        this.buffers[name] = buffer;362      }363      if (isAttribute) {364        gl.enableVertexAttribArray(loc);365      }366      gl.bindBuffer(bufferType, buffer);367      if (hasValue) {368        gl.bufferData(bufferType, value, drawType);369      }370      if (isAttribute) {371        gl.vertexAttribPointer(loc, size, dataType, false, stride, offset);372      }373      //set default options so we don't have to next time.374      //set them under the buffer name and attribute name (if an375      //attribute is defined)376      delete opt.value;377      this.bufferMemo[name] = opt;378      if (isAttribute) {379        this.bufferMemo[attributeName] = opt;380      }381      return this;382    },383    setBuffers: function(program, obj) {384      for (var name in obj) {385        this.setBuffer(program, name, obj[name]);386      }387      return this;388    },389    setFrameBuffer: function(name, opt) {390      //bind/unbind framebuffer391      if (typeof opt != 'object') {392        gl.bindFramebuffer(gl.FRAMEBUFFER, opt? this.frameBuffers[name] : null);393        return;394      }395      //get options396      opt = $.merge(this.frameBufferMemo[name] || {397        width: 0,398        height: 0,399        //All texture params400        bindToTexture: false,401        textureOptions: {402          attachment: gl.COLOR_ATTACHMENT0403        },404        //All render buffer params405        bindToRenderBuffer: false,406        renderBufferOptions: {407          attachment: gl.DEPTH_ATTACHMENT408        }409      }, opt || {});410      var bindToTexture = opt.bindToTexture,411          bindToRenderBuffer = opt.bindToRenderBuffer,412          hasBuffer = name in this.frameBuffers,413          frameBuffer = hasBuffer? this.frameBuffers[name] : gl.createFramebuffer();414      gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);415      if (!hasBuffer) {416        this.frameBuffers[name] = frameBuffer;417      }418      if (bindToTexture) {419        var texBindOpt = $.merge({420              data: {421                width: opt.width,422                height: opt.height423              }424            }, $.type(bindToTexture) == 'object'? bindToTexture : {}),425            texName = name + '-texture',426            texOpt = opt.textureOptions;427        this.setTexture(texName, texBindOpt);428        gl.framebufferTexture2D(gl.FRAMEBUFFER, texOpt.attachment, this.textureMemo[texName].textureType, this.textures[texName], 0);429      }430      if (bindToRenderBuffer) {431        var rbBindOpt = $.extend({432              width: opt.width,433              height: opt.height434            }, $.type(bindToRenderBuffer) == 'object'? bindToRenderBuffer : {}),435            rbName = name + '-renderbuffer',436            rbOpt = opt.renderBufferOptions;437        this.setRenderBuffer(rbName, rbBindOpt);438        gl.framebufferRenderbuffer(gl.FRAMEBUFFER, rbOpt.attachment, gl.RENDERBUFFER, this.renderBuffers[rbName]);439      }440      gl.bindTexture(gl.TEXTURE_2D, null);441      gl.bindRenderbuffer(gl.RENDERBUFFER, null);442      gl.bindFramebuffer(gl.FRAMEBUFFER, null);443      this.frameBufferMemo[name] = opt;444      return this;445    },446    setFrameBuffers: function(obj) {447      for (var name in obj) {448        this.setFrameBuffer(name, obj[name]);449      }450      return this;451    },452    setRenderBuffer: function(name, opt) {453      if (typeof opt != 'object') {454        gl.bindRenderbuffer(gl.RENDERBUFFER, opt? this.renderBufferMemo[name] : null);455        return;456      }457      opt = $.extend(this.renderBufferMemo[name] || {458        storageType: gl.DEPTH_COMPONENT16,459        width: 0,460        height: 0461      }, opt || {});462      var hasBuffer = name in this.renderBuffers,463          renderBuffer = hasBuffer? this.renderBuffers[name] : gl.createRenderbuffer(gl.RENDERBUFFER);464      if (!hasBuffer) {465        this.renderBuffers[name] = renderBuffer;466      }467      gl.bindRenderbuffer(gl.RENDERBUFFER, renderBuffer);468      gl.renderbufferStorage(gl.RENDERBUFFER, opt.storageType, opt.width, opt.height);469      this.renderBufferMemo[name] = opt;470      return this;471    },472    setRenderBuffers: function(obj) {473      for (var name in obj) {474        this.setRenderBuffer(name, obj[name]);475      }476      return this;477    },478    setTexture: function(name, opt) {479      //bind texture480      if (!opt || typeof opt != 'object') {481        gl.activeTexture(opt || gl.TEXTURE0);482        gl.bindTexture(this.textureMemo[name].textureType || gl.TEXTURE_2D, this.textures[name]);483        return;484      }485      if (opt.data && opt.data.type === gl.FLOAT) {486        // Enable floating-point texture.487        if (!gl.getExtension('OES_texture_float')) {488          throw 'OES_texture_float is not supported';489        }490      }491      //get defaults492      opt = $.merge(this.textureMemo[name] || {493        textureType: gl.TEXTURE_2D,494        pixelStore: [{495          name: gl.UNPACK_FLIP_Y_WEBGL,496          value: true497        }, {498          name: gl.UNPACK_ALIGNMENT,499          value: 1500        }],501        parameters: [{502          name: gl.TEXTURE_MAG_FILTER,503          value: gl.NEAREST504        }, {505          name: gl.TEXTURE_MIN_FILTER,506          value: gl.NEAREST507        }, {508          name: gl.TEXTURE_WRAP_S,509          value: gl.CLAMP_TO_EDGE510        }, {511          name: gl.TEXTURE_WRAP_T,512          value: gl.CLAMP_TO_EDGE513        }],514        data: {515          format: gl.RGBA,516          value: false,517          type: gl.UNSIGNED_BYTE,518          width: 0,519          height: 0,520          border: 0521        }522      }, opt || {});523      var textureType = ('textureType' in opt)? opt.textureType = gl.get(opt.textureType) : gl.TEXTURE_2D,524          textureTarget = ('textureTarget' in opt)? opt.textureTarget = gl.get(opt.textureTarget) : textureType,525          isCube = textureType == gl.TEXTURE_CUBE_MAP,526          hasTexture = name in this.textures,527          texture = hasTexture? this.textures[name] : gl.createTexture(),528          pixelStore = opt.pixelStore,529          parameters = opt.parameters,530          data = opt.data,531          value = data.value,532          type = data.type,533          format = data.format,534          hasValue = !!data.value;535      //save texture536      if (!hasTexture) {537        this.textures[name] = texture;538      }539      gl.bindTexture(textureType, texture);540      if (!hasTexture) {541        //set texture properties542        pixelStore.forEach(function(opt) {543          opt.name = typeof opt.name == 'string'? gl.get(opt.name) : opt.name;544          gl.pixelStorei(opt.name, opt.value);545        });546      }547      //load texture548      if (hasValue) {549        //beware that we can be loading multiple textures (i.e. it could be a cubemap)550        if (isCube) {551          for (var i = 0; i < 6; ++i) {552            if ((data.width || data.height) && (!value.width && !value.height)) {553              gl.texImage2D(textureTarget[i], 0, format, data.width, data.height, data.border, format, type, value[i]);554            } else {555              gl.texImage2D(textureTarget[i], 0, format, format, type, value[i]);556            }557          }558        } else {559          if ((data.width || data.height) && (!value.width && !value.height)) {560            gl.texImage2D(textureTarget, 0, format, data.width, data.height, data.border, format, type, value);561          } else {562            gl.texImage2D(textureTarget, 0, format, format, type, value);563          }564        }565      //we're setting a texture to a framebuffer566      } else if (data.width || data.height) {567        gl.texImage2D(textureTarget, 0, format, data.width, data.height, data.border, format, type, null);568      }569      //set texture parameters570      if (!hasTexture) {571        for (i = 0; i < parameters.length ;i++) {572          var opti = parameters[i];573          opti.name = gl.get(opti.name);574          opti.value = gl.get(opti.value);575          gl.texParameteri(textureType, opti.name, opti.value);576          if (opti.generateMipmap) {577            gl.generateMipmap(textureType);578          }579        }580      }581      //remember whether the texture is a cubemap or not582      opt.isCube = isCube;583      //set default options so we don't have to next time.584      if (hasValue) {585        opt.data.value = false;586      }587      this.textureMemo[name] = opt;588      return this;589    },590    setTextures: function(obj) {591      for (var name in obj) {592        this.setTexture(name, obj[name]);593      }594      return this;595    },596    use: function(program) {597      gl.useProgram(program.program);598      //remember last used program.599      this.usedProgram = program;600      return this;601    }602  };603  WebGL.Application = Application;604  //Feature test WebGL605  (function() {606    try {607      var canvas = document.createElement('canvas');608      PhiloGL.hasWebGL = function() {609          return !!(window.WebGLRenderingContext && (canvas.getContext('webgl') || canvas.getContext('experimental-webgl')));610      };611    } catch(e) {612      PhiloGL.hasWebGL = function() {613          return false;614      };615    }616    PhiloGL.hasExtension = function(name) {617      if (!PhiloGL.hasWebGL()) return false;618      var canvas = document.createElement('canvas');619      return (canvas.getContext('webgl') || canvas.getContext('experimental-webgl')).getExtension(name);620    };621  })();622  PhiloGL.WebGL = WebGL;623})();624//math.js625//Vec3, Mat4 and Quat classes626(function() {627  var sqrt = Math.sqrt, 628      sin = Math.sin,629      cos = Math.cos,630      tan = Math.tan,631      pi = Math.PI,632      slice = Array.prototype.slice,633      typedArray = this.Float32Array,634      //As of version 12 Chrome does not support call/apply on typed array constructors.635      ArrayImpl = (function() {636        if (!typedArray || !typedArray.call) {637          return Array;638        }639        try {640          typedArray.call({}, 10);641        } catch (e) {642          return Array;643        }644        return typedArray;645      })(),646      typed = ArrayImpl != Array;647  //create property descriptor648  function descriptor(index) {649    return {650      get: function() {651        return this[index];652      },653      set: function(val) {654        this[index] = val;655      },656      configurable: false,657      enumerable: false658    };659  }660  //Vec3 Class661  var Vec3 = function(x, y, z) {662    if (typed) {663      typedArray.call(this, 3);664      this[0] = x || 0;665      this[1] = y || 0;666      this[2] = z || 0;667    } else {668      669      this.push(x || 0,670                y || 0,671                z || 0);672    }673    this.typedContainer = new typedArray(3);674  };675  //fast Vec3 create.676  Vec3.create = function() {677    return new typedArray(3);678  };679  //create fancy x, y, z setters and getters.680  Vec3.prototype = Object.create(ArrayImpl.prototype, {681    $$family: {682      value: 'Vec3'683    },684    685    x: descriptor(0),686    y: descriptor(1),687    z: descriptor(2)688  });689  var generics = {690    691    setVec3: function(dest, vec) {692      dest[0] = vec[0];693      dest[1] = vec[1];694      dest[2] = vec[2];695      return dest;696    },697    set: function(dest, x, y, z) {698      dest[0] = x;699      dest[1] = y;700      dest[2] = z;701      return dest;702    },703    704    add: function(dest, vec) {705      return new Vec3(dest[0] + vec[0],706                      dest[1] + vec[1], 707                      dest[2] + vec[2]);708    },709    710    $add: function(dest, vec) {711      dest[0] += vec[0];712      dest[1] += vec[1];713      dest[2] += vec[2];714      return dest;715    },716    717    add2: function(dest, a, b) {718      dest[0] = a[0] + b[0];719      dest[1] = a[1] + b[1];720      dest[2] = a[2] + b[2];721      return dest;722    },723    724    sub: function(dest, vec) {725      return new Vec3(dest[0] - vec[0],726                      dest[1] - vec[1], 727                      dest[2] - vec[2]);728    },729    730    $sub: function(dest, vec) {731      dest[0] -= vec[0];732      dest[1] -= vec[1];733      dest[2] -= vec[2];734      return dest;735    },736    737    sub2: function(dest, a, b) {738      dest[0] = a[0] - b[0];739      dest[1] = a[1] - b[1];740      dest[2] = a[2] - b[2];741      return dest;742    },743    744    scale: function(dest, s) {745      return new Vec3(dest[0] * s,746                      dest[1] * s,747                      dest[2] * s);748    },749    750    $scale: function(dest, s) {751      dest[0] *= s;752      dest[1] *= s;753      dest[2] *= s;754      return dest;755    },756    neg: function(dest) {757      return new Vec3(-dest[0],758                      -dest[1],759                      -dest[2]);760    },761    $neg: function(dest) {762      dest[0] = -dest[0];763      dest[1] = -dest[1];764      dest[2] = -dest[2];765      return dest;766    },767    unit: function(dest) {768      var len = Vec3.norm(dest);769      770      if (len > 0) {771        return Vec3.scale(dest, 1 / len);772      }773      return Vec3.clone(dest);774    },775    $unit: function(dest) {776      var len = Vec3.norm(dest);777      if (len > 0) {778        return Vec3.$scale(dest, 1 / len);779      }780      return dest;781    },782    783    cross: function(dest, vec) {784      var dx = dest[0],785          dy = dest[1],786          dz = dest[2],787          vx = vec[0],788          vy = vec[1],789          vz = vec[2];790      791      return new Vec3(dy * vz - dz * vy,792                      dz * vx - dx * vz,793                      dx * vy - dy * vx);794    },795    796    $cross: function(dest, vec) {797      var dx = dest[0],798          dy = dest[1],799          dz = dest[2],800          vx = vec[0],801          vy = vec[1],802          vz = vec[2];803      dest[0] = dy * vz - dz * vy;804      dest[1] = dz * vx - dx * vz;805      dest[2] = dx * vy - dy * vx;806      return dest;807    },808    distTo: function(dest, vec) {809      var dx = dest[0] - vec[0],810          dy = dest[1] - vec[1],811          dz = dest[2] - vec[2];812      813      return sqrt(dx * dx + 814                  dy * dy + 815                  dz * dz);816    },817    distToSq: function(dest, vec) {818      var dx = dest[0] - vec[0],819          dy = dest[1] - vec[1],820          dz = dest[2] - vec[2];821      return dx * dx + dy * dy + dz * dz;822    },823    norm: function(dest) {824      var dx = dest[0], dy = dest[1], dz = dest[2];825      return sqrt(dx * dx + dy * dy + dz * dz);826    },827    normSq: function(dest) {828      var dx = dest[0], dy = dest[1], dz = dest[2];829      return dx * dx + dy * dy + dz * dz;830    },831    dot: function(dest, vec) {832      return dest[0] * vec[0] + dest[1] * vec[1] + dest[2] * vec[2];833    },834    clone: function(dest) {835      if (dest.$$family) {836        return new Vec3(dest[0], dest[1], dest[2]);837      } else {838        return Vec3.setVec3(new typedArray(3), dest);839      }840    },841    toFloat32Array: function(dest) {842          var ans = dest.typedContainer;843          if (!ans) return dest;844          845          ans[0] = dest[0];846          ans[1] = dest[1];847          ans[2] = dest[2];848          return ans;849    }850  };851  852  //add generics and instance methods853  var proto = Vec3.prototype;854  for (var method in generics) {855    Vec3[method] = generics[method];856    proto[method] = (function (m) {857      return function() {858        var args = slice.call(arguments);859        860        args.unshift(this);861        return Vec3[m].apply(Vec3, args);862      };863   })(method);864  }865  //Mat4 Class866  var Mat4 = function(n11, n12, n13, n14,867                      n21, n22, n23, n24,868                      n31, n32, n33, n34,869                      n41, n42, n43, n44) {870    871    ArrayImpl.call(this, 16);872    this.length = 16;873    874    if (typeof n11 == 'number') {875      876      this.set(n11, n12, n13, n14,877               n21, n22, n23, n24,878               n31, n32, n33, n34,879               n41, n42, n43, n44);880    881    } else {882      this.id();883    }884    this.typedContainer = new typedArray(16);885  };886  Mat4.create = function() {887   return new typedArray(16);888  };889  //create fancy components setters and getters.890  Mat4.prototype = Object.create(ArrayImpl.prototype, {891    892    $$family: {893      value: 'Mat4'894    },895    896    n11: descriptor(0),897    n12: descriptor(4),898    n13: descriptor(8),899    n14: descriptor(12),900    901    n21: descriptor(1),902    n22: descriptor(5),903    n23: descriptor(9),904    n24: descriptor(13),905    n31: descriptor(2),906    n32: descriptor(6),907    n33: descriptor(10),908    n34: descriptor(14),909    n41: descriptor(3),910    n42: descriptor(7),911    n43: descriptor(11),912    n44: descriptor(15)913  914  });915  generics = {916    917    id: function(dest) {918      919      dest[0 ] = 1;920      dest[1 ] = 0;921      dest[2 ] = 0;922      dest[3 ] = 0;923      dest[4 ] = 0;924      dest[5 ] = 1;925      dest[6 ] = 0;926      dest[7 ] = 0;927      dest[8 ] = 0;928      dest[9 ] = 0;929      dest[10] = 1;930      dest[11] = 0;931      dest[12] = 0;932      dest[13] = 0;933      dest[14] = 0;934      dest[15] = 1;935      936      return dest;937    },938    clone: function(dest) {939      if (dest.$$family) {940        return new Mat4(dest[0], dest[4], dest[8], dest[12],941                        dest[1], dest[5], dest[9], dest[13],942                        dest[2], dest[6], dest[10], dest[14],943                        dest[3], dest[7], dest[11], dest[15]);944      } else {945        return new typedArray(dest);946      }947    },948    set: function(dest, n11, n12, n13, n14,949                        n21, n22, n23, n24,950                        n31, n32, n33, n34,951                        n41, n42, n43, n44) {952      953      dest[0 ] = n11;954      dest[4 ] = n12;955      dest[8 ] = n13;956      dest[12] = n14;957      dest[1 ] = n21;958      dest[5 ] = n22;959      dest[9 ] = n23;960      dest[13] = n24;961      dest[2 ] = n31;962      dest[6 ] = n32;963      dest[10] = n33;964      dest[14] = n34;965      dest[3 ] = n41;966      dest[7 ] = n42;967      dest[11] = n43;968      dest[15] = n44;969      970      return dest;971    },972    mulVec3: function(dest, vec) {973      var ans = Vec3.clone(vec);974      return Mat4.$mulVec3(dest, ans);975    },976    $mulVec3: function(dest, vec) {977      var vx = vec[0],978          vy = vec[1],979          vz = vec[2],980          d = 1 / (dest[3] * vx + dest[7] * vy + dest[11] * vz + dest[15]);981      vec[0] = (dest[0] * vx + dest[4] * vy + dest[8 ] * vz + dest[12]) * d;982      vec[1] = (dest[1] * vx + dest[5] * vy + dest[9 ] * vz + dest[13]) * d;983      vec[2] = (dest[2] * vx + dest[6] * vy + dest[10] * vz + dest[14]) * d;984      return vec;985    },986    mulMat42: function(dest, a, b) {987      var a11 = a[0 ], a12 = a[1 ], a13 = a[2 ], a14 = a[3 ],988          a21 = a[4 ], a22 = a[5 ], a23 = a[6 ], a24 = a[7 ],989          a31 = a[8 ], a32 = a[9 ], a33 = a[10], a34 = a[11],990          a41 = a[12], a42 = a[13], a43 = a[14], a44 = a[15],991          b11 = b[0 ], b12 = b[1 ], b13 = b[2 ], b14 = b[3 ],992          b21 = b[4 ], b22 = b[5 ], b23 = b[6 ], b24 = b[7 ],993          b31 = b[8 ], b32 = b[9 ], b33 = b[10], b34 = b[11],994          b41 = b[12], b42 = b[13], b43 = b[14], b44 = b[15];995      dest[0 ] = b11 * a11 + b12 * a21 + b13 * a31 + b14 * a41;996      dest[1 ] = b11 * a12 + b12 * a22 + b13 * a32 + b14 * a42;997      dest[2 ] = b11 * a13 + b12 * a23 + b13 * a33 + b14 * a43;998      dest[3 ] = b11 * a14 + b12 * a24 + b13 * a34 + b14 * a44;999      dest[4 ] = b21 * a11 + b22 * a21 + b23 * a31 + b24 * a41;1000      dest[5 ] = b21 * a12 + b22 * a22 + b23 * a32 + b24 * a42;1001      dest[6 ] = b21 * a13 + b22 * a23 + b23 * a33 + b24 * a43;1002      dest[7 ] = b21 * a14 + b22 * a24 + b23 * a34 + b24 * a44;1003      dest[8 ] = b31 * a11 + b32 * a21 + b33 * a31 + b34 * a41;1004      dest[9 ] = b31 * a12 + b32 * a22 + b33 * a32 + b34 * a42;1005      dest[10] = b31 * a13 + b32 * a23 + b33 * a33 + b34 * a43;1006      dest[11] = b31 * a14 + b32 * a24 + b33 * a34 + b34 * a44;1007      dest[12] = b41 * a11 + b42 * a21 + b43 * a31 + b44 * a41;1008      dest[13] = b41 * a12 + b42 * a22 + b43 * a32 + b44 * a42;1009      dest[14] = b41 * a13 + b42 * a23 + b43 * a33 + b44 * a43;1010      dest[15] = b41 * a14 + b42 * a24 + b43 * a34 + b44 * a44;1011      return dest;1012    },1013    1014    mulMat4: function(a, b) {1015      var m = Mat4.clone(a);1016      return Mat4.mulMat42(m, a, b);1017    },1018    $mulMat4: function(a, b) {1019      return Mat4.mulMat42(a, a, b);1020    },1021    add: function(dest, m) {1022      var copy = Mat4.clone(dest);1023      return Mat4.$add(copy, m);1024    },1025   1026    $add: function(dest, m) {1027      dest[0 ] += m[0];1028      dest[1 ] += m[1];1029      dest[2 ] += m[2];1030      dest[3 ] += m[3];1031      dest[4 ] += m[4];1032      dest[5 ] += m[5];1033      dest[6 ] += m[6];1034      dest[7 ] += m[7];1035      dest[8 ] += m[8];1036      dest[9 ] += m[9];1037      dest[10] += m[10];1038      dest[11] += m[11];1039      dest[12] += m[12];1040      dest[13] += m[13];1041      dest[14] += m[14];1042      dest[15] += m[15];1043      1044      return dest;1045    },1046    transpose: function(dest) {1047      var m = Mat4.clone(dest);1048      return Mat4.$transpose(m);1049    },1050    $transpose: function(dest) {1051      var n4 = dest[4], n8 = dest[8], n12 = dest[12],1052          n1 = dest[1], n9 = dest[9], n13 = dest[13],1053          n2 = dest[2], n6 = dest[6], n14 = dest[14],1054          n3 = dest[3], n7 = dest[7], n11 = dest[11];1055      dest[1] = n4;1056      dest[2] = n8;1057      dest[3] = n12;1058      dest[4] = n1;1059      dest[6] = n9;1060      dest[7] = n13;1061      dest[8] = n2;1062      dest[9] = n6;1063      dest[11] = n14;1064      dest[12] = n3;1065      dest[13] = n7;1066      dest[14] = n11;1067      return dest;1068    },1069    rotateAxis: function(dest, theta, vec) {1070      var m = Mat4.clone(dest);1071      return Mat4.$rotateAxis(m, theta, vec);1072    },1073    $rotateAxis: function(dest, theta, vec) {1074      var s = sin(theta), 1075          c = cos(theta), 1076          nc = 1 - c,1077          vx = vec[0], 1078          vy = vec[1], 1079          vz = vec[2],1080          m11 = vx * vx * nc + c, 1081          m12 = vx * vy * nc + vz * s, 1082          m13 = vx * vz * nc - vy * s,1083          m21 = vy * vx * nc - vz * s, 1084          m22 = vy * vy * nc + c, 1085          m23 = vy * vz * nc + vx * s,1086          m31 = vx * vz * nc + vy * s, 1087          m32 = vy * vz * nc - vx * s, 1088          m33 = vz * vz * nc + c,1089          d11 = dest[0],1090          d12 = dest[1],1091          d13 = dest[2],1092          d14 = dest[3],1093          d21 = dest[4],1094          d22 = dest[5],1095          d23 = dest[6],1096          d24 = dest[7],1097          d31 = dest[8],1098          d32 = dest[9],1099          d33 = dest[10],1100          d34 = dest[11],1101          d41 = dest[12],1102          d42 = dest[13],1103          d43 = dest[14],1104          d44 = dest[15];1105      1106      dest[0 ] = d11 * m11 + d21 * m12 + d31 * m13;1107      dest[1 ] = d12 * m11 + d22 * m12 + d32 * m13;1108      dest[2 ] = d13 * m11 + d23 * m12 + d33 * m13;1109      dest[3 ] = d14 * m11 + d24 * m12 + d34 * m13;1110      dest[4 ] = d11 * m21 + d21 * m22 + d31 * m23;1111      dest[5 ] = d12 * m21 + d22 * m22 + d32 * m23;1112      dest[6 ] = d13 * m21 + d23 * m22 + d33 * m23;1113      dest[7 ] = d14 * m21 + d24 * m22 + d34 * m23;1114      dest[8 ] = d11 * m31 + d21 * m32 + d31 * m33;1115      dest[9 ] = d12 * m31 + d22 * m32 + d32 * m33;1116      dest[10] = d13 * m31 + d23 * m32 + d33 * m33;1117      dest[11] = d14 * m31 + d24 * m32 + d34 * m33;1118      return dest;1119    },1120    rotateXYZ: function(dest, rx, ry, rz) {1121      var ans = Mat4.clone(dest);1122      return Mat4.$rotateXYZ(ans, rx, ry, rz);1123    },1124    $rotateXYZ: function(dest, rx, ry, rz) {1125      var d11 = dest[0 ],1126          d12 = dest[1 ],1127          d13 = dest[2 ],1128          d14 = dest[3 ],1129          d21 = dest[4 ],1130          d22 = dest[5 ],1131          d23 = dest[6 ],1132          d24 = dest[7 ],1133          d31 = dest[8 ],1134          d32 = dest[9 ],1135          d33 = dest[10],1136          d34 = dest[11],1137          crx = cos(rx),1138          cry = cos(ry),1139          crz = cos(rz),1140          srx = sin(rx),1141          sry = sin(ry),1142          srz = sin(rz),1143          m11 =  cry * crz,1144          m21 = -crx * srz + srx * sry * crz,1145          m31 =  srx * srz + crx * sry * crz,1146          m12 =  cry * srz, 1147          m22 =  crx * crz + srx * sry * srz, 1148          m32 = -srx * crz + crx * sry * srz, 1149          m13 = -sry,1150          m23 =  srx * cry,1151          m33 =  crx * cry;1152      dest[0 ] = d11 * m11 + d21 * m12 + d31 * m13;1153      dest[1 ] = d12 * m11 + d22 * m12 + d32 * m13;1154      dest[2 ] = d13 * m11 + d23 * m12 + d33 * m13;1155      dest[3 ] = d14 * m11 + d24 * m12 + d34 * m13;1156      1157      dest[4 ] = d11 * m21 + d21 * m22 + d31 * m23;1158      dest[5 ] = d12 * m21 + d22 * m22 + d32 * m23;1159      dest[6 ] = d13 * m21 + d23 * m22 + d33 * m23;1160      dest[7 ] = d14 * m21 + d24 * m22 + d34 * m23;1161      1162      dest[8 ] = d11 * m31 + d21 * m32 + d31 * m33;1163      dest[9 ] = d12 * m31 + d22 * m32 + d32 * m33;1164      dest[10] = d13 * m31 + d23 * m32 + d33 * m33;1165      dest[11] = d14 * m31 + d24 * m32 + d34 * m33;1166      return dest;1167    },1168    translate: function(dest, x, y, z) {1169      var m = Mat4.clone(dest);1170      return Mat4.$translate(m, x, y, z);1171    },1172    $translate: function(dest, x, y, z) {1173      dest[12] = dest[0 ] * x + dest[4 ] * y + dest[8 ] * z + dest[12];1174      dest[13] = dest[1 ] * x + dest[5 ] * y + dest[9 ] * z + dest[13];1175      dest[14] = dest[2 ] * x + dest[6 ] * y + dest[10] * z + dest[14];1176      dest[15] = dest[3 ] * x + dest[7 ] * y + dest[11] * z + dest[15];1177      1178      return dest;1179    },1180    scale: function(dest, x, y, z) {1181      var m = Mat4.clone(dest);1182      return Mat4.$scale(m, x, y, z);1183    },1184    $scale: function(dest, x, y, z) {1185      dest[0 ] *= x;1186      dest[1 ] *= x;1187      dest[2 ] *= x;1188      dest[3 ] *= x;1189      dest[4 ] *= y;1190      dest[5 ] *= y;1191      dest[6 ] *= y;1192      dest[7 ] *= y;1193      dest[8 ] *= z;1194      dest[9 ] *= z;1195      dest[10] *= z;1196      dest[11] *= z;1197      1198      return dest;1199    },1200    //Method based on PreGL https://github.com/deanm/pregl/ (c) Dean McNamee.1201    invert: function(dest) {1202      var m = Mat4.clone(dest);1203      return  Mat4.$invert(m);1204    },1205    $invert: function(dest) {1206      var x0 = dest[0],  x1 = dest[1],  x2 = dest[2],  x3 = dest[3],1207          x4 = dest[4],  x5 = dest[5],  x6 = dest[6],  x7 = dest[7],1208          x8 = dest[8],  x9 = dest[9], x10 = dest[10], x11 = dest[11],1209          x12 = dest[12], x13 = dest[13], x14 = dest[14], x15 = dest[15];1210      var a0 = x0*x5 - x1*x4,1211          a1 = x0*x6 - x2*x4,1212          a2 = x0*x7 - x3*x4,1213          a3 = x1*x6 - x2*x5,1214          a4 = x1*x7 - x3*x5,1215          a5 = x2*x7 - x3*x6,1216          b0 = x8*x13 - x9*x12,1217          b1 = x8*x14 - x10*x12,1218          b2 = x8*x15 - x11*x12,1219          b3 = x9*x14 - x10*x13,1220          b4 = x9*x15 - x11*x13,1221          b5 = x10*x15 - x11*x14;1222      var invdet = 1 / (a0*b5 - a1*b4 + a2*b3 + a3*b2 - a4*b1 + a5*b0);1223      dest[0 ] = (+ x5*b5 - x6*b4 + x7*b3) * invdet;1224      dest[1 ] = (- x1*b5 + x2*b4 - x3*b3) * invdet;1225      dest[2 ] = (+ x13*a5 - x14*a4 + x15*a3) * invdet;1226      dest[3 ] = (- x9*a5 + x10*a4 - x11*a3) * invdet;1227      dest[4 ] = (- x4*b5 + x6*b2 - x7*b1) * invdet;1228      dest[5 ] = (+ x0*b5 - x2*b2 + x3*b1) * invdet;1229      dest[6 ] = (- x12*a5 + x14*a2 - x15*a1) * invdet;1230      dest[7 ] = (+ x8*a5 - x10*a2 + x11*a1) * invdet;1231      dest[8 ] = (+ x4*b4 - x5*b2 + x7*b0) * invdet;1232      dest[9 ] = (- x0*b4 + x1*b2 - x3*b0) * invdet;1233      dest[10] = (+ x12*a4 - x13*a2 + x15*a0) * invdet;1234      dest[11] = (- x8*a4 + x9*a2 - x11*a0) * invdet;1235      dest[12] = (- x4*b3 + x5*b1 - x6*b0) * invdet;1236      dest[13] = (+ x0*b3 - x1*b1 + x2*b0) * invdet;1237      dest[14] = (- x12*a3 + x13*a1 - x14*a0) * invdet;1238      dest[15] = (+ x8*a3 - x9*a1 + x10*a0) * invdet;1239      return dest;1240    },1241    //TODO(nico) breaking convention here... 1242    //because I don't think it's useful to add1243    //two methods for each of these.1244    lookAt: function(dest, eye, center, up) {1245      var z = Vec3.sub(eye, center);1246      z.$unit();1247      var x = Vec3.cross(up, z);1248      x.$unit();1249      var y = Vec3.cross(z, x);1250      y.$unit();1251      return Mat4.set(dest, x[0], x[1], x[2], -x.dot(eye),1252                            y[0], y[1], y[2], -y.dot(eye),1253                            z[0], z[1], z[2], -z.dot(eye),1254                            0,   0,   0,   1);1255    },1256    frustum: function(dest, left, right, bottom, top, near, far) {1257      var rl = right - left,1258          tb = top - bottom,1259          fn = far - near;1260          1261      dest[0] = (near * 2) / rl;1262      dest[1] = 0;1263      dest[2] = 0;1264      dest[3] = 0;1265      dest[4] = 0;1266      dest[5] = (near * 2) / tb;1267      dest[6] = 0;1268      dest[7] = 0;1269      dest[8] = (right + left) / rl;1270      dest[9] = (top + bottom) / tb;1271      dest[10] = -(far + near) / fn;1272      dest[11] = -1;1273      dest[12] = 0;1274      dest[13] = 0;1275      dest[14] = -(far * near * 2) / fn;1276      dest[15] = 0;1277      return dest;1278    },1279    perspective: function(dest, fov, aspect, near, far) {1280      var ymax = near * tan(fov * pi / 360),1281          ymin = -ymax,1282          xmin = ymin * aspect,1283          xmax = ymax * aspect;1284      return Mat4.frustum(dest, xmin, xmax, ymin, ymax, near, far);1285    },1286    ortho: function(dest, left, right, bottom, top, near, far) {1287      var rl = right - left,1288          tb = top - bottom,1289          fn = far - near;1290      dest[0] = 2 / rl;1291      dest[1] = 0;1292      dest[2] = 0;1293      dest[3] = 0;1294      dest[4] = 0;1295      dest[5] = 2 / tb;1296      dest[6] = 0;1297      dest[7] = 0;1298      dest[8] = 0;1299      dest[9] = 0;1300      dest[10] = -2 / fn;1301      dest[11] = 0;1302      dest[12] = -(left + right) / rl;1303      dest[13] = -(top + bottom) / tb;1304      dest[14] = -(far + near) / fn;1305      dest[15] = 1;1306      return dest;1307    },1308    toFloat32Array: function(dest) {1309          var ans = dest.typedContainer;1310          if (!ans) return dest;1311          1312          ans[0] = dest[0];1313          ans[1] = dest[1];1314          ans[2] = dest[2];1315          ans[3] = dest[3];1316          ans[4] = dest[4];1317          ans[5] = dest[5];1318          ans[6] = dest[6];1319          ans[7] = dest[7];1320          ans[8] = dest[8];1321          ans[9] = dest[9];1322          ans[10] = dest[10];1323          ans[11] = dest[11];1324          ans[12] = dest[12];1325          ans[13] = dest[13];1326          ans[14] = dest[14];1327          ans[15] = dest[15];1328          return ans;1329    }1330  };1331  1332  //add generics and instance methods1333  proto = Mat4.prototype;1334  for (method in generics) {1335    Mat4[method] = generics[method];1336    proto[method] = (function (m) {1337      return function() {1338        var args = slice.call(arguments);1339        1340        args.unshift(this);1341        return Mat4[m].apply(Mat4, args);1342      };1343   })(method);1344  }1345  //Quaternion class1346  var Quat = function(x, y, z, w) {1347    ArrayImpl.call(this, 4);1348    this[0] = x || 0;1349    this[1] = y || 0;1350    this[2] = z || 0;1351    this[3] = w || 0;1352    this.typedContainer = new typedArray(4);1353  };1354  Quat.create = function() {1355    return new typedArray(4);1356  };1357  generics = {1358    setQuat: function(dest, q) {1359      dest[0] = q[0];1360      dest[1] = q[1];1361      dest[2] = q[2];1362      dest[3] = q[3];1363      return dest;1364    },1365    set: function(dest, x, y, z, w) {1366      dest[0] = x || 0;1367      dest[1] = y || 0;1368      dest[2] = z || 0;1369      dest[3] = w || 0;1370      return dest;1371    },1372    1373    clone: function(dest) {1374      if (dest.$$family) {1375        return new Quat(dest[0], dest[1], dest[2], dest[3]);1376      } else {1377        return Quat.setQuat(new typedArray(4), dest);1378      }1379    },1380    neg: function(dest) {1381      return new Quat(-dest[0], -dest[1], -dest[2], -dest[3]);1382    },1383    $neg: function(dest) {1384      dest[0] = -dest[0];1385      dest[1] = -dest[1];1386      dest[2] = -dest[2];1387      dest[3] = -dest[3];1388      1389      return dest;1390    },1391    add: function(dest, q) {1392      return new Quat(dest[0] + q[0],1393                      dest[1] + q[1],1394                      dest[2] + q[2],1395                      dest[3] + q[3]);1396    },1397    $add: function(dest, q) {1398      dest[0] += q[0];1399      dest[1] += q[1];1400      dest[2] += q[2];1401      dest[3] += q[3];1402      1403      return dest;1404    },1405    sub: function(dest, q) {1406      return new Quat(dest[0] - q[0],1407                      dest[1] - q[1],1408                      dest[2] - q[2],1409                      dest[3] - q[3]);1410    },1411    $sub: function(dest, q) {1412      dest[0] -= q[0];1413      dest[1] -= q[1];1414      dest[2] -= q[2];1415      dest[3] -= q[3];1416      1417      return dest;1418    },1419    scale: function(dest, s) {1420      return new Quat(dest[0] * s,1421                      dest[1] * s,1422                      dest[2] * s,1423                      dest[3] * s);1424    },1425    $scale: function(dest, s) {1426      dest[0] *= s;1427      dest[1] *= s;1428      dest[2] *= s;1429      dest[3] *= s;1430      1431      return dest;1432    },1433    mulQuat: function(dest, q) {1434      var aX = dest[0],1435          aY = dest[1],1436          aZ = dest[2],1437          aW = dest[3],1438          bX = q[0],1439          bY = q[1],1440          bZ = q[2],1441          bW = q[3];1442      return new Quat(aW * bX + aX * bW + aY * bZ - aZ * bY,1443                      aW * bY + aY * bW + aZ * bX - aX * bZ,1444                      aW * bZ + aZ * bW + aX * bY - aY * bX,1445                      aW * bW - aX * bX - aY * bY - aZ * bZ);1446    },1447    $mulQuat: function(dest, q) {1448      var aX = dest[0],1449          aY = dest[1],1450          aZ = dest[2],1451          aW = dest[3],1452          bX = q[0],1453          bY = q[1],1454          bZ = q[2],1455          bW = q[3];1456      dest[0] = aW * bX + aX * bW + aY * bZ - aZ * bY;1457      dest[1] = aW * bY + aY * bW + aZ * bX - aX * bZ;1458      dest[2] = aW * bZ + aZ * bW + aX * bY - aY * bX;1459      dest[3] = aW * bW - aX * bX - aY * bY - aZ * bZ;1460      return dest;1461    },1462    divQuat: function(dest, q) {1463      var aX = dest[0],1464          aY = dest[1],1465          aZ = dest[2],1466          aW = dest[3],1467          bX = q[0],1468          bY = q[1],1469          bZ = q[2],1470          bW = q[3];1471      var d = 1 / (bW * bW + bX * bX + bY * bY + bZ * bZ);1472      1473      return new Quat((aX * bW - aW * bX - aY * bZ + aZ * bY) * d,1474                      (aX * bZ - aW * bY + aY * bW - aZ * bX) * d,1475                      (aY * bX + aZ * bW - aW * bZ - aX * bY) * d,1476                      (aW * bW + aX * bX + aY * bY + aZ * bZ) * d);1477    },1478    $divQuat: function(dest, q) {1479      var aX = dest[0],1480          aY = dest[1],1481          aZ = dest[2],1482          aW = dest[3],1483          bX = q[0],1484          bY = q[1],1485          bZ = q[2],1486          bW = q[3];1487      var d = 1 / (bW * bW + bX * bX + bY * bY + bZ * bZ);1488      1489      dest[0] = (aX * bW - aW * bX - aY * bZ + aZ * bY) * d;1490      dest[1] = (aX * bZ - aW * bY + aY * bW - aZ * bX) * d;1491      dest[2] = (aY * bX + aZ * bW - aW * bZ - aX * bY) * d;1492      dest[3] = (aW * bW + aX * bX + aY * bY + aZ * bZ) * d;1493      return dest;1494    },1495    invert: function(dest) {1496      var q0 = dest[0],1497          q1 = dest[1],1498          q2 = dest[2],1499          q3 = dest[3];1500      var d = 1 / (q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);1501      1502      return new Quat(-q0 * d, -q1 * d, -q2 * d, q3 * d);1503    },1504    $invert: function(dest) {1505      var q0 = dest[0],1506          q1 = dest[1],1507          q2 = dest[2],1508          q3 = dest[3];1509      var d = 1 / (q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);1510      dest[0] = -q0 * d;1511      dest[1] = -q1 * d;1512      dest[2] = -q2 * d;1513      dest[3] =  q3 * d;1514      1515      return dest;1516    },1517    norm: function(dest) {1518      var a = dest[0],1519          b = dest[1],1520          c = dest[2],1521          d = dest[3];1522      return sqrt(a * a + b * b + c * c + d * d);1523    },1524    normSq: function(dest) {1525      var a = dest[0],1526          b = dest[1],1527          c = dest[2],1528          d = dest[3];1529      return a * a + b * b + c * c + d * d;1530    },1531    unit: function(dest) {1532      return Quat.scale(dest, 1 / Quat.norm(dest));1533    },1534    $unit: function(dest) {1535      return Quat.$scale(dest, 1 / Quat.norm(dest));1536    },1537    conjugate: function(dest) {1538      return new Quat(-dest[0],1539                      -dest[1],1540                      -dest[2],1541                       dest[3]);1542    },1543    $conjugate: function(dest) {1544      dest[0] = -dest[0];1545      dest[1] = -dest[1];1546      dest[2] = -dest[2];1547      1548      return dest;1549    }1550  };1551  //add generics and instance methods1552  proto = Quat.prototype = {};1553  for (method in generics) {1554    Quat[method] = generics[method];1555    proto[method] = (function (m) {1556      return function() {1557        var args = slice.call(arguments);1558        1559        args.unshift(this);1560        return Quat[m].apply(Quat, args);1561      };1562   })(method);1563  }1564  1565  //Add static methods1566  Vec3.fromQuat = function(q) {1567    return new Vec3(q[0], q[1], q[2]);1568  };1569  Quat.fromVec3 = function(v, r) {1570    return new Quat(v[0], v[1], v[2], r || 0);1571  };1572  Quat.fromMat4 = function(m) {1573    var u;1574    var v;1575    var w;1576    // Choose u, v, and w such that u is the index of the biggest diagonal entry1577    // of m, and u v w is an even permutation of 0 1 and 2.1578    if (m[0] > m[5] && m[0] > m[10]) {1579      u = 0;1580      v = 1;1581      w = 2;1582    } else if (m[5] > m[0] && m[5] > m[10]) {1583      u = 1;1584      v = 2;1585      w = 0;1586    } else {1587      u = 2;1588      v = 0;1589      w = 1;1590    }1591    var r = sqrt(1 + m[u * 5] - m[v * 5] - m[w * 5]);1592    var q = new Quat;1593    1594    q[u] = 0.5 * r;1595    q[v] = 0.5 * (m['n' + v + '' + u] + m['n' + u + '' + v]) / r;1596    q[w] = 0.5 * (m['n' + u + '' + w] + m['n' + w + '' + u]) / r;1597    q[3] = 0.5 * (m['n' + v + '' + w] - m['n' + w + '' + v]) / r;1598    return q;1599  };1600  1601  Quat.fromXRotation = function(angle) {1602    return new Quat(sin(angle / 2), 0, 0, cos(angle / 2));1603  };1604  Quat.fromYRotation = function(angle) {1605    return new Quat(0, sin(angle / 2), 0, cos(angle / 2));1606  };1607  Quat.fromZRotation = function(angle) {1608    return new Quat(0, 0, sin(angle / 2), cos(angle / 2));1609  };1610  Quat.fromAxisRotation = function(vec, angle) {1611    var x = vec[0],1612        y = vec[1],1613        z = vec[2],1614        d = 1 / sqrt(x * x + y * y + z * z),1615        s = sin(angle / 2),1616        c = cos(angle / 2);1617    return new Quat(s * x * d,1618                    s * y * d,1619                    s * z * d,1620                    c);1621  };1622  1623  Mat4.fromQuat = function(q) {1624    var a = q[3],1625        b = q[0],1626        c = q[1],1627        d = q[2];1628    1629    return new Mat4(a * a + b * b - c * c - d * d, 2 * b * c - 2 * a * d, 2 * b * d + 2 * a * c, 0,1630                    2 * b * c + 2 * a * d, a * a - b * b + c * c - d * d, 2 * c * d - 2 * a * b, 0,1631                    2 * b * d - 2 * a * c, 2 * c * d + 2 * a * b, a * a - b * b - c * c + d * d, 0,1632                    0,                     0,                     0,                             1);1633  };1634  PhiloGL.Vec3 = Vec3;1635  PhiloGL.Mat4 = Mat4;1636  PhiloGL.Quat = Quat;1637})();1638//event.js1639//Handle keyboard/mouse/touch events in the Canvas1640(function() {1641  1642  //returns an O3D object or false otherwise.1643  function toO3D(n) {1644    return n !== true ? n : false;1645  }1646  1647  //Returns an element position1648  var getPos = function(elem) {1649    var bbox = elem.getBoundingClientRect();1650    return {1651      x: bbox.left,1652      y: bbox.top,1653      bbox: bbox1654    };1655  };1656  //event object wrapper1657  var event = {1658    get: function(e, win) {1659      win = win || window;1660      return e || win.event;1661    },1662    getWheel: function(e) {1663      return e.wheelDelta? e.wheelDelta / 120 : -(e.detail || 0) / 3;1664    },1665    getKey: function(e) {1666      var code = e.which || e.keyCode;1667      var key = keyOf(code);1668      //onkeydown1669      var fKey = code - 111;1670      if (fKey > 0 && fKey < 13) key = 'f' + fKey;1671      key = key || String.fromCharCode(code).toLowerCase();1672      1673      return {1674        code: code,1675        key: key,1676        shift: e.shiftKey,1677        control: e.ctrlKey,1678        alt: e.altKey,1679        meta: e.metaKey1680      };1681    },1682    isRightClick: function(e) {1683      return (e.which == 3 || e.button == 2);1684    },1685    getPos: function(e, win) {1686      // get mouse position1687      win = win || window;1688      e = e || win.event;1689      var doc = win.document;1690      doc = doc.documentElement || doc.body;1691      //TODO(nico): make touch event handling better1692      if(e.touches && e.touches.length) {1693        e = e.touches[0];1694      }1695      var page = {1696        x: e.pageX || (e.clientX + doc.scrollLeft),1697        y: e.pageY || (e.clientY + doc.scrollTop)1698      };1699      return page;1700    },1701    stop: function(e) {1702      if (e.stopPropagation) e.stopPropagation();1703      e.cancelBubble = true;1704      if (e.preventDefault) e.preventDefault();1705      else e.returnValue = false;1706    }1707  };1708  var EventsProxy = function(app, opt) {1709    var domElem = app.canvas;1710    this.scene = app.scene;1711    this.domElem = domElem;1712    this.pos = getPos(domElem);1713    this.opt = this.callbacks = opt;1714    this.size = {1715      width: domElem.width || domElem.offsetWidth,1716      height: domElem.height || domElem.offsetHeight1717    };1718    this.attachEvents();1719  };1720  1721  EventsProxy.prototype = {1722    hovered: false,1723    pressed: false,1724    touched: false,1725    touchMoved: false,1726    moved: false,1727    1728    attachEvents: function() {1729      var domElem = this.domElem,1730          opt = this.opt,1731          that = this;1732      1733      if (opt.disableContextMenu) {1734        domElem.oncontextmenu = function() { return false; };1735      }1736      1737      ['mouseup', 'mousedown', 'mousemove', 'mouseover', 'mouseout', 1738       'touchstart', 'touchmove', 'touchend'].forEach(function(action) {1739        domElem.addEventListener(action, function(e, win) {1740          that[action](that.eventInfo(action, e, win));1741        }, false);1742      });1743      1744       ['keydown', 'keyup'].forEach(function(action) {1745        document.addEventListener(action, function(e, win) {1746          that[action](that.eventInfo(action, e, win));1747        }, false);1748      });1749      //"well, this is embarrassing..."1750      var type = '';1751      if (!document.getBoxObjectFor && window.mozInnerScreenX == null) {1752        type = 'mousewheel';1753      } else {1754        type = 'DOMMouseScroll';1755      }1756      domElem.addEventListener(type, function(e, win) {1757        that['mousewheel'](that.eventInfo('mousewheel', e, win));1758      }, false);1759    },1760    1761    eventInfo: function(type, e, win) {1762      var domElem = this.domElem,1763          scene = this.scene,1764          opt = this.opt,1765          size = this.getSize(),1766          relative = opt.relative,1767          centerOrigin = opt.centerOrigin,1768          pos = opt.cachePosition && this.pos || getPos(domElem),1769          ge = event.get(e, win),1770          epos = event.getPos(e, win),1771          evt = {};1772      //get Position1773      var x = epos.x, y = epos.y;1774      if (relative) {1775        x -= pos.x; y-= pos.y;1776        if (centerOrigin) {1777          x -= size.width / 2;1778          y -= size.height / 2;1779          y *= -1; //y axis now points to the top of the screen1780        }1781      }1782      switch (type) {1783        case 'mousewheel':1784          evt.wheel = event.getWheel(ge);1785          break;1786        case 'keydown':1787        case 'keyup':1788          $.extend(evt, event.getKey(ge));1789          break;1790        case 'mouseup':1791          evt.isRightClick = event.isRightClick(ge);1792          break;1793      }1794      var cacheTarget;1795      1796      $.extend(evt, {1797        x: x,1798        y: y,1799        cache: false,1800        //stop event propagation1801        stop: function() {1802          event.stop(ge);1803        },1804        //get the target element of the event1805        getTarget: function() {1806          if (cacheTarget) return cacheTarget;1807          return (cacheTarget = !opt.picking || scene.pick(epos.x - pos.x, epos.y - pos.y, opt.lazyPicking) || true);1808        }1809      });1810      //wrap native event1811      evt.event = ge;1812      1813      return evt;1814    },1815    getSize: function() {1816      if (this.cacheSize) {1817        return this.size;1818      }1819      var domElem = this.domElem;1820      return {1821        width: domElem.width || domElem.offsetWidth,1822        height: domElem.height || domElem.offsetHeight1823      };1824    },1825    1826    mouseup: function(e) {1827      if(!this.moved) {1828        if(e.isRightClick) {1829          this.callbacks.onRightClick(e, this.hovered);1830        } else {1831          this.callbacks.onClick(e, toO3D(this.pressed));1832        }1833      }1834      if(this.pressed) {1835        if(this.moved) {1836          this.callbacks.onDragEnd(e, toO3D(this.pressed));1837        } else {1838          this.callbacks.onDragCancel(e, toO3D(this.pressed));1839        }1840        this.pressed = this.moved = false;1841      }1842    },1843    mouseout: function(e) {1844      //mouseout canvas1845      var rt = e.relatedTarget,1846          domElem = this.domElem;1847      while(rt && rt.parentNode) {1848        if(domElem == rt.parentNode) return;1849        rt = rt.parentNode;1850      }1851      if(this.hovered) {1852        this.callbacks.onMouseLeave(e, this.hovered);1853        this.hovered = false;1854      }1855      if (this.pressed && this.moved) {1856        this.callbacks.onDragEnd(e);1857        this.pressed = this.moved = false;1858      }1859    },1860    1861    mouseover: function(e) {},1862    1863    mousemove: function(e) {1864      if(this.pressed) {1865        this.moved = true;1866        this.callbacks.onDragMove(e, toO3D(this.pressed));1867        return;1868      }1869      if(this.hovered) {1870        var target = toO3D(e.getTarget());1871        if(!target || target.hash != this.hash) {1872          this.callbacks.onMouseLeave(e, this.hovered);1873          this.hovered = target;1874          this.hash = target;1875          if(target) {1876            this.hash = target.hash;1877            this.callbacks.onMouseEnter(e, this.hovered);1878          }1879        } else {1880          this.callbacks.onMouseMove(e, this.hovered);1881        }1882      } else {1883        this.hovered = toO3D(e.getTarget());1884        this.hash = this.hovered;1885        if(this.hovered) {1886          this.hash = this.hovered.hash;1887          this.callbacks.onMouseEnter(e, this.hovered);1888        }1889      }1890      if (!this.opt.picking) {1891        this.callbacks.onMouseMove(e);1892      }1893    },1894    1895    mousewheel: function(e) {1896      this.callbacks.onMouseWheel(e);1897    },1898    1899    mousedown: function(e) {1900      this.pressed = e.getTarget();1901      this.callbacks.onDragStart(e, toO3D(this.pressed));1902    },1903    1904    touchstart: function(e) {1905      this.touched = e.getTarget();1906      this.callbacks.onTouchStart(e, toO3D(this.touched));1907    },1908    1909    touchmove: function(e) {1910      if(this.touched) {1911        this.touchMoved = true;1912        this.callbacks.onTouchMove(e, toO3D(this.touched));1913      }1914    },1915    1916    touchend: function(e) {1917      if(this.touched) {1918        if(this.touchMoved) {1919          this.callbacks.onTouchEnd(e, toO3D(this.touched));1920        } else {1921          this.callbacks.onTouchCancel(e, toO3D(this.touched));1922        }1923        this.touched = this.touchMoved = false;1924      }1925    },1926    keydown: function(e) {1927      this.callbacks.onKeyDown(e);1928    },1929    keyup: function(e) {1930      this.callbacks.onKeyUp(e);1931    }1932  };1933    1934  var Events = {};1935  Events.create = function(app, opt) {1936    opt = $.extend({1937      cachePosition: true,1938      cacheSize: true,1939      relative: true,1940      centerOrigin: true,1941      disableContextMenu: true,1942      bind: false,1943      picking: false,1944      lazyPicking: false,1945      1946      onClick: $.empty,1947      onRightClick: $.empty,1948      onDragStart: $.empty,1949      onDragMove: $.empty,1950      onDragEnd: $.empty,1951      onDragCancel: $.empty,1952      onTouchStart: $.empty,1953      onTouchMove: $.empty,1954      onTouchEnd: $.empty,1955      onTouchCancel: $.empty,1956      onMouseMove: $.empty,1957      onMouseEnter: $.empty,1958      onMouseLeave: $.empty,1959      onMouseWheel: $.empty,1960      onKeyDown: $.empty,1961      onKeyUp: $.empty1962      1963    }, opt || {});1964    var bind = opt.bind;1965    if (bind) {1966      for (var name in opt) {1967        if (name.match(/^on[a-zA-Z0-9]+$/)) {1968          (function (name, fn) {1969            opt[name] = function() {1970              return fn.apply(bind, Array.prototype.slice.call(arguments));1971            };1972          })(name, opt[name]);1973        }1974      }1975    }1976    new EventsProxy(app, opt);1977    //assign event handler to app.1978    app.events = opt;1979  };1980  Events.Keys = {1981  	'enter': 13,1982  	'up': 38,1983  	'down': 40,1984  	'left': 37,1985  	'right': 39,1986  	'esc': 27,1987  	'space': 32,1988  	'backspace': 8,1989  	'tab': 9,1990  	'delete': 461991  };1992  function keyOf(code) {1993    var keyMap = Events.Keys;1994    for (var name in keyMap) {1995      if (keyMap[name] == code) {1996        return name;1997      }1998    }1999  }2000  PhiloGL.Events = Events;2001    2002})();2003//program.js2004//Creates programs out of shaders and provides convenient methods for loading2005//buffers attributes and uniforms2006(function() {2007  //First, some privates to handle compiling/linking shaders to programs.2008  2009  //Creates a shader from a string source.2010  var createShader = function(gl, shaderSource, shaderType) {2011    var shader = gl.createShader(shaderType);2012    if (shader == null) {2013      throw "Error creating the shader with shader type: " + shaderType;2014      //return false;2015    }2016    gl.shaderSource(shader, shaderSource);2017    gl.compileShader(shader);2018    var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);2019    if (!compiled) {2020      var info = gl.getShaderInfoLog(shader);2021      gl.deleteShader(shader);2022      throw "Error while compiling the shader " + info;2023      //return false;2024    }2025    return shader;2026  };2027  2028  //Creates a program from vertex and fragment shader sources.2029  var createProgram = function(gl, vertexShader, fragmentShader) {2030    var program = gl.createProgram();2031    gl.attachShader(2032        program,2033        createShader(gl, vertexShader, gl.VERTEX_SHADER));2034    gl.attachShader(2035        program,2036        createShader(gl, fragmentShader,  gl.FRAGMENT_SHADER));2037    linkProgram(gl, program);2038    return program;2039  };2040  2041  var getpath = function(path) {2042    var last = path.lastIndexOf('/');2043    if (last == '/') {2044      return './';2045    } else {2046      return path.substr(0, last + 1);2047    }2048  };2049  // preprocess a source with `#include ""` support2050  // `duplist` records all the pending replacements2051  var preprocess = function(base, source, callback, callbackError, duplist) {2052    duplist = duplist || {};2053    var match;2054    if ((match = source.match(/#include "(.*?)"/))) {2055      var xhr = PhiloGL.IO.XHR,2056        url = getpath(base) + match[1];2057      if (duplist[url]) {2058        callbackError('Recursive include');2059      }2060      new xhr({2061        url: url,2062        noCache: true,2063        onError: function(code) {2064          callbackError('Load included file `' + url + '` failed: Code ' + code);2065        },2066        onSuccess: function(response) {2067          duplist[url] = true;2068          return preprocess(url, response, function(replacement) {2069            delete duplist[url];2070            source = source.replace(/#include ".*?"/, replacement);2071            source = source.replace(/\sHAS_EXTENSION\s*\(\s*([A-Za-z_\-0-9]+)\s*\)/g, function (all, ext) {2072              return gl.getExtension(ext) ? ' 1 ': ' 0 ';2073            });2074            return preprocess(url, source, callback, callbackError, duplist);2075          }, callbackError, duplist);2076        }2077      }).send();2078      return null;2079    } else {2080      return callback(source);2081    }2082  };  2083  //Link a program.2084  var linkProgram = function(gl, program) {2085    gl.linkProgram(program);2086    var linked = gl.getProgramParameter(program, gl.LINK_STATUS);2087    if (!linked) {2088      throw "Error linking the shader: " + gl.getProgramInfoLog(program);2089      //return false;2090    }2091    return true;2092  };2093  //Returns a Magic Uniform Setter2094  var getUniformSetter = function(program, info, isArray) {2095    var name = info.name,2096        loc = gl.getUniformLocation(program, name),2097        type = info.type,2098        matrix = false,2099        vector = true,2100        glFunction, typedArray;2101    if (info.size > 1 && isArray) {2102      switch(type) {2103        case gl.FLOAT:2104          glFunction = gl.uniform1fv;2105          typedArray = Float32Array;2106          vector = false;2107          break;2108        case gl.INT: case gl.BOOL: case gl.SAMPLER_2D: case gl.SAMPLER_CUBE:2109          glFunction = gl.uniform1iv;2110          typedArray = Uint16Array;2111          vector = false;2112          break;2113      }2114    }2115    2116    if (vector) {2117      switch (type) {2118        case gl.FLOAT:2119          glFunction = gl.uniform1f;2120          break;2121        case gl.FLOAT_VEC2:2122          glFunction = gl.uniform2fv;2123          typedArray = isArray ? Float32Array : new Float32Array(2);2124          break;2125        case gl.FLOAT_VEC3:2126          glFunction = gl.uniform3fv;2127          typedArray = isArray ? Float32Array : new Float32Array(3);2128          break;2129        case gl.FLOAT_VEC4:2130          glFunction = gl.uniform4fv;2131          typedArray = isArray ? Float32Array : new Float32Array(4);2132          break;2133        case gl.INT: case gl.BOOL: case gl.SAMPLER_2D: case gl.SAMPLER_CUBE:2134          glFunction = gl.uniform1i;2135          break;2136        case gl.INT_VEC2: case gl.BOOL_VEC2:2137          glFunction = gl.uniform2iv;2138          typedArray = isArray ? Uint16Array : new Uint16Array(2);2139          break;2140        case gl.INT_VEC3: case gl.BOOL_VEC3:2141          glFunction = gl.uniform3iv;2142          typedArray = isArray ? Uint16Array : new Uint16Array(3);2143          break;2144        case gl.INT_VEC4: case gl.BOOL_VEC4:2145          glFunction = gl.uniform4iv;2146          typedArray = isArray ? Uint16Array : new Uint16Array(4);2147          break;2148        case gl.FLOAT_MAT2:2149          matrix = true;2150          glFunction = gl.uniformMatrix2fv;2151          break;2152        case gl.FLOAT_MAT3:2153          matrix = true;2154          glFunction = gl.uniformMatrix3fv;2155          break;2156        case gl.FLOAT_MAT4:2157          matrix = true;2158          glFunction = gl.uniformMatrix4fv;2159          break;2160      }2161    }2162    //TODO(nico): Safari 5.1 doesn't have Function.prototype.bind.2163    //remove this check when they implement it.2164    if (glFunction.bind) {2165      glFunction = glFunction.bind(gl);2166    } else {2167      var target = glFunction;2168      glFunction = function() { target.apply(gl, arguments); };2169    }2170    //Set a uniform array2171    if (isArray && typedArray) {2172      return function(val) {2173        glFunction(loc, new typedArray(val));2174      };2175    2176    //Set a matrix uniform2177    } else if (matrix) {2178      return function(val) {2179        glFunction(loc, false, val.toFloat32Array());2180      };2181    2182    //Set a vector/typed array uniform2183    } else if (typedArray) {2184      return function(val) {2185        typedArray.set(val.toFloat32Array ? val.toFloat32Array() : val);2186        glFunction(loc, typedArray);2187      };2188    2189    //Set a primitive-valued uniform2190    } else {2191      return function(val) {2192        glFunction(loc, val);2193      };2194    }2195    // FIXME: Unreachable code2196    throw "Unknown type: " + type;2197  };2198  //Program Class: Handles loading of programs and mapping of attributes and uniforms2199  var Program = function(vertexShader, fragmentShader) {2200    var program = createProgram(gl, vertexShader, fragmentShader);2201    if (!program) return false;2202    2203    var attributes = {},2204        attributeEnabled = {},2205        uniforms = {},2206        info, name, index;2207  2208    //fill attribute locations2209    var len = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);2210    for (var i = 0; i < len; i++) {2211      info = gl.getActiveAttrib(program, i);2212      name = info.name;2213      index = gl.getAttribLocation(program, info.name);2214      attributes[name] = index;2215    }2216    2217    //create uniform setters2218    len = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);2219    for (i = 0; i < len; i++) {2220      info = gl.getActiveUniform(program, i);2221      name = info.name;2222      //if array name then clean the array brackets2223      name = name[name.length -1] == ']' ? name.substr(0, name.length -3) : name;2224      uniforms[name] = getUniformSetter(program, info, info.name != name);2225    }2226    this.program = program;2227    //handle attributes and uniforms2228    this.attributes = attributes;2229    this.attributeEnabled = attributeEnabled;2230    this.uniforms = uniforms;2231  };2232  Program.prototype = {2233    2234    $$family: 'program',2235    setUniform: function(name, val) {2236      if (this.uniforms[name]) {2237        this.uniforms[name](val);2238      }2239      return this;2240    },2241    setUniforms: function(obj) {2242      for (var name in obj) {2243        this.setUniform(name, obj[name]);2244      }2245      return this;2246    }2247  };2248  ['setBuffer', 'setBuffers', 'use'].forEach(function(name) {2249    Program.prototype[name] = function() {2250      var args = Array.prototype.slice.call(arguments);2251      args.unshift(this);2252      app[name].apply(app, args);2253      return this;2254    };2255  });2256  ['setFrameBuffer', 'setFrameBuffers', 'setRenderBuffer', 2257   'setRenderBuffers', 'setTexture', 'setTextures'].forEach(function(name) {2258    Program.prototype[name] = function() {2259      app[name].apply(app, arguments);2260      return this;2261    };2262  });2263  //Get options in object or arguments2264  function getOptions(args, base) {2265    var opt;2266    if (args.length == 2) {2267      opt = {2268        vs: args[0],2269        fs: args[1]2270      };2271    } else {2272      opt = args[0] || {};2273    }2274    return $.merge(base || {}, opt);2275  }2276  //Create a program from vertex and fragment shader node ids2277  Program.fromShaderIds = function() {2278    var opt = getOptions(arguments),2279      vs = $(opt.vs),2280      fs = $(opt.fs);2281    return preprocess(opt.path, vs.innerHTML, function(vectexShader) {2282      return preprocess(opt.path, fs.innerHTML, function(fragmentShader) {2283        opt.onSuccess(new Program(vectexShader, fragmentShader), opt);2284      });2285    });2286  };2287  //Create a program from vs and fs sources2288  Program.fromShaderSources = function() {2289    var opt = getOptions(arguments, {path: './'});2290    return preprocess(opt.path, opt.vs, function(vectexShader) {2291      return preprocess(opt.path, opt.fs, function(fragmentShader) {2292        try {2293          var program = new Program(vectexShader, fragmentShader);2294          if(opt.onSuccess) {2295            opt.onSuccess(program, opt); 2296          } else {2297            return program;2298          }2299        } catch(e) {2300          if (opt.onError) {2301            opt.onError(e, opt);2302          } else {2303            throw e;2304          }2305        }2306      });2307    });2308  };2309  //Build program from default shaders (requires Shaders)2310  Program.fromDefaultShaders = function(opt) {2311    opt = opt || {};2312    var vs = opt.vs || 'Default',2313      fs = opt.fs || 'Default',2314      sh = PhiloGL.Shaders;2315    opt.vs = sh.Vertex[vs];2316    opt.fs = sh.Fragment[fs];2317    return PhiloGL.Program.fromShaderSources(opt);2318  };2319  //Implement Program.fromShaderURIs (requires IO)2320  Program.fromShaderURIs = function(opt) {2321    opt = $.merge({2322      path: '',2323      vs: '',2324      fs: '',2325      noCache: false,2326      onSuccess: $.empty,2327      onError: $.empty2328    }, opt || {});2329    var vertexShaderURI = opt.path + opt.vs,2330        fragmentShaderURI = opt.path + opt.fs,2331        XHR = PhiloGL.IO.XHR;2332    new XHR.Group({2333      urls: [vertexShaderURI, fragmentShaderURI],2334      noCache: opt.noCache,2335      onError: function(arg) {2336        opt.onError(arg);2337      },2338      onComplete: function(ans) {2339        try {2340          return preprocess(vertexShaderURI, ans[0], function(vectexShader) {2341            return preprocess(fragmentShaderURI, ans[1], function(fragmentShader) {2342              opt.vs = vectexShader;2343              opt.fs = fragmentShader;2344              return Program.fromShaderSources(opt);2345            }, opt.onError);2346          }, opt.onError);2347        } catch (e) {2348          opt.onError(e, opt);2349        }2350      }2351    }).send();2352  };2353  PhiloGL.Program = Program;2354})();2355//io.js2356//Provides loading of assets with XHR and JSONP methods.2357(function () {2358  var IO = {};2359  var XHR = function(opt) {2360    opt = $.merge({2361      url: 'http://philogljs.org/',2362      method: 'GET',2363      async: true,2364      noCache: false,2365      //body: null,2366      sendAsBinary: false,2367      responseType: false,2368      onProgress: $.empty,2369      onSuccess: $.empty,2370      onError: $.empty,2371      onAbort: $.empty,2372      onComplete: $.empty2373    }, opt || {});2374    this.opt = opt;2375    this.initXHR();2376  };2377  XHR.State = {};2378  ['UNINITIALIZED', 'LOADING', 'LOADED', 'INTERACTIVE', 'COMPLETED'].forEach(function(stateName, i) {2379    XHR.State[stateName] = i;2380  });2381  XHR.prototype = {2382    initXHR: function() {2383      var req = this.req = new XMLHttpRequest(),2384          that = this;2385      ['Progress', 'Error', 'Abort', 'Load'].forEach(function(event) {2386        if (req.addEventListener) {2387          req.addEventListener(event.toLowerCase(), function(e) {2388            that['handle' + event](e);2389          }, false);2390        } else {2391          req['on' + event.toLowerCase()] = function(e) {2392            that['handle' + event](e);2393          };2394        }2395      });2396    },2397    2398    send: function(body) {2399      var req = this.req,2400          opt = this.opt,2401          async = opt.async;2402      2403      if (opt.noCache) {2404        opt.url += (opt.url.indexOf('?') >= 0? '&' : '?') + $.uid();2405      }2406      req.open(opt.method, opt.url, async);2407      if (opt.responseType) {2408        req.responseType = opt.responseType;2409      }2410      2411      if (async) {2412        req.onreadystatechange = function(e) {2413          if (req.readyState == XHR.State.COMPLETED) {2414            if (req.status == 200) {2415              opt.onSuccess(req.responseType ? req.response : req.responseText);2416            } else {2417              opt.onError(req.status);2418            }2419          }2420        };2421      }2422      2423      if (opt.sendAsBinary) {2424        req.sendAsBinary(body || opt.body || null);2425      } else {2426        req.send(body || opt.body || null);2427      }2428      if (!async) {2429        if (req.status == 200) {2430          opt.onSuccess(req.responseType ? req.response : req.responseText);2431        } else {2432          opt.onError(req.status);2433        }2434      }2435    },2436    setRequestHeader: function(header, value) {2437      this.req.setRequestHeader(header, value);2438      return this;2439    },2440    handleProgress: function(e) {2441      if (e.lengthComputable) {2442        this.opt.onProgress(e, Math.round(e.loaded / e.total * 100));2443      } else {2444        this.opt.onProgress(e, -1);2445      }2446    },2447    handleError: function(e) {2448      this.opt.onError(e);2449    },2450    handleAbort: function() {2451      this.opt.onAbort(e);2452    },2453    handleLoad: function(e) {2454       this.opt.onComplete(e);2455    }2456  };2457  //Make parallel requests and group the responses.2458  XHR.Group = function(opt) {2459    opt = $.merge({2460      urls: [],2461      onError: $.empty,2462      onSuccess: $.empty,2463      onComplete: $.empty,2464      method: 'GET',2465      async: true,2466      noCache: false,2467      //body: null,2468      sendAsBinary: false,2469      responseType: false2470    }, opt || {});2471    var urls = $.splat(opt.urls),2472        len = urls.length,2473        ans = new Array(len),2474        reqs = urls.map(function(url, i) {2475            return new XHR({2476              url: url,2477              method: opt.method,2478              async: opt.async,2479              noCache: opt.noCache,2480              sendAsBinary: opt.sendAsBinary,2481              responseType: opt.responseType,2482              body: opt.body,2483              //add callbacks2484              onError: handleError(i),2485              onSuccess: handleSuccess(i)2486            });2487        });2488    function handleError(i) {2489      return function(e) {2490        --len;2491        opt.onError(e, i);2492        2493        if (!len) opt.onComplete(ans);2494      };2495    }2496    function handleSuccess(i) {2497      return function(response) {2498        --len;2499        ans[i] = response;2500        opt.onSuccess(response, i);2501        if (!len) opt.onComplete(ans);2502      };2503    }2504    this.reqs = reqs;2505  };2506  XHR.Group.prototype = {2507    send: function() {2508      for (var i = 0, reqs = this.reqs, l = reqs.length; i < l; ++i) {2509        reqs[i].send();2510      }2511    }2512  };2513  var JSONP = function(opt) {2514    opt = $.merge({2515      url: 'http://philogljs.org/',2516      data: {},2517      noCache: false,2518      onComplete: $.empty,2519      callbackKey: 'callback'2520    }, opt || {});2521    2522    var index = JSONP.counter++;2523    //create query string2524    var data = [];2525    for(var prop in opt.data) {2526      data.push(prop + '=' + opt.data[prop]);2527    }2528    data = data.join('&');2529    //append unique id for cache2530    if (opt.noCache) {2531      data += (data.indexOf('?') >= 0? '&' : '?') + $.uid();2532    }2533    //create source url2534    var src = opt.url + 2535      (opt.url.indexOf('?') > -1 ? '&' : '?') +2536      opt.callbackKey + '=PhiloGL.IO.JSONP.requests.request_' + index +2537      (data.length > 0 ? '&' + data : '');2538    //create script2539    var script = document.createElement('script');2540    script.type = 'text/javascript';2541    script.src = src;2542    //create callback2543    JSONP.requests['request_' + index] = function(json) {2544      opt.onComplete(json);2545      //remove script2546      if(script.parentNode) {2547        script.parentNode.removeChild(script);2548      }2549      if(script.clearAttributes) {2550        script.clearAttributes();2551      } 2552    };2553    //inject script2554    document.getElementsByTagName('head')[0].appendChild(script);2555  };2556  JSONP.counter = 0;2557  JSONP.requests = {};2558  //Load multiple Image assets async2559  var Images = function(opt) {2560    opt = $.merge({2561      src: [],2562      noCache: false,2563      onProgress: $.empty,2564      onComplete: $.empty2565    }, opt || {});2566    var count = 0, l = opt.src.length;2567    //Image onload handler2568    var load = function() {2569      opt.onProgress(Math.round(++count / l * 100));2570      if (count == l) {2571        opt.onComplete(images);2572      }2573    };2574    //Image error handler2575    var error = function() {2576      if (++count == l) {2577        opt.onComplete(images);2578      }2579    };2580    //uid for image sources2581    var noCache = opt.noCache,2582        uid = $.uid(),2583        getSuffix = function(s) { return (s.indexOf('?') >= 0? '&' : '?') + uid; };2584    //Create image array2585    var images = opt.src.map(function(src, i) {2586      var img = new Image();2587      img.index = i;2588      img.onload = load;2589      img.onerror = error;2590      img.src = src + (noCache? getSuffix(src) : '');2591      return img;2592    });2593    return images;2594  };2595  //Load multiple textures from images2596  var Textures = function(opt) {2597    opt = $.merge({2598      src: [],2599      noCache: false,2600      onComplete: $.empty2601    }, opt || {});2602    Images({2603      src: opt.src,2604      noCache: opt.noCache,2605      onComplete: function(images) {2606        var textures = {};2607        images.forEach(function(img, i) {2608          textures[opt.id && opt.id[i] || opt.src && opt.src[i]] = $.merge({2609            data: {2610              value: img2611            }2612          }, opt);2613        });2614        app.setTextures(textures);2615        opt.onComplete();2616      }2617    });2618  };2619  2620  IO.XHR = XHR;2621  IO.JSONP = JSONP;2622  IO.Images = Images;2623  IO.Textures = Textures;2624  PhiloGL.IO = IO;2625})();2626//camera.js2627//Provides a Camera with ModelView and Projection matrices2628(function () {2629  //Define some locals2630  var Vec3 = PhiloGL.Vec3,2631      Mat4 = PhiloGL.Mat4;2632  //Camera class2633  var Camera = function(fov, aspect, near, far, opt) {2634    opt = opt || {};2635    var pos = opt.position,2636        target = opt.target,2637        up = opt.up;2638    this.type = opt.type ? opt.type : 'perspective';2639    this.fov = fov;2640    this.near = near;2641    this.far = far;2642    this.aspect = aspect;2643    this.position = pos && new Vec3(pos.x, pos.y, pos.z) || new Vec3();2644    this.target = target && new Vec3(target.x, target.y, target.z) || new Vec3();2645    this.up = up && new Vec3(up.x, up.y, up.z) || new Vec3(0, 1, 0);2646    if (this.type == 'perspective') {2647      this.projection = new Mat4().perspective(fov, aspect, near, far);2648    } else {2649      var ymax = near * Math.tan(fov * Math.PI / 360),2650          ymin = -ymax,2651          xmin = ymin * aspect,2652          xmax = ymax * aspect;2653      this.projection = new Mat4().ortho(xmin, xmax, ymin, ymax, near, far);2654    }2655    this.view = new Mat4();2656  };2657  Camera.prototype = {2658    2659    update: function() {2660      if (this.type == 'perspective') {2661        this.projection = new Mat4().perspective(this.fov, this.aspect, this.near, this.far);2662      } else {2663        var ymax = this.near * Math.tan(this.fov * Math.PI / 360),2664            ymin = -ymax,2665            xmin = ymin * this.aspect,2666            xmax = ymax * this.aspect;2667        this.projection = new Mat4().ortho(xmin, xmax, ymin, ymax, this.near, this.far);2668      }2669      this.view.lookAt(this.position, this.target, this.up);  2670    },2671    //Set Camera view and projection matrix2672    setStatus: function (program) {2673      var camera = this,2674          pos = camera.position,2675          view = camera.view,2676          projection = camera.projection,2677          viewProjection = view.mulMat4(projection),2678          viewProjectionInverse = viewProjection.invert();2679      program.setUniforms({2680        cameraPosition: [pos.x, pos.y, pos.z],2681        projectionMatrix: projection,2682        viewMatrix: view,2683        viewProjectionMatrix: viewProjection,2684        viewInverseMatrix: view.invert(),2685        viewProjectionInverseMatrix: viewProjectionInverse2686      }); 2687    }2688  2689  };2690  PhiloGL.Camera = Camera;2691})();2692//o3d.js2693//Scene Objects2694(function () {2695  //Define some locals2696  var Vec3 = PhiloGL.Vec3,2697      Mat4 = PhiloGL.Mat4,2698      cos = Math.cos,2699      sin = Math.sin,2700      pi = Math.PI,2701      max = Math.max,2702      slice = Array.prototype.slice;2703  function normalizeColors(arr, len) {2704    if (arr && arr.length < len) {2705      var a0 = arr[0],2706          a1 = arr[1],2707          a2 = arr[2],2708          a3 = arr[3],2709          ans = [a0, a1, a2, a3],2710          times = len / arr.length,2711          index;2712      while (--times) {2713        index = times * 4;2714        ans[index    ] = a0;2715        ans[index + 1] = a1;2716        ans[index + 2] = a2;2717        ans[index + 3] = a3;2718      }2719      return new Float32Array(ans);2720    } else {2721      return arr;2722    }2723  }2724  //Model repository2725  var O3D = {2726      //map attribute names to property names2727      //TODO(nico): textures are treated separately.2728      attributeMap: {2729        'position': 'vertices',2730        'normal': 'normals',2731        'pickingColor': 'pickingColors',2732        'colors': 'color'2733      }2734  };2735  //Model abstract O3D Class2736  O3D.Model = function(opt) {2737    opt = opt || {};2738    this.id = opt.id || $.uid();2739    //picking options2740    this.pickable = !!opt.pickable;2741    this.pick = opt.pick || function() { return false; };2742    this.vertices = opt.vertices;2743    this.normals = opt.normals;2744    this.textures = opt.textures && $.splat(opt.textures);2745    this.colors = opt.colors;2746    this.indices = opt.indices;2747    this.shininess = opt.shininess || 0;2748    this.reflection = opt.reflection || 0;2749    this.refraction = opt.refraction || 0;2750    if (opt.pickingColors) {2751      this.pickingColors = opt.pickingColors;2752    }2753    if (opt.texCoords) {2754      this.texCoords = opt.texCoords;2755    }2756    //extra uniforms2757    this.uniforms = opt.uniforms || {};2758    //extra attribute descriptors2759    this.attributes = opt.attributes || {};2760    //override the render method2761    this.render = opt.render;2762    //whether to render as triangles, lines, points, etc.2763    this.drawType = opt.drawType || 'TRIANGLES';2764    //whether to display the object at all2765    this.display = 'display' in opt? opt.display : true;2766    //before and after render callbacks2767    this.onBeforeRender = opt.onBeforeRender || $.empty;2768    this.onAfterRender = opt.onAfterRender || $.empty;2769    //set a custom program per o3d2770    if (opt.program) {2771      this.program = opt.program;2772    }2773    //model position, rotation, scale and all in all matrix2774    this.position = new Vec3;2775    this.rotation = new Vec3;2776    this.scale = new Vec3(1, 1, 1);2777    this.matrix = new Mat4;2778    if (opt.computeCentroids) {2779      this.computeCentroids();2780    }2781    if (opt.computeNormals) {2782      this.computeNormals();2783    }2784  };2785  //Buffer setter mixin2786  var Setters = {2787    setUniforms: function(program) {2788      program.setUniforms(this.uniforms);2789    },2790    setAttributes: function(program) {2791      var attributes = this.attributes;2792      for (var name in attributes) {2793        var descriptor = attributes[name],2794            bufferId = this.id + '-' + name;2795        if (!Object.keys(descriptor).length) {2796          program.setBuffer(bufferId, true);2797        } else {2798          descriptor.attribute = name;2799          program.setBuffer(bufferId, descriptor);2800          delete descriptor.value;2801        }2802      }2803    },2804    setVertices: function(program) {2805      if (!this.$vertices) return;2806      if (this.dynamic) {2807        program.setBuffer('position-' + this.id, {2808          attribute: 'position',2809          value: this.$vertices,2810          size: 32811        });2812      } else {2813        program.setBuffer('position-' + this.id);2814      }2815    },2816    setNormals: function(program) {2817      if (!this.$normals) return;2818      if (this.dynamic) {2819        program.setBuffer('normal-' + this.id, {2820          attribute: 'normal',2821          value: this.$normals,2822          size: 32823        });2824      } else {2825        program.setBuffer('normal-' + this.id);2826      }2827    },2828    setIndices: function(program) {2829      if (!this.$indices) return;2830      if (this.dynamic) {2831        program.setBuffer('indices-' + this.id, {2832          bufferType: gl.ELEMENT_ARRAY_BUFFER,2833          drawType: gl.STATIC_DRAW,2834          value: this.$indices,2835          size: 12836        });2837      } else {2838        program.setBuffer('indices-' + this.id);2839      }2840    },2841    setPickingColors: function(program) {2842      if (!this.$pickingColors) return;2843      if (this.dynamic) {2844        program.setBuffer('pickingColor-' + this.id, {2845          attribute: 'pickingColor',2846          value: this.$pickingColors,2847          size: 42848        });2849      } else {2850        program.setBuffer('pickingColor-' + this.id);2851      }2852    },2853    setColors: function(program) {2854      if (!this.$colors) return;2855      if (this.dynamic) {2856        program.setBuffer('color-' + this.id, {2857          attribute: 'color',2858          value: this.$colors,2859          size: 42860        });2861      } else {2862        program.setBuffer('color-' + this.id);2863      }2864    },2865    setTexCoords: function(program) {2866      if (!this.$texCoords) return;2867      var id = this.id,2868          i, txs, l, tex;2869      if (this.dynamic) {2870        //If is an object containing textureName -> textureCoordArray2871        //Set all textures, samplers and textureCoords.2872        if ($.type(this.$texCoords) == 'object') {2873          for (i = 0, txs = this.textures, l = txs.length; i < l; i++) {2874            tex = txs[i];2875            program.setBuffer('texCoord-' + i + '-' + id, {2876              attribute: 'texCoord' + (i + 1),2877              value: this.$texCoords[tex],2878              size: 22879            });2880          }2881        //An array of textureCoordinates2882        } else {2883          program.setBuffer('texCoord-' + id, {2884            attribute: 'texCoord1',2885            value: this.$texCoords,2886            size: 22887          });2888        }2889      } else {2890        if ($.type(this.$texCoords) == 'object') {2891          for (i = 0, txs = this.textures, l = txs.length; i < l; i++) {2892            program.setBuffer('texCoord-' + i + '-' + id);2893          }2894        } else {2895          program.setBuffer('texCoord-' + id);2896        }2897      }2898    },2899    setTextures: function(program, force) {2900      this.textures = this.textures? $.splat(this.textures) : [];2901      var dist = 5;2902      for (var i = 0, texs = this.textures, l = texs.length, mtexs = PhiloGL.Scene.MAX_TEXTURES; i < mtexs; i++) {2903        if (i < l) {2904          var isCube = app.textureMemo[texs[i]].isCube;2905          if (isCube) {2906            program.setUniform('hasTextureCube' + (i + 1), true);2907            program.setTexture(texs[i], gl['TEXTURE' + (i + dist)]);2908          } else {2909            program.setUniform('hasTexture' + (i + 1), true);2910            program.setTexture(texs[i], gl['TEXTURE' + i]);2911          }2912        } else {2913          program.setUniform('hasTextureCube' + (i + 1), false);2914          program.setUniform('hasTexture' + (i + 1), false);2915        }2916        program.setUniform('sampler' + (i + 1), i);2917        program.setUniform('samplerCube' + (i + 1), i + dist);2918      }2919    },2920    setState: function(program) {2921      this.setUniforms(program);2922      this.setAttributes(program);2923      this.setVertices(program);2924      this.setColors(program);2925      this.setPickingColors(program);2926      this.setNormals(program);2927      this.setTextures(program);2928      this.setTexCoords(program);2929      this.setIndices(program);2930    },2931    unsetState: function(program) {2932      var attributes = program.attributes;2933      //unbind the array and element buffers2934      gl.bindBuffer(gl.ARRAY_BUFFER, null);2935      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);2936      for (var name in attributes) {2937        gl.disableVertexAttribArray(attributes[name]);2938      }2939    }2940 };2941  //ensure known attributes use typed arrays2942  O3D.Model.prototype = Object.create(null, {2943    hash: {2944      get: function() {2945        return this.id + ' ' + this.$pickingIndex;2946      }2947    },2948    vertices: {2949      set: function(val) {2950        if (!val) {2951            delete this.$vertices;2952            delete this.$verticesLength;2953            return;2954        }2955        var vlen = val.length;2956        if (val.BYTES_PER_ELEMENT) {2957          this.$vertices = val;2958        } else {2959          if (this.$verticesLength == vlen) {2960            this.$vertices.set(val);2961          } else {2962            this.$vertices = new Float32Array(val);2963          }2964        }2965        this.$verticesLength = vlen;2966      },2967      get: function() {2968        return this.$vertices;2969      }2970    },2971    normals: {2972      set: function(val) {2973        if (!val) {2974            delete this.$normals;2975            delete this.$normalsLength;2976            return;2977        }2978        var vlen = val.length;2979        if (val.BYTES_PER_ELEMENT) {2980          this.$normals = val;2981        } else {2982          if (this.$normalsLength == vlen) {2983            this.$normals.set(val);2984          } else {2985            this.$normals = new Float32Array(val);2986          }2987        }2988        this.$normalsLength = vlen;2989      },2990      get: function() {2991        return this.$normals;2992      }2993    },2994    colors: {2995      set: function(val) {2996        if (!val) {2997            delete this.$colors;2998            delete this.$colorsLength;2999            return;3000        }3001        var vlen = val.length;3002        if (val.BYTES_PER_ELEMENT) {3003          this.$colors = val;3004        } else {3005          if (this.$colorsLength == vlen) {3006            this.$colors.set(val);3007          } else {3008            this.$colors = new Float32Array(val);3009          }3010        }3011        if (this.$vertices && this.$verticesLength / 3 * 4 != vlen) {3012          this.$colors = normalizeColors(slice.call(this.$colors), this.$verticesLength / 3 * 4);3013        }3014        this.$colorsLength = this.$colors.length;3015      },3016      get: function() {3017        return this.$colors;3018      }3019    },3020    pickingColors: {3021      set: function(val) {3022        if (!val) {3023            delete this.$pickingColors;3024            delete this.$pickingColorsLength;3025            return;3026        }3027        var vlen = val.length;3028        if (val.BYTES_PER_ELEMENT) {3029          this.$pickingColors = val;3030        } else {3031          if (this.$pickingColorsLength == vlen) {3032            this.$pickingColors.set(val);3033          } else {3034            this.$pickingColors = new Float32Array(val);3035          }3036        }3037        if (this.$vertices && this.$verticesLength / 3 * 4 != vlen) {3038          this.$pickingColors = normalizeColors(slice.call(this.$pickingColors), this.$verticesLength / 3 * 4);3039        }3040        this.$pickingColorsLength = this.$pickingColors.length;3041      },3042      get: function() {3043        return this.$pickingColors;3044      }3045    },3046    texCoords: {3047      set: function(val) {3048        if (!val) {3049            delete this.$texCoords;3050            delete this.$texCoordsLength;3051            return;3052        }3053        if ($.type(val) == 'object') {3054          var ans = {};3055          for (var prop in val) {3056            var texCoordArray = val[prop];3057            ans[prop] = texCoordArray.BYTES_PER_ELEMENT ? texCoordArray : new Float32Array(texCoordArray);3058          }3059          this.$texCoords = ans;3060        } else {3061          var vlen = val.length;3062          if (val.BYTES_PER_ELEMENT) {3063            this.$texCoords = val;3064          } else {3065            if (this.$texCoordsLength == vlen) {3066              this.$texCoords.set(val);3067            } else {3068              this.$texCoords = new Float32Array(val);3069            }3070          }3071          this.$texCoordsLength = vlen;3072        }3073      },3074      get: function() {3075        return this.$texCoords;3076      }3077    },3078    indices: {3079      set: function(val) {3080        if (!val) {3081            delete this.$indices;3082            delete this.$indicesLength;3083            return;3084        }3085        var vlen = val.length;3086        if (val.BYTES_PER_ELEMENT) {3087          this.$indices = val;3088        } else {3089          if (this.$indicesLength == vlen) {3090            this.$indices.set(val);3091          } else {3092            this.$indices = new Uint16Array(val);3093          }3094        }3095        this.$indicesLength = vlen;3096      },3097      get: function() {3098        return this.$indices;3099      }3100    }3101  });3102  $.extend(O3D.Model.prototype, {3103    $$family: 'model',3104    update: function() {3105      var matrix = this.matrix,3106          pos = this.position,3107          rot = this.rotation,3108          scale = this.scale;3109      matrix.id();3110      matrix.$translate(pos.x, pos.y, pos.z);3111      matrix.$rotateXYZ(rot.x, rot.y, rot.z);3112      matrix.$scale(scale.x, scale.y, scale.z);3113    },3114    computeCentroids: function() {3115      var faces = this.faces,3116          vertices = this.vertices,3117          centroids = [];3118      faces.forEach(function(face) {3119        var centroid = [0, 0, 0],3120            acum = 0;3121        face.forEach(function(idx) {3122          var vertex = vertices[idx];3123          centroid[0] += vertex[0];3124          centroid[1] += vertex[1];3125          centroid[2] += vertex[2];3126          acum++;3127        });3128        centroid[0] /= acum;3129        centroid[1] /= acum;3130        centroid[2] /= acum;3131        centroids.push(centroid);3132      });3133      this.centroids = centroids;3134    },3135    computeNormals: function() {3136      var faces = this.faces,3137          vertices = this.vertices,3138          normals = [];3139      faces.forEach(function(face) {3140        var v1 = vertices[face[0]],3141            v2 = vertices[face[1]],3142            v3 = vertices[face[2]],3143            dir1 = {3144              x: v3[0] - v2[0],3145              y: v3[1] - v2[1],3146              z: v3[1] - v2[2]3147            },3148            dir2 = {3149              x: v1[0] - v2[0],3150              y: v1[1] - v2[1],3151              z: v1[2] - v2[2]3152            };3153        Vec3.$cross(dir2, dir1);3154        if (Vec3.norm(dir2) > 1e-6) {3155          Vec3.unit(dir2);3156        }3157        normals.push([dir2.x, dir2.y, dir2.z]);3158      });3159      this.normals = normals;3160    }3161  });3162  //Apply our Setters mixin3163  $.extend(O3D.Model.prototype, Setters);3164  //Now some primitives, Cube, Sphere, Cone, Cylinder3165  //Cube3166  O3D.Cube = function(config) {3167    O3D.Model.call(this, $.extend({3168      vertices: [-1, -1,  1,3169                 1, -1,  1,3170                 1,  1,  1,3171                -1,  1,  1,3172                -1, -1, -1,3173                -1,  1, -1,3174                 1,  1, -1,3175                 1, -1, -1,3176                -1,  1, -1,3177                -1,  1,  1,3178                 1,  1,  1,3179                 1,  1, -1,3180                -1, -1, -1,3181                 1, -1, -1,3182                 1, -1,  1,3183                -1, -1,  1,3184                 1, -1, -1,3185                 1,  1, -1,3186                 1,  1,  1,3187                 1, -1,  1,3188                -1, -1, -1,3189                -1, -1,  1,3190                -1,  1,  1,3191                -1,  1, -1],3192      texCoords: [0.0, 0.0,3193                  1.0, 0.0,3194                  1.0, 1.0,3195                  0.0, 1.0,3196                  // Back face3197                  1.0, 0.0,3198                  1.0, 1.0,3199                  0.0, 1.0,3200                  0.0, 0.0,3201                  // Top face3202                  0.0, 1.0,3203                  0.0, 0.0,3204                  1.0, 0.0,3205                  1.0, 1.0,3206                  // Bottom face3207                  1.0, 1.0,3208                  0.0, 1.0,3209                  0.0, 0.0,3210                  1.0, 0.0,3211                  // Right face3212                  1.0, 0.0,3213                  1.0, 1.0,3214                  0.0, 1.0,3215                  0.0, 0.0,3216                  // Left face3217                  0.0, 0.0,3218                  1.0, 0.0,3219                  1.0, 1.0,3220                  0.0, 1.0],3221      normals: [3222        // Front face3223        0.0,  0.0,  1.0,3224        0.0,  0.0,  1.0,3225        0.0,  0.0,  1.0,3226        0.0,  0.0,  1.0,3227        // Back face3228        0.0,  0.0, -1.0,3229        0.0,  0.0, -1.0,3230        0.0,  0.0, -1.0,3231        0.0,  0.0, -1.0,3232        // Top face3233        0.0,  1.0,  0.0,3234        0.0,  1.0,  0.0,3235        0.0,  1.0,  0.0,3236        0.0,  1.0,  0.0,3237        // Bottom face3238        0.0, -1.0,  0.0,3239        0.0, -1.0,  0.0,3240        0.0, -1.0,  0.0,3241        0.0, -1.0,  0.0,3242        // Right face3243        1.0,  0.0,  0.0,3244        1.0,  0.0,  0.0,3245        1.0,  0.0,  0.0,3246        1.0,  0.0,  0.0,3247        // Left face3248        -1.0,  0.0,  0.0,3249        -1.0,  0.0,  0.0,3250        -1.0,  0.0,  0.0,3251        -1.0,  0.0,  0.03252      ],3253      indices: [0, 1, 2, 0, 2, 3,3254                4, 5, 6, 4, 6, 7,3255                8, 9, 10, 8, 10, 11,3256                12, 13, 14, 12, 14, 15,3257                16, 17, 18, 16, 18, 19,3258                20, 21, 22, 20, 22, 23]3259    }, config || {}));3260  };3261  O3D.Cube.prototype = Object.create(O3D.Model.prototype);3262  //Primitives constructors inspired by TDL http://code.google.com/p/webglsamples/,3263  //copyright 2011 Google Inc. new BSD License (http://www.opensource.org/licenses/bsd-license.php).3264  O3D.Sphere = function(opt) {3265      var nlat = opt.nlat || 10,3266           nlong = opt.nlong || 10,3267           radius = opt.radius || 1,3268           startLat = 0,3269           endLat = pi,3270           latRange = endLat - startLat,3271           startLong = 0,3272           endLong = 2 * pi,3273           longRange = endLong - startLong,3274           numVertices = (nlat + 1) * (nlong + 1),3275           vertices = new Float32Array(numVertices * 3),3276           normals = new Float32Array(numVertices * 3),3277           texCoords = new Float32Array(numVertices * 2),3278           indices = new Uint16Array(nlat * nlong * 6);3279      if (typeof radius == 'number') {3280        var value = radius;3281        radius = function(n1, n2, n3, u, v) {3282          return value;3283        };3284      }3285      //Create vertices, normals and texCoords3286      for (var y = 0; y <= nlat; y++) {3287        for (var x = 0; x <= nlong; x++) {3288          var u = x / nlong,3289              v = y / nlat,3290              theta = longRange * u,3291              phi = latRange * v,3292              sinTheta = sin(theta),3293              cosTheta = cos(theta),3294              sinPhi = sin(phi),3295              cosPhi = cos(phi),3296              ux = cosTheta * sinPhi,3297              uy = cosPhi,3298              uz = sinTheta * sinPhi,3299              r = radius(ux, uy, uz, u, v),3300              index = x + y * (nlong + 1),3301              i3 = index * 3,3302              i2 = index * 2;3303          vertices[i3 + 0] = r * ux;3304          vertices[i3 + 1] = r * uy;3305          vertices[i3 + 2] = r * uz;3306          normals[i3 + 0] = ux;3307          normals[i3 + 1] = uy;3308          normals[i3 + 2] = uz;3309          texCoords[i2 + 0] = u;3310          texCoords[i2 + 1] = v;3311        }3312      }3313      //Create indices3314      var numVertsAround = nlat + 1;3315      for (x = 0; x < nlat; x++) {3316        for (y = 0; y < nlong; y++) {3317          var index = (x * nlong + y) * 6;3318          indices[index + 0] = y * numVertsAround + x;3319          indices[index + 1] = y * numVertsAround + x + 1;3320          indices[index + 2] = (y + 1) * numVertsAround + x;3321          indices[index + 3] = (y + 1) * numVertsAround + x;3322          indices[index + 4] = y * numVertsAround + x + 1;3323          indices[index + 5] = (y + 1) * numVertsAround + x + 1;3324        }3325      }3326      O3D.Model.call(this, $.extend({3327        vertices: vertices,3328        indices: indices,3329        normals: normals,3330        texCoords: texCoords3331      }, opt || {}));3332  };3333  O3D.Sphere.prototype = Object.create(O3D.Model.prototype);3334  //Code based on http://blog.andreaskahler.com/2009/06/creating-icosphere-mesh-in-code.html3335  O3D.IcoSphere = function(opt) {3336    var iterations = opt.iterations || 0,3337        vertices = [],3338        indices = [],3339        sqrt = Math.sqrt,3340        acos = Math.acos,3341        atan2 = Math.atan2,3342        pi = Math.PI,3343        pi2 = pi * 2;3344    //Add a callback for when a vertex is created3345    opt.onAddVertex = opt.onAddVertex || $.empty;3346    // and Icosahedron vertices3347    var t = (1 + sqrt(5)) / 2,3348        len = sqrt(1 + t * t);3349    vertices.push(-1 / len,  t / len,  0,3350                   1 / len,  t / len,  0,3351                  -1 / len, -t / len,  0,3352                   1 / len, -t / len,  0,3353                   0, -1 / len,  t / len,3354                   0,  1 / len,  t / len,3355                   0, -1 / len, -t / len,3356                   0,  1 / len, -t / len,3357                   t / len,  0, -1 / len,3358                   t / len,  0,  1 / len,3359                  -t / len,  0, -1 / len,3360                  -t / len,  0,  1 / len);3361      indices.push(0, 11, 5,3362                 0, 5, 1,3363                 0, 1, 7,3364                 0, 7, 10,3365                 0, 10, 11,3366                 1, 5, 9,3367                 5, 11, 4,3368                 11, 10, 2,3369                 10, 7, 6,3370                 7, 1, 8,3371                 3, 9, 4,3372                 3, 4, 2,3373                 3, 2, 6,3374                 3, 6, 8,3375                 3, 8, 9,3376                 4, 9, 5,3377                 2, 4, 11,3378                 6, 2, 10,3379                 8, 6, 7,3380                 9, 8, 1);3381    var getMiddlePoint = (function() {3382      var pointMemo = {};3383      return function(i1, i2) {3384        i1 *= 3;3385        i2 *= 3;3386        var mini = i1 < i2 ? i1 : i2,3387            maxi = i1 > i2 ? i1 : i2,3388            key = mini + '|' + maxi;3389        if (key in pointMemo) {3390          return pointMemo[key];3391        }3392        var x1 = vertices[i1    ],3393            y1 = vertices[i1 + 1],3394            z1 = vertices[i1 + 2],3395            x2 = vertices[i2    ],3396            y2 = vertices[i2 + 1],3397            z2 = vertices[i2 + 2],3398            xm = (x1 + x2) / 2,3399            ym = (y1 + y2) / 2,3400            zm = (z1 + z2) / 2,3401            len = sqrt(xm * xm + ym * ym + zm * zm);3402        xm /= len;3403        ym /= len;3404        zm /= len;3405        vertices.push(xm, ym, zm);3406        return (pointMemo[key] = (vertices.length / 3 - 1));3407      };3408    })();3409    for (var i = 0; i < iterations; i++) {3410      var indices2 = [];3411      for (var j = 0, l = indices.length; j < l; j += 3) {3412        var a = getMiddlePoint(indices[j    ], indices[j + 1]),3413            b = getMiddlePoint(indices[j + 1], indices[j + 2]),3414            c = getMiddlePoint(indices[j + 2], indices[j    ]);3415        indices2.push(indices[j], a, c,3416                      indices[j + 1], b, a,3417                      indices[j + 2], c, b,3418                      a, b, c);3419      }3420      indices = indices2;3421    }3422    //Calculate texCoords and normals3423    var l = indices.length,3424        normals = new Float32Array(l * 3),3425        texCoords = new Float32Array(l * 2);3426    for (var i = 0; i < l; i += 3) {3427      var i1 = indices[i    ],3428          i2 = indices[i + 1],3429          i3 = indices[i + 2],3430          in1 = i1 * 3,3431          in2 = i2 * 3,3432          in3 = i3 * 3,3433          iu1 = i1 * 2,3434          iu2 = i2 * 2,3435          iu3 = i3 * 2,3436          x1 = vertices[in1    ],3437          y1 = vertices[in1 + 1],3438          z1 = vertices[in1 + 2],3439          theta1 = acos(z1 / sqrt(x1 * x1 + y1 * y1 + z1 * z1)),3440          phi1 = atan2(y1, x1),3441          v1 = theta1 / pi,3442          u1 = 1 - phi1 / pi2,3443          x2 = vertices[in2    ],3444          y2 = vertices[in2 + 1],3445          z2 = vertices[in2 + 2],3446          theta2 = acos(z2 / sqrt(x2 * x2 + y2 * y2 + z2 * z2)),3447          phi2 = atan2(y2, x2),3448          v2 = theta2 / pi,3449          u2 = 1 - phi2 / pi2,3450          x3 = vertices[in3    ],3451          y3 = vertices[in3 + 1],3452          z3 = vertices[in3 + 2],3453          theta3 = acos(z3 / sqrt(x3 * x3 + y3 * y3 + z3 * z3)),3454          phi3 = atan2(y3, x3),3455          v3 = theta3 / pi,3456          u3 = 1 - phi3 / pi2,3457          vec1 = {3458            x: x3 - x2,3459            y: y3 - y2,3460            z: z3 - z23461          },3462          vec2 = {3463            x: x1 - x2,3464            y: y1 - y2,3465            z: z1 - z23466          },3467          normal = Vec3.cross(vec1, vec2).$unit();3468      normals[in1    ] = normals[in2    ] = normals[in3    ] = normal.x;3469      normals[in1 + 1] = normals[in2 + 1] = normals[in3 + 1] = normal.y;3470      normals[in1 + 2] = normals[in2 + 2] = normals[in3 + 2] = normal.z;3471      texCoords[iu1    ] = u1;3472      texCoords[iu1 + 1] = v1;3473      texCoords[iu2    ] = u2;3474      texCoords[iu2 + 1] = v2;3475      texCoords[iu3    ] = u3;3476      texCoords[iu3 + 1] = v3;3477    }3478    O3D.Model.call(this, $.extend({3479      vertices: vertices,3480      indices: indices,3481      normals: normals,3482      texCoords: texCoords3483    }, opt || {}));3484  };3485  O3D.IcoSphere.prototype = Object.create(O3D.Model.prototype);3486  O3D.TruncatedCone = function(config) {3487    var bottomRadius = config.bottomRadius || 0,3488        topRadius = config.topRadius || 0,3489        height = config.height || 1,3490        nradial = config.nradial || 10,3491        nvertical = config.nvertical || 10,3492        topCap = !!config.topCap,3493        bottomCap = !!config.bottomCap,3494        extra = (topCap? 2 : 0) + (bottomCap? 2 : 0),3495        numVertices = (nradial + 1) * (nvertical + 1 + extra),3496        vertices = new Float32Array(numVertices * 3),3497        normals = new Float32Array(numVertices * 3),3498        texCoords = new Float32Array(numVertices * 2),3499        indices = new Uint16Array(nradial * (nvertical + extra) * 6),3500        vertsAroundEdge = nradial + 1,3501        math = Math,3502        slant = math.atan2(bottomRadius - topRadius, height),3503        msin = math.sin,3504        mcos = math.cos,3505        mpi = math.PI,3506        cosSlant = mcos(slant),3507        sinSlant = msin(slant),3508        start = topCap? -2 : 0,3509        end = nvertical + (bottomCap? 2 : 0),3510        i3 = 0,3511        i2 = 0;3512    for (var i = start; i <= end; i++) {3513      var v = i / nvertical,3514          y = height * v,3515          ringRadius;3516      if (i < 0) {3517        y = 0;3518        v = 1;3519        ringRadius = bottomRadius;3520      } else if (i > nvertical) {3521        y = height;3522        v = 1;3523        ringRadius = topRadius;3524      } else {3525        ringRadius = bottomRadius +3526          (topRadius - bottomRadius) * (i / nvertical);3527      }3528      if (i == -2 || i == nvertical + 2) {3529        ringRadius = 0;3530        v = 0;3531      }3532      y -= height / 2;3533      for (var j = 0; j < vertsAroundEdge; j++) {3534        var sin = msin(j * mpi * 2 / nradial);3535        var cos = mcos(j * mpi * 2 / nradial);3536        vertices[i3 + 0] = sin * ringRadius;3537        vertices[i3 + 1] = y;3538        vertices[i3 + 2] = cos * ringRadius;3539        normals[i3 + 0] = (i < 0 || i > nvertical) ? 0 : (sin * cosSlant);3540        normals[i3 + 1] = (i < 0) ? -1 : (i > nvertical ? 1 : sinSlant);3541        normals[i3 + 2] = (i < 0 || i > nvertical) ? 0 : (cos * cosSlant);3542        texCoords[i2 + 0] = j / nradial;3543        texCoords[i2 + 1] = v;3544        i2 += 2;3545        i3 += 3;3546      }3547    }3548    for (i = 0; i < nvertical + extra; i++) {3549      for (j = 0; j < nradial; j++) {3550        var index = (i * nradial + j) * 6;3551        indices[index + 0] = vertsAroundEdge * (i + 0) + 0 + j;3552        indices[index + 1] = vertsAroundEdge * (i + 0) + 1 + j;3553        indices[index + 2] = vertsAroundEdge * (i + 1) + 1 + j;3554        indices[index + 3] = vertsAroundEdge * (i + 0) + 0 + j;3555        indices[index + 4] = vertsAroundEdge * (i + 1) + 1 + j;3556        indices[index + 5] = vertsAroundEdge * (i + 1) + 0 + j;3557      }3558    }3559    O3D.Model.call(this, $.extend({3560      vertices: vertices,3561      normals: normals,3562      texCoords: texCoords,3563      indices: indices3564    }, config || {}));3565  };3566  O3D.TruncatedCone.prototype = Object.create(O3D.Model.prototype);3567  O3D.Cone = function(config) {3568    config.topRadius = 0;3569    config.topCap = !!config.cap;3570    config.bottomCap = !!config.cap;3571    config.bottomRadius = config.radius || 3;3572    O3D.TruncatedCone.call(this, config);3573  };3574  O3D.Cone.prototype = Object.create(O3D.TruncatedCone.prototype);3575  O3D.Cylinder = function(config) {3576    config.bottomRadius = config.radius;3577    config.topRadius = config.radius;3578    O3D.TruncatedCone.call(this, config);3579  };3580  O3D.Cylinder.prototype = Object.create(O3D.TruncatedCone.prototype);3581  O3D.Plane = function(config) {3582    var type = config.type,3583        coords = type.split(','),3584        c1len = config[coords[0] + 'len'], //width3585        c2len = config[coords[1] + 'len'], //height3586        subdivisions1 = config['n' + coords[0]] || 1, //subdivisionsWidth3587        subdivisions2 = config['n' + coords[1]] || 1, //subdivisionsDepth3588        offset = config.offset,3589        flipCull = !!config.flipCull, 3590        numVertices = (subdivisions1 + 1) * (subdivisions2 + 1),3591        positions = new Float32Array(numVertices * 3),3592        normals = new Float32Array(numVertices * 3),3593        texCoords = new Float32Array(numVertices * 2),3594        i2 = 0, i3 = 0;3595    if (flipCull) {3596      c1len = - c1len;3597    }3598    3599    for (var z = 0; z <= subdivisions2; z++) {3600      for (var x = 0; x <= subdivisions1; x++) {3601        var u = x / subdivisions1,3602            v = z / subdivisions2;3603        if (flipCull) {3604          texCoords[i2 + 0] = 1 - u;3605        } else {3606          texCoords[i2 + 0] = u;3607        }3608        texCoords[i2 + 1] = v;3609        i2 += 2;3610        switch (type) {3611          case 'x,y':3612            positions[i3 + 0] = c1len * u - c1len * 0.5;3613            positions[i3 + 1] = c2len * v - c2len * 0.5;3614            positions[i3 + 2] = offset;3615            normals[i3 + 0] = 0;3616            normals[i3 + 1] = 0;3617            if (flipCull) {3618              normals[i3 + 2] = 1;3619            } else {3620              normals[i3 + 2] = -1;3621            }3622          break;3623          case 'x,z':3624            positions[i3 + 0] = c1len * u - c1len * 0.5;3625            positions[i3 + 1] = offset;3626            positions[i3 + 2] = c2len * v - c2len * 0.5;3627            normals[i3 + 0] = 0;3628            if (flipCull) {3629              normals[i3 + 1] = 1;3630            } else {3631              normals[i3 + 1] = -1;3632            }3633            normals[i3 + 2] = 0;3634          break;3635          case 'y,z':3636            positions[i3 + 0] = offset;3637            positions[i3 + 1] = c1len * u - c1len * 0.5;3638            positions[i3 + 2] = c2len * v - c2len * 0.5;3639            if (flipCull) {3640              normals[i3 + 0] = 1;3641            } else {3642              normals[i3 + 0] = -1;3643            }3644            normals[i3 + 1] = 0;3645            normals[i3 + 2] = 0;3646          break;3647        }3648        i3 += 3;3649      }3650    }3651    var numVertsAcross = subdivisions1 + 1,3652        indices = [];3653    for (z = 0; z < subdivisions2; z++) {3654      for (x = 0; x < subdivisions1; x++) {3655        var index = (z * subdivisions1 + x) * 6;3656        // Make triangle 1 of quad.3657        indices[index + 0] = (z + 0) * numVertsAcross + x;3658        indices[index + 1] = (z + 1) * numVertsAcross + x;3659        indices[index + 2] = (z + 0) * numVertsAcross + x + 1;3660        // Make triangle 2 of quad.3661        indices[index + 3] = (z + 1) * numVertsAcross + x;3662        indices[index + 4] = (z + 1) * numVertsAcross + x + 1;3663        indices[index + 5] = (z + 0) * numVertsAcross + x + 1;3664      }3665    }3666    O3D.Model.call(this, $.extend({3667      vertices: positions,3668      normals: normals,3669      texCoords: texCoords,3670      indices: indices3671    }, config));3672  };3673  O3D.Plane.prototype = Object.create(O3D.Model.prototype);3674  //unique id3675  O3D.id = $.time();3676  //Assign to namespace3677  PhiloGL.O3D = O3D;3678})();3679//shaders.js3680//Default Shaders3681(function() {3682  //Add default shaders3683  var Shaders = {3684    Vertex: {},3685    Fragment: {}3686  };3687  var VertexShaders = Shaders.Vertex,3688      FragmentShaders = Shaders.Fragment;3689  VertexShaders.Default = [3690    "#define LIGHT_MAX 4",3691    //object attributes3692    "attribute vec3 position;",3693    "attribute vec3 normal;",3694    "attribute vec4 color;",3695    "attribute vec4 pickingColor;",3696    "attribute vec2 texCoord1;",3697    //camera and object matrices3698    "uniform mat4 viewMatrix;",3699    "uniform mat4 viewInverseMatrix;",3700    "uniform mat4 projectionMatrix;",3701    "uniform mat4 viewProjectionMatrix;",3702    //objectMatrix * viewMatrix = worldMatrix3703    "uniform mat4 worldMatrix;",3704    "uniform mat4 worldInverseMatrix;",3705    "uniform mat4 worldInverseTransposeMatrix;",3706    "uniform mat4 objectMatrix;",3707    "uniform vec3 cameraPosition;",3708    //lighting configuration3709    "uniform bool enableLights;",3710    "uniform vec3 ambientColor;",3711    "uniform vec3 directionalColor;",3712    "uniform vec3 lightingDirection;",3713    //point lights configuration3714    "uniform vec3 pointLocation[LIGHT_MAX];",3715    "uniform vec3 pointColor[LIGHT_MAX];",3716    "uniform int numberPoints;",3717    //reflection / refraction configuration3718		"uniform bool useReflection;",3719    //varyings3720		"varying vec3 vReflection;",3721    "varying vec4 vColor;",3722    "varying vec4 vPickingColor;",3723    "varying vec2 vTexCoord;",3724    "varying vec4 vNormal;",3725    "varying vec3 lightWeighting;",3726    "void main(void) {",3727      "vec4 mvPosition = worldMatrix * vec4(position, 1.0);",3728      "vec4 transformedNormal = worldInverseTransposeMatrix * vec4(normal, 1.0);",3729      //lighting code3730      "if(!enableLights) {",3731        "lightWeighting = vec3(1.0, 1.0, 1.0);",3732      "} else {",3733        "vec3 plightDirection;",3734        "vec3 pointWeight = vec3(0.0, 0.0, 0.0);",3735        "float directionalLightWeighting = max(dot(transformedNormal.xyz, lightingDirection), 0.0);",3736        "for (int i = 0; i < LIGHT_MAX; i++) {",3737          "if (i < numberPoints) {",3738            "plightDirection = normalize((viewMatrix * vec4(pointLocation[i], 1.0)).xyz - mvPosition.xyz);",3739            "pointWeight += max(dot(transformedNormal.xyz, plightDirection), 0.0) * pointColor[i];",3740          "} else {",3741            "break;",3742          "}",3743        "}",3744        "lightWeighting = ambientColor + (directionalColor * directionalLightWeighting) + pointWeight;",3745      "}",3746      //refraction / reflection code3747      "if (useReflection) {",3748        "vReflection = (viewInverseMatrix[3] - (worldMatrix * vec4(position, 1.0))).xyz;",3749      "} else {",3750        "vReflection = vec3(1.0, 1.0, 1.0);",3751      "}",3752      //pass results to varyings3753      "vColor = color;",3754      "vPickingColor = pickingColor;",3755      "vTexCoord = texCoord1;",3756      "vNormal = transformedNormal;",3757      "gl_Position = projectionMatrix * worldMatrix * vec4(position, 1.0);",3758    "}"3759  ].join("\n");3760 FragmentShaders.Default = [3761    "#ifdef GL_ES",3762    "precision highp float;",3763    "#endif",3764    //varyings3765    "varying vec4 vColor;",3766    "varying vec4 vPickingColor;",3767    "varying vec2 vTexCoord;",3768    "varying vec3 lightWeighting;",3769    "varying vec3 vReflection;",3770    "varying vec4 vNormal;",3771    //texture configs3772    "uniform bool hasTexture1;",3773    "uniform sampler2D sampler1;",3774    "uniform bool hasTextureCube1;",3775		"uniform samplerCube samplerCube1;",3776    //picking configs3777    "uniform bool enablePicking;",3778    "uniform bool hasPickingColors;",3779    "uniform vec3 pickColor;",3780		//reflection / refraction configs3781		"uniform float reflection;",3782		"uniform float refraction;",3783    //fog configuration3784    "uniform bool hasFog;",3785    "uniform vec3 fogColor;",3786    "uniform float fogNear;",3787    "uniform float fogFar;",3788    "void main(){",3789      //set color from texture3790      "if (!hasTexture1) {",3791        "gl_FragColor = vec4(vColor.rgb * lightWeighting, vColor.a);",3792      "} else {",3793        "gl_FragColor = vec4(texture2D(sampler1, vec2(vTexCoord.s, vTexCoord.t)).rgb * lightWeighting, 1.0);",3794      "}",3795      //has cube texture then apply reflection3796     "if (hasTextureCube1) {",3797       "vec3 nReflection = normalize(vReflection);",3798       "vec3 reflectionValue;",3799       "if (refraction > 0.0) {",3800        "reflectionValue = refract(nReflection, vNormal.xyz, refraction);",3801       "} else {",3802        "reflectionValue = -reflect(nReflection, vNormal.xyz);",3803       "}",3804       //TODO(nico): check whether this is right.3805       "vec4 cubeColor = textureCube(samplerCube1, vec3(-reflectionValue.x, -reflectionValue.y, reflectionValue.z));",3806       "gl_FragColor = vec4(mix(gl_FragColor.xyz, cubeColor.xyz, reflection), 1.0);",3807     "}",3808      //set picking3809      "if (enablePicking) {",3810        "if (hasPickingColors) {",3811          "gl_FragColor = vPickingColor;",3812        "} else {",3813          "gl_FragColor = vec4(pickColor, 1.0);",3814        "}",3815      "}",3816      //handle fog3817      "if (hasFog) {",3818        "float depth = gl_FragCoord.z / gl_FragCoord.w;",3819        "float fogFactor = smoothstep(fogNear, fogFar, depth);",3820        "gl_FragColor = mix(gl_FragColor, vec4(fogColor, gl_FragColor.w), fogFactor);",3821      "}",3822    "}"3823  ].join("\n");3824  PhiloGL.Shaders = Shaders;3825})();3826//scene.js3827//Scene Object management and rendering3828(function() {3829  //Define some locals3830  var Vec3 = PhiloGL.Vec3,3831      Mat4 = PhiloGL.Mat4;3832  //Scene class3833  var Scene = function(program, camera, opt) {3834    opt = $.merge({3835      lights: {3836        enable: false,3837        //ambient light3838        ambient: {3839          r: 0.2,3840          g: 0.2,3841          b: 0.23842        },3843        //directional light3844        directional: {3845          direction: {3846            x: 1,3847            y: 1,3848            z: 13849          },3850          color: {3851            r: 0,3852            g: 0,3853            b: 03854          }3855        }3856        //point light3857        //points: []3858      },3859      effects: {3860        fog: false3861        // { near, far, color }3862      }3863    }, opt || {});3864    this.program = opt.program ? program[opt.program] : program;3865    this.camera = camera;3866    this.models = [];3867    this.config = opt;3868  };3869  Scene.prototype = {3870    add: function() {3871      for (var i = 0, models = this.models, l = arguments.length; i < l; i++) {3872        var model = arguments[i];3873        //Generate unique id for model3874        model.id = model.id || $.uid();3875        models.push(model);3876        //Create and load Buffers3877        this.defineBuffers(model);3878      }3879    },3880    remove: function(model) {3881      var models = this.models,3882          indexOf = models.indexOf(model);3883      if (indexOf > -1) {3884        models.splice(indexOf, 1);3885      }3886    },3887    getProgram: function(obj) {3888      var program = this.program;3889      if (program.$$family != 'program' && obj && obj.program) {3890        program = program[obj.program];3891        program.use();3892        return program;3893      }3894      return program;3895    },3896    defineBuffers: function(obj) {3897      var program = this.getProgram(obj),3898          prevDynamic = obj.dynamic;3899      obj.dynamic = true;3900      obj.setState(program);3901      obj.dynamic = prevDynamic;3902      obj.unsetState(program);3903    },3904    beforeRender: function(program) {3905      //Setup lighting and scene effects like fog, etc.3906      this.setupLighting(program);3907      this.setupEffects(program);3908      if (this.camera) {3909        this.camera.setStatus(program);3910      }3911    },3912    //Setup the lighting system: ambient, directional, point lights.3913    setupLighting: function(program) {3914      //Setup Lighting3915      var abs = Math.abs,3916          camera = this.camera,3917          cpos = camera.position,3918          light = this.config.lights,3919          ambient = light.ambient,3920          directional = light.directional,3921          dcolor = directional.color,3922          dir = directional.direction,3923          enable = light.enable,3924          points = light.points && $.splat(light.points) || [],3925          numberPoints = points.length,3926          pointLocations = [],3927          pointColors = [],3928          enableSpecular = [],3929          pointSpecularColors = [];3930      //Normalize lighting direction vector3931      dir = new Vec3(dir.x, dir.y, dir.z).$unit().$scale(-1);3932      //Set light uniforms. Ambient and directional lights.3933      program.setUniform('enableLights', enable);3934      if (!enable) return;3935      program.setUniform('ambientColor', [ambient.r, ambient.g, ambient.b]);3936      program.setUniform('directionalColor', [dcolor.r, dcolor.g, dcolor.b]);3937      program.setUniform('lightingDirection', [dir.x, dir.y, dir.z]);3938      //Set point lights3939      program.setUniform('numberPoints', numberPoints);3940      for (var i = 0, l = numberPoints; i < l; i++) {3941        var point = points[i],3942            position = point.position,3943            color = point.color || point.diffuse,3944            spec = point.specular;3945        pointLocations.push(position.x, position.y, position.z);3946        pointColors.push(color.r, color.g, color.b);3947        //Add specular color3948        enableSpecular.push(+!!spec);3949        if (spec) {3950          pointSpecularColors.push(spec.r, spec.g, spec.b);3951        } else {3952          pointSpecularColors.push(0, 0, 0);3953        }3954      }3955      program.setUniforms({3956        'pointLocation': pointLocations,3957        'pointColor': pointColors3958      });3959      program.setUniforms({3960        'enableSpecular': enableSpecular,3961        'pointSpecularColor': pointSpecularColors3962      });3963    },3964    //Setup effects like fog, etc.3965    setupEffects: function(program) {3966      var config = this.config.effects,3967          fog = config.fog,3968          color = fog.color || { r: 0.5, g: 0.5, b: 0.5 };3969      if (fog) {3970        program.setUniforms({3971          'hasFog': true,3972          'fogNear': fog.near,3973          'fogFar': fog.far,3974          'fogColor': [color.r, color.g, color.b]3975        });3976      } else {3977        program.setUniform('hasFog', false);3978      }3979    },3980    //Renders all objects in the scene.3981    render: function(opt) {3982      opt = opt || {};3983      var camera = this.camera,3984          program = this.program,3985          renderProgram = opt.renderProgram,3986          pType = $.type(program),3987          multiplePrograms = !renderProgram && pType == 'object',3988          options = $.extend({3989            onBeforeRender: $.empty,3990            onAfterRender: $.empty3991          }, opt || {});3992      //If we're just using one program then3993      //execute the beforeRender method once.3994      !multiplePrograms && this.beforeRender(renderProgram || program);3995      //Go through each model and render it.3996      for (var i = 0, models = this.models, l = models.length; i < l; ++i) {3997        var elem = models[i];3998        if (elem.display) {3999          var program = renderProgram || this.getProgram(elem);4000          //Setup the beforeRender method for each object4001          //when there are multiple programs to be used.4002          multiplePrograms && this.beforeRender(program);4003          elem.onBeforeRender(program, camera);4004          options.onBeforeRender(elem, i);4005          this.renderObject(elem, program);4006          options.onAfterRender(elem, i);4007          elem.onAfterRender(program, camera);4008        }4009      }4010    },4011    renderToTexture: function(name, opt) {4012      opt = opt || {};4013      var texture = app.textures[name + '-texture'],4014          texMemo = app.textureMemo[name + '-texture'];4015      this.render(opt);4016      gl.bindTexture(texMemo.textureType, texture);4017      //gl.generateMipmap(texMemo.textureType);4018      //gl.bindTexture(texMemo.textureType, null);4019    },4020    renderObject: function(obj, program) {4021      var camera = this.camera,4022          view = camera.view,4023          projection = camera.projection,4024          object = obj.matrix,4025          world = view.mulMat4(object),4026          worldInverse = world.invert(),4027          worldInverseTranspose = worldInverse.transpose();4028      obj.setState(program);4029      //Now set view and normal matrices4030      program.setUniforms({4031        objectMatrix: object,4032        worldMatrix: world,4033        worldInverseMatrix: worldInverse,4034        worldInverseTransposeMatrix: worldInverseTranspose4035//        worldViewProjection:  view.mulMat4(object).$mulMat4(view.mulMat4(projection))4036      });4037      //Draw4038      //TODO(nico): move this into O3D, but, somehow, abstract the gl.draw* methods inside that object.4039      if (obj.render) {4040        obj.render(gl, program, camera);4041      } else {4042        if (obj.$indicesLength) {4043          gl.drawElements((obj.drawType !== undefined) ? gl.get(obj.drawType) : gl.TRIANGLES, obj.$indicesLength, gl.UNSIGNED_SHORT, 0);4044        } else {4045          gl.drawArrays((obj.drawType !== undefined) ? gl.get(obj.drawType) : gl.TRIANGLES, 0, obj.$verticesLength / 3);4046        }4047      }4048      obj.unsetState(program);4049    },4050    //setup picking framebuffer4051    setupPicking: function() {4052      //create picking program4053      var program = PhiloGL.Program.fromDefaultShaders(),4054          floor = Math.floor;4055      //create framebuffer4056      app.setFrameBuffer('$picking', {4057        width: 5,4058        height: 1,4059        bindToTexture: {4060          parameters: [{4061            name: 'TEXTURE_ MAG_FILTER',4062            value: 'LINEAR'4063          }, {4064            name: 'TEXTURE_MIN_FILTER',4065            value: 'LINEAR',4066            generateMipmap: false4067          }]4068        },4069        bindToRenderBuffer: true4070      });4071      app.setFrameBuffer('$picking', false);4072      this.pickingProgram = program;4073    },4074    //returns an element at the given position4075    pick: function(x, y, lazy) {4076      //setup the picking program if this is4077      //the first time we enter the method.4078      if (!this.pickingProgram) {4079        this.setupPicking();4080      }4081      var o3dHash = {},4082          o3dList = [],4083          program = app.usedProgram,4084          pickingProgram = this.pickingProgram,4085          camera = this.camera,4086          oldtarget = camera.target,4087          oldaspect = camera.aspect,4088          config = this.config,4089          memoLightEnable = config.lights.enable,4090          memoFog = config.effects.fog,4091          width = gl.canvas.width,4092          height = gl.canvas.height,4093          floor = Math.floor,4094          pickingRes = Scene.PICKING_RES,4095          resWidth = 5,4096          resHeight = 1,4097          ndcx = x * 2 / width - 1,4098          ndcy = 1 - y * 2 / height,4099          target = this.unproject([ndcx, ndcy,  1.0], camera),4100          hash = [],4101          pixel = new Uint8Array(1 * 1 * 4),4102          index = 0,4103          backgroundColor, capture, pindex;4104      this.camera.target = target;4105      this.camera.update ();4106      //setup the scene for picking4107      config.lights.enable = false;4108      config.effects.fog = false;4109      //enable picking and render to texture4110      app.setFrameBuffer('$picking', true);4111      pickingProgram.use();4112      pickingProgram.setUniform('enablePicking', true);4113      //render the scene to a texture4114      gl.disable(gl.BLEND);4115      gl.viewport(0, 0, resWidth, resHeight);4116      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);4117      //read the background color so we don't step on it4118      gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);4119      backgroundColor = pixel[0] + pixel[1] * 256 + pixel[2] * 256 * 256;4120      //render picking scene4121      this.renderPickingScene({4122        background: backgroundColor,4123        o3dHash: o3dHash,4124        o3dList: o3dList,4125        hash: hash4126      });4127      // the target point is in the center of the screen,4128      // so it should be the center point.4129      gl.readPixels(2, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);4130      var stringColor = [pixel[0], pixel[1], pixel[2]].join(),4131          elem = o3dHash[stringColor],4132          pick;4133      if (!elem) {4134        for (var i = 0, l = o3dList.length; i < l; i++) {4135          elem = o3dList[i];4136          pick = elem.pick(pixel);4137          if (pick !== false) {4138            elem.$pickingIndex = pick;4139          } else {4140            elem = false;4141          }4142        }4143      }4144      //restore all values and unbind buffers4145      app.setFrameBuffer('$picking', false);4146      app.setTexture('$picking-texture', false);4147      pickingProgram.setUniform('enablePicking', false);4148      config.lights.enable = memoLightEnable;4149      config.effects.fog = memoFog;4150      //restore previous program4151      if (program) program.use();4152      //restore the viewport size to original size4153      gl.viewport(0, 0, width, height);4154      //restore camera properties4155      camera.target = oldtarget;4156      camera.aspect = oldaspect;4157      camera.update();4158      //store model hash and pixel array4159      this.o3dHash = o3dHash;4160      this.o3dList = o3dList;4161      this.pixel = pixel;4162      this.capture = capture;4163      return elem && elem.pickable && elem;4164    },4165    unproject: function(pt, camera) {4166      return camera.view.invert().mulMat4(camera.projection.invert()).mulVec3(pt);4167    },4168    renderPickingScene: function(opt) {4169      //if set through the config, render a custom scene.4170      if (this.config.renderPickingScene) {4171        this.config.renderPickingScene.call(this, opt);4172        return;4173      }4174      var pickingProgram = this.pickingProgram,4175          o3dHash = opt.o3dHash,4176          o3dList = opt.o3dList,4177          background = opt.background,4178          hash = opt.hash,4179          index = 0;4180      //render to texture4181      this.renderToTexture('$picking', {4182        renderProgram: pickingProgram,4183        onBeforeRender: function(elem, i) {4184          if (i == background) {4185            index = 1;4186          }4187          var suc = i + index,4188              hasPickingColors = !!elem.pickingColors;4189          pickingProgram.setUniform('hasPickingColors', hasPickingColors);4190          if (!hasPickingColors) {4191            hash[0] = suc % 256;4192            hash[1] = ((suc / 256) >> 0) % 256;4193            hash[2] = ((suc / (256 * 256)) >> 0) % 256;4194            pickingProgram.setUniform('pickColor', [hash[0] / 255, hash[1] / 255, hash[2] / 255]);4195            o3dHash[hash.join()] = elem;4196          } else {4197            o3dList.push(elem);4198          }4199        }4200      });4201    },4202    resetPicking: $.empty4203  };4204  Scene.MAX_TEXTURES = 10;4205  Scene.MAX_POINT_LIGHTS = 4;4206  Scene.PICKING_RES = 4;4207  PhiloGL.Scene = Scene;4208})();4209//workers.js4210//4211(function () {4212  function WorkerGroup(fileName, n) {4213    var workers = this.workers = [];4214    while (n--) {4215      workers.push(new Worker(fileName));4216    }4217  }4218  WorkerGroup.prototype = {4219    map: function(callback) {4220      var workers = this.workers;4221      var configs = this.configs = [];4222      for (var i = 0, l = workers.length; i < l; i++) {4223        configs.push(callback && callback(i));4224      }4225      return this;4226    },4227    reduce: function(opt) {4228      var fn = opt.reduceFn,4229          workers = this.workers,4230          configs = this.configs,4231          l = workers.length,4232          acum = opt.initialValue,4233          message = function (e) {4234            l--;4235            if (acum === undefined) {4236              acum = e.data;4237            } else {4238              acum = fn(acum, e.data);4239            }4240            if (l == 0) {4241              opt.onComplete(acum);4242            }4243          };4244      for (var i = 0, ln = l; i < ln; i++) {4245        var w = workers[i];4246        w.onmessage = message;4247        w.postMessage(configs[i]);4248      }4249      return this;4250    }4251  };4252  PhiloGL.WorkerGroup = WorkerGroup;4253})();4254(function() {4255  //Timer based animation4256  var Fx = function(options) {4257      this.opt = $.merge({4258        delay: 0,4259        duration: 1000,4260        transition: function(x) { return x; },4261        onCompute: $.empty,4262        onComplete: $.empty4263      }, options || {});4264  };4265  var Queue = Fx.Queue = [];4266  Fx.prototype = {4267    time:null,4268    4269    start: function(options) {4270      this.opt = $.merge(this.opt, options || {});4271      this.time = $.time();4272      this.animating = true;4273      Queue.push(this);4274    },4275    //perform a step in the animation4276    step: function() {4277      //if not animating, then return4278      if (!this.animating) return;4279      var currentTime = $.time(), 4280          time = this.time,4281          opt = this.opt,4282          delay = opt.delay,4283          duration = opt.duration,4284          delta = 0;4285      //hold animation for the delay4286      if (currentTime < time + delay) {4287        opt.onCompute.call(this, delta);4288        return;4289      }4290      //if in our time window, then execute animation4291      if (currentTime < time + delay + duration) {4292        delta = opt.transition((currentTime - time - delay) / duration);4293        opt.onCompute.call(this, delta);4294      } else {4295        this.animating = false;4296        opt.onCompute.call(this, 1);4297        opt.onComplete.call(this);4298      }4299    }4300  };4301  4302  Fx.compute = function(from, to, delta) {4303    return from + (to - from) * delta;4304  };4305  //Easing equations4306  Fx.Transition = {4307    linear: function(p){4308      return p;4309    }4310  };4311  var Trans = Fx.Transition;4312  (function(){4313    var makeTrans = function(transition, params){4314      params = $.splat(params);4315      return $.extend(transition, {4316        easeIn: function(pos){4317          return transition(pos, params);4318        },4319        easeOut: function(pos){4320          return 1 - transition(1 - pos, params);4321        },4322        easeInOut: function(pos){4323          return (pos <= 0.5)? transition(2 * pos, params) / 2 : (2 - transition(4324              2 * (1 - pos), params)) / 2;4325        }4326      });4327    };4328    var transitions = {4329      Pow: function(p, x){4330        return Math.pow(p, x[0] || 6);4331      },4332      Expo: function(p){4333        return Math.pow(2, 8 * (p - 1));4334      },4335      Circ: function(p){4336        return 1 - Math.sin(Math.acos(p));4337      },4338      Sine: function(p){4339        return 1 - Math.sin((1 - p) * Math.PI / 2);4340      },4341      Back: function(p, x){4342        x = x[0] || 1.618;4343        return Math.pow(p, 2) * ((x + 1) * p - x);4344      },4345      Bounce: function(p){4346        var value;4347        for ( var a = 0, b = 1; 1; a += b, b /= 2) {4348          if (p >= (7 - 4 * a) / 11) {4349            value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2);4350            break;4351          }4352        }4353        return value;4354      },4355      Elastic: function(p, x){4356        return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3);4357      }4358    };4359    for (var t in transitions) {4360      Trans[t] = makeTrans(transitions[t]);4361    }4362    ['Quad', 'Cubic', 'Quart', 'Quint'].forEach(function(elem, i){4363      Trans[elem] = makeTrans(function(p){4364        return Math.pow(p, [4365          i + 24366        ]);4367      });4368    });4369  })();4370  //animationTime - function branching4371  var global = self || window,4372      checkFxQueue = function() {4373        var newQueue = [];4374        if (Queue.length) {4375          for (var i = 0, l = Queue.length, fx; i < l; i++) {4376            fx = Queue[i];4377            fx.step();4378            if (fx.animating) {4379              newQueue.push(fx);4380            }4381          }4382          Fx.Queue = Queue = newQueue;4383        }4384      };4385  if (global) {4386    var found = false;4387    ['webkitAnimationTime', 'mozAnimationTime', 'animationTime',4388     'webkitAnimationStartTime', 'mozAnimationStartTime', 'animationStartTime'].forEach(function(impl) {4389      if (impl in global) {4390        Fx.animationTime = function() {4391          return global[impl];4392        };4393        found = true;4394      }4395    });4396    if (!found) {4397      Fx.animationTime = $.time;4398    }4399    //requestAnimationFrame - function branching4400    found = false;4401    ['webkitRequestAnimationFrame', 'mozRequestAnimationFrame', 'requestAnimationFrame'].forEach(function(impl) {4402      if (impl in global) {4403        Fx.requestAnimationFrame = function(callback) {4404          global[impl](function() {4405            checkFxQueue();4406            callback();4407          });4408        };4409        found = true;4410      }4411    });4412    if (!found) {4413      Fx.requestAnimationFrame = function(callback) {4414        setTimeout(function() {4415          checkFxQueue();4416          callback();4417        }, 1000 / 60);4418      };4419    }4420  }4421  4422  PhiloGL.Fx = Fx;4423})();4424//media.js4425//media has utility functions for image, video and audio manipulation (and4426//maybe others like device, etc).4427(function() {4428  var Media = {};4429  var Image = function() {};4430  //post process an image by setting it to a texture with a specified fragment4431  //and vertex shader.4432  Image.postProcess = (function() {4433    var plane = new PhiloGL.O3D.Plane({4434      type: 'x,y',4435      xlen: 1,4436      ylen: 1,4437      offset: 04438    }), camera = new PhiloGL.Camera(45, 1, 0.1, 500, {4439      position: { x: 0, y: 0, z: 1.205 }4440    }), scene = new PhiloGL.Scene({}, camera);4441    return function(opt) {4442      var program = app.program.$$family ? app.program : app.program[opt.program],4443          textures = opt.fromTexture ? $.splat(opt.fromTexture) : [],4444          framebuffer = opt.toFrameBuffer,4445          screen = !!opt.toScreen,4446          width = opt.width || app.canvas.width,4447          height = opt.height || app.canvas.height;4448      camera.aspect = opt.aspectRatio ? opt.aspectRatio : Math.max(height / width, width / height);4449      camera.update();4450      scene.program = program;4451      plane.textures = textures;4452      plane.program = program;4453      if(!scene.models.length) {4454          scene.add(plane);4455      }4456      if (framebuffer) {4457        //create framebuffer4458        if (!(framebuffer in app.frameBufferMemo)) {4459          app.setFrameBuffer(framebuffer, {4460            width: width,4461            height: height,4462            bindToTexture: {4463              parameters: [{4464                name: 'TEXTURE_MAG_FILTER',4465                value: 'LINEAR'4466              }, {4467                name: 'TEXTURE_MIN_FILTER',4468                value: 'LINEAR',4469                generateMipmap: false4470              }]4471            },4472            bindToRenderBuffer: false4473          });4474        }4475        program.use();4476        app.setFrameBuffer(framebuffer, true);4477        gl.viewport(0, 0, width, height);4478        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);4479        program.setUniforms(opt.uniforms || {});4480        scene.renderToTexture(framebuffer);4481        app.setFrameBuffer(framebuffer, false);4482      }4483      if (screen) {4484        program.use();4485        gl.viewport(0, 0, width, height);4486        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);4487        program.setUniforms(opt.uniforms || {});4488        scene.render();4489      }4490      return this;4491    };4492  })();4493  Media.Image = Image;4494  PhiloGL.Media = Media;4495})();...git.py
Source:git.py  
1"""Functions for interacting with hg"""2import os3import subprocess4import urlparse5import urllib6import re7from util.commands import run_cmd, remove_path, run_quiet_cmd8from util.file import safe_unlink9import logging10log = logging.getLogger(__name__)11class DefaultShareBase:12    pass13DefaultShareBase = DefaultShareBase()14def _make_absolute(repo):15    if repo.startswith("file://"):16        # Make file:// urls absolute17        path = repo[len("file://"):]18        repo = "file://%s" % os.path.abspath(path)19    elif "://" not in repo:20        repo = os.path.abspath(repo)21    return repo22def get_repo_name(repo):23    bits = urlparse.urlsplit(repo)24    host = urllib.quote(bits.netloc, "")25    path = urllib.quote(bits.path.lstrip("/"), "")26    return os.path.join(host, path)27def has_revision(dest, revision):28    """Returns True if revision exists in dest"""29    try:30        run_quiet_cmd(['git', 'log', '--oneline', '-n1', revision], cwd=dest)31        return True32    except subprocess.CalledProcessError:33        return False34def has_ref(dest, refname):35    """Returns True if refname exists in dest.36    refname can be a branch or tag name."""37    try:38        run_quiet_cmd(['git', 'show-ref', '-d', refname], cwd=dest)39        return True40    except subprocess.CalledProcessError:41        return False42def init(dest, bare=False):43    """Initializes an empty repository at dest. If dest exists and isn't empty, it will be removed.44    If `bare` is True, then a bare repo will be created."""45    if not os.path.isdir(dest):46        log.info("removing %s", dest)47        safe_unlink(dest)48    else:49        for f in os.listdir(dest):50            f = os.path.join(dest, f)51            log.info("removing %s", f)52            if os.path.isdir(f):53                remove_path(f)54            else:55                safe_unlink(f)56    # Git will freak out if it tries to create intermediate directories for57    # dest, and then they exist. We can hit this when pulling in multiple repos58    # in parallel to shared repo paths that contain common parent directories59    # Let's create all the directories first60    try:61        os.makedirs(dest)62    except OSError, e:63        if e.errno == 20:64            # Not a directory error...one of the parents of dest isn't a65            # directory66            raise67    if bare:68        cmd = ['git', 'init', '--bare', '-q', dest]69    else:70        cmd = ['git', 'init', '-q', dest]71    log.info(" ".join(cmd))72    run_quiet_cmd(cmd)73def is_git_repo(dest):74    """Returns True if dest is a valid git repo"""75    if not os.path.isdir(dest):76        return False77    try:78        proc = subprocess.Popen(["git", "rev-parse", "--git-dir"], cwd=dest, stdout=subprocess.PIPE)79        if proc.wait() != 0:80            return False81        output = proc.stdout.read().strip()82        git_dir = os.path.normpath(os.path.join(dest, output))83        retval = (git_dir == dest or git_dir == os.path.join(dest, ".git"))84        return retval85    except subprocess.CalledProcessError:86        return False87def get_git_dir(dest):88    """Returns the path to the git directory for dest. For bare repos this is89    dest itself, for regular repos this is dest/.git"""90    assert is_git_repo(dest)91    cmd = ['git', 'config', '--bool', '--get', 'core.bare']92    proc = subprocess.Popen(cmd, cwd=dest, stdout=subprocess.PIPE)93    proc.wait()94    is_bare = proc.stdout.read().strip()95    if is_bare == "false":96        d = os.path.join(dest, ".git")97    else:98        d = dest99    assert os.path.exists(d)100    return d101def set_share(repo, share):102    alternates = os.path.join(get_git_dir(repo), 'objects', 'info', 'alternates')103    share_objects = os.path.join(get_git_dir(share), 'objects')104    with open(alternates, 'w') as f:105        f.write("%s\n" % share_objects)106def clean(repo):107    # Two '-f's means "clean submodules", which is what we want so far.108    run_cmd(['git', 'clean', '-f', '-f', '-d', '-x'], cwd=repo, stdout=subprocess.PIPE)109def add_remote(repo, remote_name, remote_repo):110    """Adds a remote named `remote_name` to the local git repo in `repo`111    pointing to `remote_repo`"""112    run_cmd(['git', 'remote', 'add', remote_name, remote_repo], cwd=repo)113def set_remote_url(repo, remote_name, remote_repo):114    """Sets the url for a remote"""115    run_cmd(['git', 'remote', 'set-url', remote_name, remote_repo], cwd=repo)116def get_remote(repo, remote_name):117    """Returns the url for the given remote, or None if the remote doesn't118    exist"""119    cmd = ['git', 'remote', '-v']120    proc = subprocess.Popen(cmd, cwd=repo, stdout=subprocess.PIPE)121    proc.wait()122    for line in proc.stdout.readlines():123        m = re.match(r"%s\s+(\S+) \(fetch\)$" % re.escape(remote_name), line)124        if m:125            return m.group(1)126def set_remote(repo, remote_name, remote_repo):127    """Sets remote named `remote_name` to `remote_repo`"""128    log.debug("%s: getting remotes", repo)129    my_remote = get_remote(repo, remote_name)130    if my_remote == remote_repo:131        return132    if my_remote is not None:133        log.info("%s: setting remote %s to %s (was %s)", repo, remote_name, remote_repo, my_remote)134        set_remote_url(repo, remote_name, remote_repo)135    else:136        log.info("%s: adding remote %s %s", repo, remote_name, remote_repo)137        add_remote(repo, remote_name, remote_repo)138def git(repo, dest, refname=None, revision=None, update_dest=True,139        shareBase=DefaultShareBase, mirrors=None, clean_dest=False):140    """Makes sure that `dest` is has `revision` or `refname` checked out from141    `repo`.142    Do what it takes to make that happen, including possibly clobbering143    dest.144    If `mirrors` is set, will try and use the mirrors before `repo`.145    """146    if shareBase is DefaultShareBase:147        shareBase = os.environ.get("GIT_SHARE_BASE_DIR", None)148    if shareBase is not None:149        repo_name = get_repo_name(repo)150        share_dir = os.path.join(shareBase, repo_name)151    else:152        share_dir = None153    if share_dir is not None and not is_git_repo(share_dir):154        log.info("creating bare repo %s", share_dir)155        try:156            init(share_dir, bare=True)157            os.utime(share_dir, None)158        except Exception:159            log.warning("couldn't create shared repo %s; disabling sharing", share_dir, exc_info=True)160            shareBase = None161            share_dir = None162    dest = os.path.abspath(dest)163    log.info("Checking dest %s", dest)164    if not is_git_repo(dest):165        if os.path.exists(dest):166            log.warning("%s doesn't appear to be a valid git directory; clobbering", dest)167            remove_path(dest)168        if share_dir is not None:169            # Initialize the repo and set up the share170            init(dest)171            set_share(dest, share_dir)172        else:173            # Otherwise clone into dest174            clone(repo, dest, refname=refname, mirrors=mirrors, update_dest=False)175    # Make sure our share is pointing to the right place176    if share_dir is not None:177        lock_file = os.path.join(get_git_dir(share_dir), "index.lock")178        if os.path.exists(lock_file):179            log.info("removing %s", lock_file)180            safe_unlink(lock_file)181        set_share(dest, share_dir)182    # If we're supposed to be updating to a revision, check if we183    # have that revision already. If so, then there's no need to184    # fetch anything.185    do_fetch = False186    if revision is None:187        # we don't have a revision specified, so pull in everything188        do_fetch = True189    elif has_ref(dest, revision):190        # revision is actually a ref name, so we need to run fetch191        # to make sure we update the ref192        do_fetch = True193    elif not has_revision(dest, revision):194        # we don't have this revision, so need to fetch it195        do_fetch = True196    if do_fetch:197        if share_dir:198            # Fetch our refs into our share199            try:200                # TODO: Handle fetching refnames like refs/tags/XXXX201                if refname is None:202                    fetch(repo, share_dir, mirrors=mirrors)203                else:204                    fetch(repo, share_dir, mirrors=mirrors, refname=refname)205            except subprocess.CalledProcessError:206                # Something went wrong!207                # Clobber share_dir and re-raise208                log.info("error fetching into %s - clobbering", share_dir)209                remove_path(share_dir)210                raise211            try:212                if refname is None:213                    fetch(share_dir, dest, fetch_remote="origin")214                else:215                    fetch(share_dir, dest, fetch_remote="origin", refname=refname)216            except subprocess.CalledProcessError:217                log.info("clobbering %s", share_dir)218                remove_path(share_dir)219                log.info("error fetching into %s - clobbering", dest)220                remove_path(dest)221                raise222        else:223            try:224                fetch(repo, dest, mirrors=mirrors, refname=refname)225            except Exception:226                log.info("error fetching into %s - clobbering", dest)227                remove_path(dest)228                raise229    # Set our remote230    set_remote(dest, 'origin', repo)231    if update_dest:232        log.info("Updating local copy refname: %s; revision: %s", refname, revision)233        # Sometimes refname is passed in as a revision234        if revision:235            if not has_revision(dest, revision) and has_ref(dest, 'origin/%s' % revision):236                log.info("Using %s as ref name instead of revision", revision)237                refname = revision238                revision = None239        rev = update(dest, refname=refname, revision=revision)240        if clean_dest:241            clean(dest)242        return rev243    if clean_dest:244        clean(dest)245def clone(repo, dest, refname=None, mirrors=None, shared=False, update_dest=True):246    """Clones git repo and places it at `dest`, replacing whatever else is247    there.  The working copy will be empty.248    If `mirrors` is set, will try and clone from the mirrors before249    cloning from `repo`.250    If `shared` is True, then git shared repos will be used251    If `update_dest` is False, then no working copy will be created252    """253    if os.path.exists(dest):254        remove_path(dest)255    if mirrors:256        log.info("Attempting to clone from mirrors")257        for mirror in mirrors:258            log.info("Cloning from %s", mirror)259            try:260                retval = clone(mirror, dest, refname, update_dest=update_dest)261                return retval262            except KeyboardInterrupt:263                raise264            except Exception:265                log.exception("Problem cloning from mirror %s", mirror)266                continue267        else:268            log.info("Pulling from mirrors failed; falling back to %s", repo)269    cmd = ['git', 'clone', '-q']270    if not update_dest:271        # TODO: Use --bare/--mirror here?272        cmd.append('--no-checkout')273    if refname:274        cmd.extend(['--branch', refname])275    if shared:276        cmd.append('--shared')277    cmd.extend([repo, dest])278    run_cmd(cmd)279    if update_dest:280        return get_revision(dest)281def update(dest, refname=None, revision=None, remote_name="origin"):282    """Updates working copy `dest` to `refname` or `revision`.  If neither is283    set then the working copy will be updated to the latest revision on the284    current refname.  Local changes will be discarded."""285    # If we have a revision, switch to that286    # We use revision^0 (and refname^0 below) to force the names to be287    # dereferenced into commit ids, which makes git check them out in a288    # detached state. This is equivalent to 'git checkout --detach', except is289    # supported by older versions of git290    if revision is not None:291        cmd = ['git', 'checkout', '-q', '-f', revision + '^0']292        run_cmd(cmd, cwd=dest)293    else:294        if not refname:295            refname = '%s/master' % remote_name296        else:297            refname = '%s/%s' % (remote_name, refname)298        cmd = ['git', 'checkout', '-q', '-f', refname + '^0']299        run_cmd(cmd, cwd=dest)300    return get_revision(dest)301def fetch(repo, dest, refname=None, remote_name="origin", fetch_remote=None, mirrors=None, fetch_tags=True):302    """Fetches changes from git repo and places it in `dest`.303    If `mirrors` is set, will try and fetch from the mirrors first before304    `repo`."""305    if mirrors:306        for mirror in mirrors:307            try:308                return fetch(mirror, dest, refname=refname)309            except KeyboardInterrupt:310                raise311            except Exception:312                log.exception("Problem fetching from mirror %s", mirror)313                continue314        else:315            log.info("Pulling from mirrors failed; falling back to %s", repo)316    # Convert repo to an absolute path if it's a local repository317    repo = _make_absolute(repo)318    cmd = ['git', 'fetch', '-q', repo]319    if not fetch_tags:320        # Don't fetch tags into our local tags/ refs since we have no way to321        # associate those with this remote and can't purge it later.322        cmd.append('--no-tags')323    if refname:324        if fetch_remote:325            cmd.append("+refs/remotes/{fetch_remote}/{refname}:refs/remotes/{remote_name}/{refname}".format(refname=refname, remote_name=remote_name, fetch_remote=fetch_remote))326        else:327            cmd.append("+refs/heads/{refname}:refs/remotes/{remote_name}/{refname}".format(refname=refname, remote_name=remote_name))328    else:329        if fetch_remote:330            cmd.append("+refs/remotes/{fetch_remote}/*:refs/remotes/{remote_name}/*".format(remote_name=remote_name, fetch_remote=fetch_remote))331        else:332            cmd.append("+refs/heads/*:refs/remotes/{remote_name}/*".format(remote_name=remote_name))333    run_cmd(cmd, cwd=dest)334def get_revision(path):335    """Returns which revision directory `path` currently has checked out."""336    proc = subprocess.Popen(['git', 'rev-parse', 'HEAD'], cwd=path, stdout=subprocess.PIPE)337    proc.wait()...studio2FieldDD.js
Source:studio2FieldDD.js  
1/**2 *3 * SugarCRM Community Edition is a customer relationship management program developed by4 * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.5 *6 * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.7 * Copyright (C) 2011 - 2018 SalesAgility Ltd.8 *9 * This program is free software; you can redistribute it and/or modify it under10 * the terms of the GNU Affero General Public License version 3 as published by the11 * Free Software Foundation with the addition of the following permission added12 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK13 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY14 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.15 *16 * This program is distributed in the hope that it will be useful, but WITHOUT17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS18 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more19 * details.20 *21 * You should have received a copy of the GNU Affero General Public License along with22 * this program; if not, see http://www.gnu.org/licenses or write to the Free23 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA24 * 02110-1301 USA.25 *26 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,27 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.28 *29 * The interactive user interfaces in modified source and object code versions30 * of this program must display Appropriate Legal Notices, as required under31 * Section 5 of the GNU Affero General Public License version 3.32 *33 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,34 * these Appropriate Legal Notices must retain the display of the "Powered by35 * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not36 * reasonably feasible for technical reasons, the Appropriate Legal Notices must37 * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".38 */39Studio2.FieldDD = function(id, sGroup) {40	Studio2.FieldDD.superclass.constructor.call(this, id, sGroup);41};42YAHOO.extend(Studio2.FieldDD, YAHOO.util.DDProxy, {43    startDrag: function(x, y) {44        // make the proxy look like the source element45		var dragEl = this.getDragEl();46		var clickEl = this.getEl();47		dragEl.innerHTML = clickEl.innerHTML;48		dragEl.className = clickEl.className;49		Studio2.copyId = null;50		this.showAnimation = true;51		if (Studio2.isSpecial(clickEl) && (Studio2.establishLocation(clickEl) == 'toolbox')) {52			var copy = Studio2.copyElement(clickEl);53			Studio2.setCopy(copy);54			clickEl.parentNode.insertBefore(copy,clickEl.nextSibling);55			YAHOO.util.Dom.setStyle(clickEl, "display", "none");	// don't want it to take up any space56		} else {57			YAHOO.util.Dom.setStyle(clickEl, "visibility", "hidden"); // want a empty space as we're dragging it away from this place58		}59        Studio2.setScrollObj(this);60    },61    endDrag: function(e) {62        Studio2.clearScrollObj();63     	ModuleBuilder.state.isDirty=true;64        var srcEl = this.getEl();65        var proxy = this.getDragEl();66        var proxyid = proxy.id;67        var thisid = this.id;68        if (YAHOO.util.Dom.get(srcEl)) { // if we have a valid srcEl still...hasn't been deleted earlier69			// Show the proxy element and animate it to the src element's location70        	YAHOO.util.Dom.setStyle(proxy, "visibility", "");71        	YAHOO.util.Dom.setStyle(srcEl, "display", ""); // display!=none for getXY to work72        	//YAHOO.util.Dom.setStyle(proxy).alignTo(srcEl, 'tl', null, {73				//callback: function(){74        	YAHOO.util.Dom.setStyle(proxyid, "visibility", "hidden");75			if(typeof(YAHOO.util.Dom.get(thisid)) != 'undefined' && YAHOO.util.Dom.get(thisid)!=null) 76				YAHOO.util.Dom.setStyle(thisid, "visibility", "");77		}78		if (Studio2.isSpecial(srcEl) && Studio2.copy()) {79			Studio2.activateCopy(); // activateCopy makes it active, and removes the flag that says there is a copy80		} 81		82		proxy.innerHTML = "";83    },84	onInvalidDrop: function(e) {85        Studio2.clearScrollObj();86		var dragEl = this.getDragEl();87		dragEl.innerHTML = '';88		Studio2.removeCopy();89		YAHOO.util.Dom.setStyle(this.getEl(), "display", "block");90	},91    onDrag: Studio2.onDrag,92    93    onDragDrop: function(e, id) {94		var srcEl = this.getEl();95		var destEl = YAHOO.util.Dom.get(id); // where this element is being dropped96		var srcLocation = Studio2.establishLocation(srcEl);97		var destLocation = Studio2.establishLocation(destEl);98		// CASE1: Trying to delete an item from the toolbox or move fields within the toolbox - don't allow99		if ( ((srcLocation == 'toolbox') && (destLocation == 'delete')) ||100			 ((srcLocation == 'toolbox') && (destLocation == 'toolbox'))) {101			Studio2.removeCopy();102			YAHOO.util.Dom.setStyle(srcEl, "display", "block");	// make it visible again - we made special elements invisible in startDrag103			return;104		}105		// CASE2: Delete a panel element106		// if source was in a panel (not toolbox) and destination is delete then remove this element107		if ((srcLocation == 'panels') && (destLocation == 'delete')) {108			if(Studio2.isSpecial(srcEl)) //nsingh- Bug 23057 Disallow deleting a (filler) as it does not make sense to do so.109				return;110			var parent = srcEl.parentNode;111			var sibling = srcEl.previousSibling;112			while(sibling != null) {113				if (sibling.className && (sibling.className.indexOf('le_field') != -1)) {114					break;115				}116				sibling = sibling.previousSibling;117			}118			if (sibling == null) {119				sibling = srcEl.nextSibling;120				while(sibling != null) {121					if (sibling.className && (sibling.className.indexOf('le_field') != -1)) {122						break;123					}124					sibling = sibling.nextSibling;125				}126			}127			Studio2.removeElement(srcEl);128			Studio2.unregisterExpandableField( srcEl );129//			this.showAnimation = false; // can't show animation as the source no longer exists130			if (sibling == null) {131	        	// If we've just deleted the last field from a panel then we need to tidy up132				Studio2.tidyFields(parent);133			} else {134				Studio2.registerExpandableField(sibling);135			}136			return;137		} // end delete138		// CASE3: Simple field swap139		// Either neither one is special, or they're both special and both in panels140		if (( ! Studio2.isSpecial(srcEl) && ! Studio2.isSpecial(destEl)) ||141			( Studio2.isSpecial(srcEl) && Studio2.isSpecial(destEl) && (srcLocation == 'panels') && (destLocation == 'panels')) ) {142			Studio2.swapElements(srcEl, destEl);143			this.runSpecialCode(srcEl, destEl);144			return;145		}146		// CASE4: swapping a special field from the toolbox with a field in a panel147		if (Studio2.copy() && (destLocation == 'panels')) {148			// CASE: split a field149			//Disallow (filler) on (filler)150			 if( Studio2.isSpecial(destEl) ) {Studio2.removeCopy(); return }151			var destSibling = Studio2.nextField( destEl ) || Studio2.prevField( destEl );152			if( Studio2.isExpandable( destEl ) && destEl.getAttribute("state") == 'expanded' ){153				Studio2.removeCopy(); return;154			}155			if( Studio2.isExpandable( destEl ) && destEl.getAttribute("state") == 'reduced' ){ Studio2.unregisterExpandableField( destEl ); }156			var copy = Studio2.copyElement(srcEl);157			Studio2.activateElement(copy);158			YAHOO.util.Dom.setStyle(copy, "display", "");159			Studio2.swapElements( Studio2.copy(),destEl );160			YAHOO.util.Dom.setStyle(srcEl, "display", "");161			Studio2.registerExpandableField (destSibling );162			return;163		}164		// CASE5: moving a plain field from the panel to a special field in the toolbox - just copy165		if ( ! Studio2.isSpecial(srcEl) && Studio2.isSpecial(destEl) && (destLocation == 'toolbox')) {166			// make a copy of the destination167			if(Studio2.isExpandable (srcEl ) && Studio2.isExpanded( srcEl)) {168				Studio2.toggleFieldWidth(srcEl.id); //bring back the old filler.169				Studio2.unregisterExpandableField ( srcEl );170			}171			//check if srcSibling needs to expand172//			var srcSibling = ;173			var copy = Studio2.copyElement(destEl);174			var destination = document.getElementById('availablefields');175			destination.appendChild(copy);176			Studio2.swapElements(copy,srcEl);177			YAHOO.util.Dom.setStyle(srcEl, "display", "");178			Studio2.activateElement(copy);179			//if src is expanded, reduce it then unregister180			//After Swap Only.181			Studio2.registerExpandableField( Studio2.nextField( srcEl ) || Studio2.prevField( srcEl ) );182			return;183		}184		//CASE6: (filler) droppped on a expandable field.185		if(Studio2.isSpecial(srcEl)  && destLocation == srcLocation  ){186			//Disallow Swap if dropping on a expanded field.187			if( Studio2.isExpandable( destEl ) && Studio2.isExpanded( destEl )) {return; }188			var srcSibling = Studio2.prevField( srcEl ) || Studio2.nextField( srcEl );189			var destSibling = Studio2.prevField( destEl ) || Studio2.nextField( destEl );190			Studio2.swapElements(srcEl, destEl); //don't change order.191			if ( !Studio2.isExpandable( destSibling ) && Studio2.isExpandable(srcSibling) && Studio2.isReduced(srcSibling) && !(srcSibling.id == destEl.id && srcEl.id == destSibling.id)) {192				Studio2.unregisterExpandableField( srcSibling );193				Studio2.registerExpandableField (destSibling );194				Studio2.unregisterExpandableField( destEl );195			}196			if ( !Studio2.isExpandable( destEl ) && Studio2.isSpecial( destSibling )) {197				Studio2.registerExpandableField (destEl );198			}199			if(!Studio2.isSpecial(destSibling)) {Studio2.registerExpandableField (destSibling )}200			return;201		}202		//CASE 7: A special field swapped with a regular field. Source is not-special, destination is special.203		if(!Studio2.isSpecial(srcEl) && Studio2.isSpecial(destEl) && destLocation == srcLocation) {204			/**205				if destination's left sibling is expandable.206					unregister left sibling from expandable.207				if src field's left sibling is not special208					register left sibling to expandable.209			*/210			var srcSibling = Studio2.prevField(srcEl) || Studio2.nextField( srcEl ) ;211			var destSibling = Studio2.prevField(destEl) || Studio2.nextField( destEl );212			var sameRow = (srcSibling!=null && destSibling!=null) ? (srcSibling.id == destEl.id && destSibling.id == srcEl.id) : false;213			if (Studio2.isExpandable( srcEl ) && Studio2.isExpanded( srcEl )) {return;} //disallow dropping expanded fields onto fillers.214			if (Studio2.isExpandable ( srcEl ) && Studio2.isReduced( srcEl ) && !sameRow) {Studio2.unregisterExpandableField( srcEl );}215			if (Studio2.isExpandable (destSibling) && !sameRow ){Studio2.unregisterExpandableField( destSibling )}216			//expand src sibling217			if( srcEl.id == destSibling.id && srcSibling.id == destEl.id ) {Studio2.registerExpandableField ( srcEl ) }218			Studio2.swapElements(srcEl, destEl);219			if (Studio2.isSpecial(destSibling)) {Studio2.registerExpandableField(srcEl)}220			Studio2.registerExpandableField( srcSibling );221			return;222		}223		if( !Studio2.isSpecial( srcEl ) && Studio2.isSpecial( destEl) && destLocation == 'panels' && srcLocation =='toolbox'){224			var destSibling = Studio2.nextField( destEl ) || Studio2.prevField ( destEl );225			Studio2.unregisterExpandableField( destSibling );226			Studio2.swapElements( srcEl,destEl );227			Studio2.removeElement( destEl ) ;228			return;229		}230		Studio2.swapElements( srcEl,destEl );231		this.runSpecialCode(srcEl,destEl);232		if ((srcLocation != destLocation)) {233			if (Studio2.isSpecial(srcEl) && ! Studio2.isSpecial(destEl))  {234				Studio2.removeElement(srcEl);235//				this.showAnimation = false;236				return;237			}238			if (Studio2.isSpecial(destEl) && ! Studio2.isSpecial(srcEl))  {239				Studio2.removeElement(destEl);240//				this.showAnimation = false;241				return;242			}243		}244    },245    runSpecialCode: function(srcEl, destEl){246		var srcLeftSibling = Studio2.prevField(srcEl);247		var srcRightSibling = Studio2.nextField(srcEl);248		var destRightSibling = Studio2.nextField(destEl);249		var destLeftSibling = Studio2.prevField(destEl);250	//For every affected element unexpand if needed.251	//registration vs Transformation.252		if ( Studio2.isExpandable (srcEl ) && Studio2.isExpandable( destEl) ){253			//src is dest now. copy dest's properties to src.254			Studio2.swapStates( srcEl, destEl );255			//srcEl.setAttribute("state", destEl.getAttribute("state"));256		}257		var registerSrc = !Studio2.isExpandable( srcEl );258		var destExpandable = !Studio2.isSpecial(destEl) && ((null==destRightSibling && null==destLeftSibling)259							|| (null !== destRightSibling) && Studio2.isSpecial(destRightSibling));260		var srcUnexpandable = !Studio2.isSpecial(srcEl) && ((null!==srcLeftSibling && !Studio2.isSpecial(srcLeftSibling))261							|| ((null !== srcRightSibling) && !Studio2.isSpecial(srcRightSibling)));262		var destUnexpandable = !Studio2.isSpecial(destEl) && ((null!==destLeftSibling && !Studio2.isSpecial(destLeftSibling))263							|| ((null!== destRightSibling) && !Studio2.isSpecial(destRightSibling)));264			if( registerSrc ){265				Studio2.registerExpandableField( srcEl );266			}267			if(srcUnexpandable){268				Studio2.unregisterExpandableField(  srcEl );269			}270			if(destExpandable){271				Studio2.registerExpandableField(destEl);272			}273			if(destUnexpandable){274				Studio2.unregisterExpandableField( destEl );275			}276		if(srcLeftSibling!==null && !Studio2.isSpecial(srcLeftSibling) && !Studio2.isSpecial(srcEl))277			Studio2.unregisterExpandableField( srcLeftSibling );278	return;279    }...copy.js
Source:copy.js  
1module.exports = {2    less: {3        files: [{4            expand: true,5            dot: true,6            filter: 'isFile',7            flatten: true,8            cwd: 'scss/temp/',9            dest: 'scss/',10            src: ['{,*/}*.scss'],11            rename: function(dest, src) {12                if (src !== 'material-design-iconic-font.scss') {13                    src = "_" + src;14                }15                return dest + src;16            }17        }]18    },19    action: {20        files: [{21            expand: true,22            dot: true,23            filter: 'isFile',24            flatten: true,25            cwd: 'node_modules/material-design-icons/action/svg/production/',26            dest: 'svg/google/action/',27            src: ['{,*/}*_24px.svg'],28            rename: function(dest, src) {29                src = src.replace('ic_','');30                src = src.replace('_24px','');31                return dest + src.replace(/[_ ]/g,'-');32            }33        }]34    },35    alert: {36        files: [{37            expand: true,38            dot: true,39            filter: 'isFile',40            flatten: true,41            cwd: 'node_modules/material-design-icons/alert/svg/production/',42            dest: 'svg/google/alert/',43            src: ['{,*/}*_24px.svg'],44            rename: function(dest, src) {45                src = src.replace('ic_','');46                src = src.replace('_24px','');47                return dest + src.replace(/[_ ]/g,'-');48            }49        }]50    },51    av: {52        files: [{53            expand: true,54            dot: true,55            filter: 'isFile',56            flatten: true,57            cwd: 'node_modules/material-design-icons/av/svg/production/',58            dest: 'svg/google/av/',59            src: ['{,*/}*_24px.svg'],60            rename: function(dest, src) {61                src = src.replace('ic_','');62                src = src.replace('_24px','');63                return dest + src.replace(/[_ ]/g,'-');64            }65        }]66    },67    communication: {68        files: [{69            expand: true,70            dot: true,71            filter: 'isFile',72            flatten: true,73            cwd: 'node_modules/material-design-icons/communication/svg/production/',74            dest: 'svg/google/communication/',75            src: ['{,*/}*_24px.svg'],76            rename: function(dest, src) {77                src = src.replace('ic_','');78                src = src.replace('_24px','');79                return dest + src.replace(/[_ ]/g,'-');80            }81        }]82    },83    content: {84        files: [{85            expand: true,86            dot: true,87            filter: 'isFile',88            flatten: true,89            cwd: 'node_modules/material-design-icons/content/svg/production/',90            dest: 'svg/google/content/',91            src: ['{,*/}*_24px.svg'],92            rename: function(dest, src) {93                src = src.replace('ic_','');94                src = src.replace('_24px','');95                return dest + src.replace(/[_ ]/g,'-');96            }97        }]98    },99    device: {100        files: [{101            expand: true,102            dot: true,103            filter: 'isFile',104            flatten: true,105            cwd: 'node_modules/material-design-icons/device/svg/production/',106            dest: 'svg/google/device/',107            src: ['{,*/}*_24px.svg'],108            rename: function(dest, src) {109                src = src.replace('ic_','');110                src = src.replace('_24px','');111                return dest + src.replace(/[_ ]/g,'-');112            }113        }]114    },115    editor: {116        files: [{117            expand: true,118            dot: true,119            filter: 'isFile',120            flatten: true,121            cwd: 'node_modules/material-design-icons/editor/svg/production/',122            dest: 'svg/google/editor/',123            src: ['{,*/}*_24px.svg'],124            rename: function(dest, src) {125                src = src.replace('ic_','');126                src = src.replace('_24px','');127                return dest + src.replace(/[_ ]/g,'-');128            }129        }]130    },131    file: {132        files: [{133            expand: true,134            dot: true,135            filter: 'isFile',136            flatten: true,137            cwd: 'node_modules/material-design-icons/file/svg/production/',138            dest: 'svg/google/file/',139            src: ['{,*/}*_24px.svg'],140            rename: function(dest, src) {141                src = src.replace('ic_','');142                src = src.replace('_24px','');143                return dest + src.replace(/[_ ]/g,'-');144            }145        }]146    },147    hardware: {148        files: [{149            expand: true,150            dot: true,151            filter: 'isFile',152            flatten: true,153            cwd: 'node_modules/material-design-icons/hardware/svg/production/',154            dest: 'svg/google/hardware/',155            src: ['{,*/}*_24px.svg'],156            rename: function(dest, src) {157                src = src.replace('ic_','');158                src = src.replace('_24px','');159                return dest + src.replace(/[_ ]/g,'-');160            }161        }]162    },163    image: {164        files: [{165            expand: true,166            dot: true,167            filter: 'isFile',168            flatten: true,169            cwd: 'node_modules/material-design-icons/image/svg/production/',170            dest: 'svg/google/image/',171            src: ['{,*/}*_24px.svg'],172            rename: function(dest, src) {173                src = src.replace('ic_','');174                src = src.replace('_24px','');175                return dest + src.replace(/[_ ]/g,'-');176            }177        }]178    },179    maps: {180        files: [{181            expand: true,182            dot: true,183            filter: 'isFile',184            flatten: true,185            cwd: 'node_modules/material-design-icons/maps/svg/production/',186            dest: 'svg/google/maps/',187            src: ['{,*/}*_24px.svg'],188            rename: function(dest, src) {189                src = src.replace('ic_','');190                src = src.replace('_24px','');191                return dest + src.replace(/[_ ]/g,'-');192            }193        }]194    },195    navigation: {196        files: [{197            expand: true,198            dot: true,199            filter: 'isFile',200            flatten: true,201            cwd: 'node_modules/material-design-icons/navigation/svg/production/',202            dest: 'svg/google/navigation/',203            src: ['{,*/}*_24px.svg'],204            rename: function(dest, src) {205                src = src.replace('ic_','');206                src = src.replace('_24px','');207                return dest + src.replace(/[_ ]/g,'-');208            }209        }]210    },211    notification: {212        files: [{213            expand: true,214            dot: true,215            filter: 'isFile',216            flatten: true,217            cwd: 'node_modules/material-design-icons/notification/svg/production/',218            dest: 'svg/google/notification/',219            src: ['{,*/}*_24px.svg'],220            rename: function(dest, src) {221                src = src.replace('ic_','');222                src = src.replace('_24px','');223                return dest + src.replace(/[_ ]/g,'-');224            }225        }]226    },227    social: {228        files: [{229            expand: true,230            dot: true,231            filter: 'isFile',232            flatten: true,233            cwd: 'node_modules/material-design-icons/social/svg/production/',234            dest: 'svg/google/social/',235            src: ['{,*/}*_24px.svg'],236            rename: function(dest, src) {237                src = src.replace('ic_','');238                src = src.replace('_24px','');239                return dest + src.replace(/[_ ]/g,'-');240            }241        }]242    },243    toggle: {244        files: [{245            expand: true,246            dot: true,247            filter: 'isFile',248            flatten: true,249            cwd: 'node_modules/material-design-icons/toggle/svg/production/',250            dest: 'svg/google/toggle/',251            src: ['{,*/}*_24px.svg'],252            rename: function(dest, src) {253                src = src.replace('ic_','');254                src = src.replace('_24px','');255                return dest + src.replace(/[_ ]/g,'-');256            }257        }]258    }...Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
