From 511677209e6c930ce1ba96e9abea6f8ad0b36939 Mon Sep 17 00:00:00 2001 From: Guilherme Francisco Date: Mon, 13 Jan 2025 11:36:43 +0000 Subject: [PATCH] LIMS-1564 - Remove unused dependencies (#868) * Remove touchscreen app * Remove unused dependencies * Remove local version of jquery-flot-pie * Remove aliased dependencies --------- Co-authored-by: Mark W <24956497+ndg63276@users.noreply.github.com> --- .../src/js/modules/blstats/views/histogram.js | 2 +- .../js/modules/blstats/views/robotdewar.js | 2 +- client/src/js/modules/cell/views/autoproc.js | 2 +- client/src/js/modules/cell/views/states.js | 2 +- client/src/js/modules/dc/views/aiplots.js | 2 +- client/src/js/modules/dc/views/distl.js | 2 +- client/src/js/modules/dc/views/rdplot.js | 2 +- client/src/js/modules/stats/views/pie.js | 4 +- client/src/js/modules/types/gen/dc/datplot.js | 2 +- .../js/modules/types/pow/dc/datplotlarge.js | 4 +- .../src/js/modules/types/saxs/dc/datplot.js | 2 +- client/src/js/utils.js | 2 +- client/src/js/vendor/GLmol.js | 1712 -------- client/src/js/vendor/MarchingSquares.js | 258 -- client/src/js/vendor/Three49custom.js | 382 -- .../js/vendor/backbone/backbone-validation.js | 643 --- .../backbone/backbone-validation.js_.js | 634 --- .../js/vendor/backbone/backbone.babysitter.js | 190 - client/src/js/vendor/backbone/backbone.js | 1608 -------- .../js/vendor/backbone/backbone.marionette.js | 3430 ----------------- .../js/vendor/backbone/backbone.paginator.js | 1325 ------- .../src/js/vendor/backbone/backbone.wreqr.js | 440 --- .../js/vendor/backbone/backgrid-paginator.js | 451 --- .../js/vendor/backbone/backgrid-select-all.js | 294 -- client/src/js/vendor/backbone/backgrid.js | 2895 -------------- client/src/js/vendor/backbone/json2.js | 489 --- .../js/vendor/flot/jquery.flot.axislabels.js | 466 --- client/src/js/vendor/flot/jquery.flot.pie.js | 812 ---- .../src/js/vendor/flot/jquery.flot.resize.js | 60 - client/src/js/vendor/gunzip.min.js | 26 - .../vendor/jquery/jquery-ui.combobox-1.0.7.js | 179 - .../js/vendor/jquery/jquery-ui.combobox.js | 243 -- client/src/js/vendor/jquery/jquery-ui.min.js | 12 - client/src/js/vendor/jquery/jquery.color.js | 663 ---- client/src/js/vendor/jquery/jquery.cookie.js | 113 - .../src/js/vendor/jquery/jquery.touchSwipe.js | 2036 ---------- client/src/js/vendor/three.min.js | 861 ----- client/src/js/vendor/underscore.min.js | 6 - client/src/js/vendor/vue/vee-validate.min.js | 1 - client/src/js/vendor/vue/vue.min.js | 6 - client/webpack.config.js | 8 - 41 files changed, 14 insertions(+), 20257 deletions(-) delete mode 100644 client/src/js/vendor/GLmol.js delete mode 100644 client/src/js/vendor/MarchingSquares.js delete mode 100644 client/src/js/vendor/Three49custom.js delete mode 100644 client/src/js/vendor/backbone/backbone-validation.js delete mode 100644 client/src/js/vendor/backbone/backbone-validation.js_.js delete mode 100644 client/src/js/vendor/backbone/backbone.babysitter.js delete mode 100644 client/src/js/vendor/backbone/backbone.js delete mode 100644 client/src/js/vendor/backbone/backbone.marionette.js delete mode 100755 client/src/js/vendor/backbone/backbone.paginator.js delete mode 100644 client/src/js/vendor/backbone/backbone.wreqr.js delete mode 100755 client/src/js/vendor/backbone/backgrid-paginator.js delete mode 100755 client/src/js/vendor/backbone/backgrid-select-all.js delete mode 100755 client/src/js/vendor/backbone/backgrid.js delete mode 100644 client/src/js/vendor/backbone/json2.js delete mode 100755 client/src/js/vendor/flot/jquery.flot.axislabels.js delete mode 100644 client/src/js/vendor/flot/jquery.flot.pie.js delete mode 100644 client/src/js/vendor/flot/jquery.flot.resize.js delete mode 100644 client/src/js/vendor/gunzip.min.js delete mode 100644 client/src/js/vendor/jquery/jquery-ui.combobox-1.0.7.js delete mode 100644 client/src/js/vendor/jquery/jquery-ui.combobox.js delete mode 100644 client/src/js/vendor/jquery/jquery-ui.min.js delete mode 100755 client/src/js/vendor/jquery/jquery.color.js delete mode 100644 client/src/js/vendor/jquery/jquery.cookie.js delete mode 100755 client/src/js/vendor/jquery/jquery.touchSwipe.js delete mode 100644 client/src/js/vendor/three.min.js delete mode 100644 client/src/js/vendor/underscore.min.js delete mode 100644 client/src/js/vendor/vue/vee-validate.min.js delete mode 100644 client/src/js/vendor/vue/vue.min.js diff --git a/client/src/js/modules/blstats/views/histogram.js b/client/src/js/modules/blstats/views/histogram.js index c6aa26fe5..b1546ec21 100644 --- a/client/src/js/modules/blstats/views/histogram.js +++ b/client/src/js/modules/blstats/views/histogram.js @@ -1,7 +1,7 @@ define(['marionette', 'modules/blstats/models/histogram', 'utils', 'jquery', 'jquery.flot', - 'jquery.flot.resize', + 'jquery-flot-resize', 'jquery.flot.tickrotor', ], function(Marionette, Histogram, utils, $) { diff --git a/client/src/js/modules/blstats/views/robotdewar.js b/client/src/js/modules/blstats/views/robotdewar.js index 6aadf7276..7645d94a9 100644 --- a/client/src/js/modules/blstats/views/robotdewar.js +++ b/client/src/js/modules/blstats/views/robotdewar.js @@ -1,7 +1,7 @@ define(['marionette', 'modules/blstats/models/robotdewar', 'utils', 'jquery', 'jquery.flot', - 'jquery.flot.resize', + 'jquery-flot-resize', ], function(Marionette, Dewar, utils, $) { return Marionette.ItemView.extend({ diff --git a/client/src/js/modules/cell/views/autoproc.js b/client/src/js/modules/cell/views/autoproc.js index 886ab354b..bf1dfbc06 100644 --- a/client/src/js/modules/cell/views/autoproc.js +++ b/client/src/js/modules/cell/views/autoproc.js @@ -1,7 +1,7 @@ define(['marionette', 'utils', 'jquery', 'jquery.flot', - 'jquery.flot.pie', + 'flot-pie', ], function(Marionette, utils, $) { diff --git a/client/src/js/modules/cell/views/states.js b/client/src/js/modules/cell/views/states.js index 467cd7ae5..12250015a 100644 --- a/client/src/js/modules/cell/views/states.js +++ b/client/src/js/modules/cell/views/states.js @@ -1,7 +1,7 @@ define(['marionette', 'utils', 'jquery', 'jquery.flot', - 'jquery.flot.pie', + 'flot-pie', ], function(Marionette, utils, $) { diff --git a/client/src/js/modules/dc/views/aiplots.js b/client/src/js/modules/dc/views/aiplots.js index a0a9978e7..1fce92216 100644 --- a/client/src/js/modules/dc/views/aiplots.js +++ b/client/src/js/modules/dc/views/aiplots.js @@ -3,7 +3,7 @@ define(['marionette', 'backbone', 'modules/dc/collections/aiplots', 'templates/dc/aiplots.html', 'jquery', 'jquery.flot', - 'jquery.flot.resize', + 'jquery-flot-resize', 'jquery.flot.tooltip', ], function(Marionette, Backbone, AIPlots, utils, template, $) { diff --git a/client/src/js/modules/dc/views/distl.js b/client/src/js/modules/dc/views/distl.js index 76496c70f..120caca7c 100644 --- a/client/src/js/modules/dc/views/distl.js +++ b/client/src/js/modules/dc/views/distl.js @@ -1,7 +1,7 @@ define(['marionette', 'modules/dc/models/distl', 'utils', 'jquery', 'jquery.flot', - 'jquery.flot.resize', + 'jquery-flot-resize', 'jquery.flot.selection', ], function(Marionette, DCDISTLModel, utils, $) { diff --git a/client/src/js/modules/dc/views/rdplot.js b/client/src/js/modules/dc/views/rdplot.js index 1cd413c94..07e16f91a 100644 --- a/client/src/js/modules/dc/views/rdplot.js +++ b/client/src/js/modules/dc/views/rdplot.js @@ -2,7 +2,7 @@ define(['marionette', 'modules/dc/models/rd', 'utils', 'templates/dc/rdplot.html', 'jquery', 'jquery.flot', - 'jquery.flot.resize', + 'jquery-flot-resize', ], function(Marionette, RDModel, utils, template, $) { diff --git a/client/src/js/modules/stats/views/pie.js b/client/src/js/modules/stats/views/pie.js index cd75a09a7..54222d28b 100644 --- a/client/src/js/modules/stats/views/pie.js +++ b/client/src/js/modules/stats/views/pie.js @@ -1,8 +1,8 @@ define(['marionette', 'modules/stats/models/pie', 'utils', 'jquery', 'jquery.flot', - 'jquery.flot.resize', - 'jquery.flot.pie', + 'jquery-flot-resize', + 'flot-pie', ], function(Marionette, Pie, utils, $) { return Marionette.ItemView.extend({ diff --git a/client/src/js/modules/types/gen/dc/datplot.js b/client/src/js/modules/types/gen/dc/datplot.js index a2254be18..67c3d2d9c 100644 --- a/client/src/js/modules/types/gen/dc/datplot.js +++ b/client/src/js/modules/types/gen/dc/datplot.js @@ -1,7 +1,7 @@ define(['marionette', 'modules/types/gen/dc/models/dat', 'utils', 'jquery', 'jquery.flot', - 'jquery.flot.resize', + 'jquery-flot-resize', ], function(Marionette, Dat, utils, $) { // DAT Plot diff --git a/client/src/js/modules/types/pow/dc/datplotlarge.js b/client/src/js/modules/types/pow/dc/datplotlarge.js index 1c9067dc0..a9c96abfc 100644 --- a/client/src/js/modules/types/pow/dc/datplotlarge.js +++ b/client/src/js/modules/types/pow/dc/datplotlarge.js @@ -5,8 +5,8 @@ define(['backbone', 'utils', 'jquery', 'jquery.flot', - 'jquery.flot.resize', - 'jquery.flot.axislabels' + 'jquery-flot-resize', + 'flot-axislabels' ], function(Backbone, Marionette, Dat, DataCollections, utils, $) { var DatCollection = Backbone.Collection.extend({ diff --git a/client/src/js/modules/types/saxs/dc/datplot.js b/client/src/js/modules/types/saxs/dc/datplot.js index 818b02f55..73981dfa4 100644 --- a/client/src/js/modules/types/saxs/dc/datplot.js +++ b/client/src/js/modules/types/saxs/dc/datplot.js @@ -1,7 +1,7 @@ define(['marionette', 'modules/types/gen/dc/models/dat', 'utils', 'jquery', 'jquery.flot', - 'jquery.flot.resize', + 'jquery-flot-resize', ], function(Marionette, Dat, utils, $) { // DAT Plot diff --git a/client/src/js/utils.js b/client/src/js/utils.js index ef29ccb45..aea8e7fda 100644 --- a/client/src/js/utils.js +++ b/client/src/js/utils.js @@ -2,7 +2,7 @@ define(['backbone', 'marionette', 'views/dialog', 'jquery', - 'jquery.color', + 'jquery-color', 'jquery-ui/ui/effect', 'jquery-ui/ui/effects/effect-highlight' ], function(Backbone, Marionette, DialogView, $) { diff --git a/client/src/js/vendor/GLmol.js b/client/src/js/vendor/GLmol.js deleted file mode 100644 index 9f2f8edc2..000000000 --- a/client/src/js/vendor/GLmol.js +++ /dev/null @@ -1,1712 +0,0 @@ -/* - GLmol - Molecular Viewer on WebGL/Javascript (0.46) - (C) Copyright 2011-2012, biochem_fan - License: dual license of MIT or LGPL3 - - Contributors: - Robert Hanson for parseXYZ, deferred instantiation - - This program uses - Three.js - https://github.com/mrdoob/three.js - Copyright (c) 2010-2012 three.js Authors. All rights reserved. - jQuery - http://jquery.org/ - Copyright (c) 2011 John Resig - */ - -// Workaround for Intel GMA series (gl_FrontFacing causes compilation error) -THREE.ShaderLib.lambert.fragmentShader = THREE.ShaderLib.lambert.fragmentShader.replace("gl_FrontFacing", "true"); -THREE.ShaderLib.lambert.vertexShader = THREE.ShaderLib.lambert.vertexShader.replace(/\}$/, "#ifdef DOUBLE_SIDED\n if (transformedNormal.z < 0.0) vLightFront = vLightBack;\n #endif\n }"); - -var TV3 = THREE.Vector3, TF3 = THREE.Face3, TCo = THREE.Color; - -THREE.Geometry.prototype.colorAll = function (color) { - for (var i = 0; i < this.faces.length; i++) { - this.faces[i].color = color; - } -}; - -THREE.Matrix4.prototype.isIdentity = function() { - for (var i = 0; i < 4; i++) - for (var j = 0; j < 4; j++) - if (this.elements[i * 4 + j] != (i == j) ? 1 : 0) return false; - return true; -}; - -var GLmol = (function() { -function GLmol(id, suppressAutoload) { - if (id) this.create(id, suppressAutoload); - return true; -} - -GLmol.prototype.create = function(id, suppressAutoload) { - this.Nucleotides = [' G', ' A', ' T', ' C', ' U', ' DG', ' DA', ' DT', ' DC', ' DU']; - this.ElementColors = {"H": 0xCCCCCC, "C": 0xAAAAAA, "O": 0xCC0000, "N": 0x0000CC, "S": 0xCCCC00, "P": 0x6622CC, - "F": 0x00CC00, "CL": 0x00CC00, "BR": 0x882200, "I": 0x6600AA, - "FE": 0xCC6600, "CA": 0x8888AA}; -// Reference: A. Bondi, J. Phys. Chem., 1964, 68, 441. - this.vdwRadii = {"H": 1.2, "Li": 1.82, "Na": 2.27, "K": 2.75, "C": 1.7, "N": 1.55, "O": 1.52, - "F": 1.47, "P": 1.80, "S": 1.80, "CL": 1.75, "BR": 1.85, "SE": 1.90, - "ZN": 1.39, "CU": 1.4, "NI": 1.63}; - - this.id = id; - this.aaScale = 1; // or 2 - - this.container = $('#' + this.id); - this.WIDTH = this.container.width() * this.aaScale, this.HEIGHT = this.container.height() * this.aaScale; - this.ASPECT = this.WIDTH / this.HEIGHT; - this.NEAR = 1, FAR = 800; - this.CAMERA_Z = -150; - this.renderer = new THREE.WebGLRenderer({antialias: true}); - this.renderer.sortObjects = false; // hopefully improve performance - // 'antialias: true' now works in Firefox too! - // setting this.aaScale = 2 will enable antialias in older Firefox but GPU load increases. - this.renderer.domElement.style.width = "100%"; - this.renderer.domElement.style.height = "100%"; - this.container.append(this.renderer.domElement); - this.renderer.setSize(this.WIDTH, this.HEIGHT); - - this.camera = new THREE.PerspectiveCamera(20, this.ASPECT, 1, 800); // will be updated anyway - this.camera.position = new TV3(0, 0, this.CAMERA_Z); - this.camera.lookAt(new TV3(0, 0, 0)); - this.perspectiveCamera = this.camera; - this.orthoscopicCamera = new THREE.OrthographicCamera(); - this.orthoscopicCamera.position.z = this.CAMERA_Z; - this.orthoscopicCamera.lookAt(new TV3(0, 0, 0)); - - var self = this; - $(window).resize(function() { // only window can capture resize event - self.WIDTH = self.container.width() * self.aaScale; - self.HEIGHT = self.container.height() * self.aaScale; - self.ASPECT = self.WIDTH / self.HEIGHT; - self.renderer.setSize(self.WIDTH, self.HEIGHT); - self.camera.aspect = self.ASPECT; - self.camera.updateProjectionMatrix(); - self.show(); - }); - - this.scene = null; - this.rotationGroup = null; // which contains modelGroup - this.modelGroup = null; - - this.bgColor = 0x000000; - this.fov = 20; - this.fogStart = 0.4; - this.slabNear = -50; // relative to the center of rotationGroup - this.slabFar = +50; - - // Default values - this.sphereRadius = 1.5; - this.cylinderRadius = 0.4; - this.lineWidth = 1.5 * this.aaScale; - this.curveWidth = 3 * this.aaScale; - this.defaultColor = 0xCCCCCC; - this.sphereQuality = 16; //16; - this.cylinderQuality = 16; //8; - this.axisDIV = 5; // 3 still gives acceptable quality - this.strandDIV = 6; - this.nucleicAcidStrandDIV = 4; - this.tubeDIV = 8; - this.coilWidth = 0.3; - this.helixSheetWidth = 1.3; - this.nucleicAcidWidth = 0.8; - this.thickness = 0.4; - - // UI variables - this.cq = new THREE.Quaternion(1, 0, 0, 0); - this.dq = new THREE.Quaternion(1, 0, 0, 0); - this.isDragging = false; - this.mouseStartX = 0; - this.mouseStartY = 0; - this.currentModelPos = 0; - this.cz = 0; - this.enableMouse(); - - if (suppressAutoload) return; - this.loadMolecule(); -} - -GLmol.prototype.setupLights = function(scene) { - var directionalLight = new THREE.DirectionalLight(0xFFFFFF); - directionalLight.position = new TV3(0.2, 0.2, -1).normalize(); - directionalLight.intensity = 1.2; - scene.add(directionalLight); - var ambientLight = new THREE.AmbientLight(0x202020); - scene.add(ambientLight); -}; - -GLmol.prototype.parseSDF = function(str) { - var atoms = this.atoms; - var protein = this.protein; - - var lines = str.split("\n"); - if (lines.length < 4) return; - var atomCount = parseInt(lines[3].substr(0, 3)); - if (isNaN(atomCount) || atomCount <= 0) return; // might be a PDB file. - var bondCount = parseInt(lines[3].substr(3, 3)); - var offset = 4; - if (lines.length < 4 + atomCount + bondCount) return; - for (var i = 1; i <= atomCount; i++) { - var line = lines[offset]; - offset++; - var atom = {}; - atom.serial = i; - atom.x = parseFloat(line.substr(0, 10)); - atom.y = parseFloat(line.substr(10, 10)); - atom.z = parseFloat(line.substr(20, 10)); - atom.hetflag = true; - atom.atom = atom.elem = line.substr(31, 3).replace(/ /g, ""); - atom.bonds = []; - atom.bondOrder = []; - atoms[i] = atom; - } - for (i = 1; i <= bondCount; i++) { - var line = lines[offset]; - offset++; - var from = parseInt(line.substr(0, 3)); - var to = parseInt(line.substr(3, 3)); - var order = parseInt(line.substr(6, 3)); - atoms[from].bonds.push(to); - atoms[from].bondOrder.push(order); - atoms[to].bonds.push(from); - atoms[to].bondOrder.push(order); - } - - protein.sdf = true; -}; - -GLmol.prototype.parseXYZ = function(str) { - var atoms = this.atoms; - var protein = this.protein; - - var lines = str.split("\n"); - if (lines.length < 3) return; - var atomCount = parseInt(lines[0].substr(0, 3)); - if (isNaN(atomCount) || atomCount <= 0) return; - if (lines.length < atomCount + 2) return; - var offset = 2; - for (var i = 1; i <= atomCount; i++) { - var line = lines[offset++]; - var tokens = line.replace(/^\s+/, "").replace(/\s+/g," ").split(" "); - console.log(tokens); - var atom = {}; - atom.serial = i; - atom.atom = atom.elem = tokens[0]; - atom.x = parseFloat(tokens[1]); - atom.y = parseFloat(tokens[2]); - atom.z = parseFloat(tokens[3]); - atom.hetflag = true; - atom.bonds = []; - atom.bondOrder = []; - atoms[i] = atom; - } - for (var i = 1; i < atomCount; i++) // hopefully XYZ is small enough - for (var j = i + 1; j <= atomCount; j++) - if (this.isConnected(atoms[i], atoms[j])) { - atoms[i].bonds.push(j); - atoms[i].bondOrder.push(1); - atoms[j].bonds.push(i); - atoms[j].bondOrder.push(1); - } - protein.sdf = true; -}; - -GLmol.prototype.parsePDB2 = function(str) { - var atoms = this.atoms; - var protein = this.protein; - var molID; - - var atoms_cnt = 0; - lines = str.split("\n"); - for (var i = 0; i < lines.length; i++) { - line = lines[i].replace(/^\s*/, ''); // remove indent - var recordName = line.substr(0, 6); - if (recordName == 'ATOM ' || recordName == 'HETATM') { - var atom, resn, chain, resi, x, y, z, hetflag, elem, serial, altLoc, b; - altLoc = line.substr(16, 1); - if (altLoc != ' ' && altLoc != 'A') continue; // FIXME: ad hoc - serial = parseInt(line.substr(6, 5)); - atom = line.substr(12, 4).replace(/ /g, ""); - resn = line.substr(17, 3); - chain = line.substr(21, 1); - resi = parseInt(line.substr(22, 5)); - x = parseFloat(line.substr(30, 8)); - y = parseFloat(line.substr(38, 8)); - z = parseFloat(line.substr(46, 8)); - b = parseFloat(line.substr(60, 8)); - elem = line.substr(76, 2).replace(/ /g, ""); - if (elem == '') { // for some incorrect PDB files - elem = line.substr(12, 4).replace(/ /g,""); - } - if (line[0] == 'H') hetflag = true; - else hetflag = false; - atoms[serial] = {'resn': resn, 'x': x, 'y': y, 'z': z, 'elem': elem, - 'hetflag': hetflag, 'chain': chain, 'resi': resi, 'serial': serial, 'atom': atom, - 'bonds': [], 'ss': 'c', 'color': 0xFFFFFF, 'bonds': [], 'bondOrder': [], 'b': b /*', altLoc': altLoc*/}; - } else if (recordName == 'SHEET ') { - var startChain = line.substr(21, 1); - var startResi = parseInt(line.substr(22, 4)); - var endChain = line.substr(32, 1); - var endResi = parseInt(line.substr(33, 4)); - protein.sheet.push([startChain, startResi, endChain, endResi]); - } else if (recordName == 'CONECT') { -// MEMO: We don't have to parse SSBOND, LINK because both are also -// described in CONECT. But what about 2JYT??? - var from = parseInt(line.substr(6, 5)); - for (var j = 0; j < 4; j++) { - var to = parseInt(line.substr([11, 16, 21, 26][j], 5)); - if (isNaN(to)) continue; - if (atoms[from] != undefined) { - atoms[from].bonds.push(to); - atoms[from].bondOrder.push(1); - } - } - } else if (recordName == 'HELIX ') { - var startChain = line.substr(19, 1); - var startResi = parseInt(line.substr(21, 4)); - var endChain = line.substr(31, 1); - var endResi = parseInt(line.substr(33, 4)); - protein.helix.push([startChain, startResi, endChain, endResi]); - } else if (recordName == 'CRYST1') { - protein.a = parseFloat(line.substr(6, 9)); - protein.b = parseFloat(line.substr(15, 9)); - protein.c = parseFloat(line.substr(24, 9)); - protein.alpha = parseFloat(line.substr(33, 7)); - protein.beta = parseFloat(line.substr(40, 7)); - protein.gamma = parseFloat(line.substr(47, 7)); - protein.spacegroup = line.substr(55, 11); - this.defineCell(); - } else if (recordName == 'REMARK') { - var type = parseInt(line.substr(7, 3)); - if (type == 290 && line.substr(13, 5) == 'SMTRY') { - var n = parseInt(line[18]) - 1; - var m = parseInt(line.substr(21, 2)); - if (protein.symMat[m] == undefined) protein.symMat[m] = new THREE.Matrix4().identity(); - protein.symMat[m].elements[n] = parseFloat(line.substr(24, 9)); - protein.symMat[m].elements[n + 4] = parseFloat(line.substr(34, 9)); - protein.symMat[m].elements[n + 8] = parseFloat(line.substr(44, 9)); - protein.symMat[m].elements[n + 12] = parseFloat(line.substr(54, 10)); - } else if (type == 350 && line.substr(13, 5) == 'BIOMT') { - var n = parseInt(line[18]) - 1; - var m = parseInt(line.substr(21, 2)); - if (protein.biomtMatrices[m] == undefined) protein.biomtMatrices[m] = new THREE.Matrix4().identity(); - protein.biomtMatrices[m].elements[n] = parseFloat(line.substr(24, 9)); - protein.biomtMatrices[m].elements[n + 4] = parseFloat(line.substr(34, 9)); - protein.biomtMatrices[m].elements[n + 8] = parseFloat(line.substr(44, 9)); - protein.biomtMatrices[m].elements[n + 12] = parseFloat(line.substr(54, 10)); - } else if (type == 350 && line.substr(11, 11) == 'BIOMOLECULE') { - protein.biomtMatrices = []; protein.biomtChains = ''; - } else if (type == 350 && line.substr(34, 6) == 'CHAINS') { - protein.biomtChains += line.substr(41, 40); - } - } else if (recordName == 'HEADER') { - protein.pdbID = line.substr(62, 4); - } else if (recordName == 'TITLE ') { - if (protein.title == undefined) protein.title = ""; - protein.title += line.substr(10, 70) + "\n"; // CHECK: why 60 is not enough??? - } else if (recordName == 'COMPND') { - // TODO: Implement me! - } - } - - // Assign secondary structures - for (i = 0; i < atoms.length; i++) { - atom = atoms[i]; if (atom == undefined) continue; - - var found = false; - // MEMO: Can start chain and end chain differ? - for (j = 0; j < protein.sheet.length; j++) { - if (atom.chain != protein.sheet[j][0]) continue; - if (atom.resi < protein.sheet[j][1]) continue; - if (atom.resi > protein.sheet[j][3]) continue; - atom.ss = 's'; - if (atom.resi == protein.sheet[j][1]) atom.ssbegin = true; - if (atom.resi == protein.sheet[j][3]) atom.ssend = true; - } - for (j = 0; j < protein.helix.length; j++) { - if (atom.chain != protein.helix[j][0]) continue; - if (atom.resi < protein.helix[j][1]) continue; - if (atom.resi > protein.helix[j][3]) continue; - atom.ss = 'h'; - if (atom.resi == protein.helix[j][1]) atom.ssbegin = true; - else if (atom.resi == protein.helix[j][3]) atom.ssend = true; - } - } -}; - -// Catmull-Rom subdivision -GLmol.prototype.subdivide = function(_points, DIV) { // points as Vector3 - var ret = []; - var points = _points; - points = new Array(); // Smoothing test - points.push(_points[0]); - for (var i = 1, lim = _points.length - 1; i < lim; i++) { - var p1 = _points[i], p2 = _points[i + 1]; - if (p1.smoothen) points.push(new TV3((p1.x + p2.x) / 2, (p1.y + p2.y) / 2, (p1.z + p2.z) / 2)); - else points.push(p1); - } - points.push(_points[_points.length - 1]); - - for (var i = -1, size = points.length; i <= size - 3; i++) { - var p0 = points[(i == -1) ? 0 : i]; - var p1 = points[i + 1], p2 = points[i + 2]; - var p3 = points[(i == size - 3) ? size - 1 : i + 3]; - var v0 = new TV3().sub(p2, p0).multiplyScalar(0.5); - var v1 = new TV3().sub(p3, p1).multiplyScalar(0.5); - for (var j = 0; j < DIV; j++) { - var t = 1.0 / DIV * j; - var x = p1.x + t * v0.x - + t * t * (-3 * p1.x + 3 * p2.x - 2 * v0.x - v1.x) - + t * t * t * (2 * p1.x - 2 * p2.x + v0.x + v1.x); - var y = p1.y + t * v0.y - + t * t * (-3 * p1.y + 3 * p2.y - 2 * v0.y - v1.y) - + t * t * t * (2 * p1.y - 2 * p2.y + v0.y + v1.y); - var z = p1.z + t * v0.z - + t * t * (-3 * p1.z + 3 * p2.z - 2 * v0.z - v1.z) - + t * t * t * (2 * p1.z - 2 * p2.z + v0.z + v1.z); - ret.push(new TV3(x, y, z)); - } - } - ret.push(points[points.length - 1]); - return ret; -}; - -GLmol.prototype.drawAtomsAsSphere = function(group, atomlist, defaultRadius, forceDefault, scale) { - var sphereGeometry = new THREE.SphereGeometry(1, this.sphereQuality, this.sphereQuality); // r, seg, ring - for (var i = 0; i < atomlist.length; i++) { - var atom = this.atoms[atomlist[i]]; - if (atom == undefined) continue; - - var sphereMaterial = new THREE.MeshLambertMaterial({color: atom.color}); - var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial); - group.add(sphere); - var r = (!forceDefault && this.vdwRadii[atom.elem] != undefined) ? this.vdwRadii[atom.elem] : defaultRadius; - if (!forceDefault && scale) r *= scale; - sphere.scale.x = sphere.scale.y = sphere.scale.z = r; - sphere.position.x = atom.x; - sphere.position.y = atom.y; - sphere.position.z = atom.z; - } -}; - -// about two times faster than sphere when div = 2 -GLmol.prototype.drawAtomsAsIcosahedron = function(group, atomlist, defaultRadius, forceDefault) { - var geo = this.IcosahedronGeometry(); - for (var i = 0; i < atomlist.length; i++) { - var atom = this.atoms[atomlist[i]]; - if (atom == undefined) continue; - - var mat = new THREE.MeshLambertMaterial({color: atom.color}); - var sphere = new THREE.Mesh(geo, mat); - sphere.scale.x = sphere.scale.y = sphere.scale.z = (!forceDefault && this.vdwRadii[atom.elem] != undefined) ? this.vdwRadii[atom.elem] : defaultRadius; - group.add(sphere); - sphere.position.x = atom.x; - sphere.position.y = atom.y; - sphere.position.z = atom.z; - } -}; - -GLmol.prototype.isConnected = function(atom1, atom2) { - var s = atom1.bonds.indexOf(atom2.serial); - if (s != -1) return atom1.bondOrder[s]; - - if (this.protein.sdf && (atom1.hetflag || atom2.hetflag)) return 0; // CHECK: or should I ? - - var distSquared = (atom1.x - atom2.x) * (atom1.x - atom2.x) + - (atom1.y - atom2.y) * (atom1.y - atom2.y) + - (atom1.z - atom2.z) * (atom1.z - atom2.z); - -// if (atom1.altLoc != atom2.altLoc) return false; - if (isNaN(distSquared)) return 0; - if (distSquared < 0.5) return 0; // maybe duplicate position. - - if (distSquared > 1.3 && (atom1.elem == 'H' || atom2.elem == 'H' || atom1.elem == 'D' || atom2.elem == 'D')) return 0; - if (distSquared < 3.42 && (atom1.elem == 'S' || atom2.elem == 'S')) return 1; - if (distSquared > 2.78) return 0; - return 1; -}; - -GLmol.prototype.drawBondAsStickSub = function(group, atom1, atom2, bondR, order) { - var delta, tmp; - if (order > 1) delta = this.calcBondDelta(atom1, atom2, bondR * 2.3); - var p1 = new TV3(atom1.x, atom1.y, atom1.z); - var p2 = new TV3(atom2.x, atom2.y, atom2.z); - var mp = p1.clone().addSelf(p2).multiplyScalar(0.5); - - var c1 = new TCo(atom1.color), c2 = new TCo(atom2.color); - if (order == 1 || order == 3) { - this.drawCylinder(group, p1, mp, bondR, atom1.color); - this.drawCylinder(group, p2, mp, bondR, atom2.color); - } - if (order > 1) { - tmp = mp.clone().addSelf(delta); - this.drawCylinder(group, p1.clone().addSelf(delta), tmp, bondR, atom1.color); - this.drawCylinder(group, p2.clone().addSelf(delta), tmp, bondR, atom2.color); - tmp = mp.clone().subSelf(delta); - this.drawCylinder(group, p1.clone().subSelf(delta), tmp, bondR, atom1.color); - this.drawCylinder(group, p2.clone().subSelf(delta), tmp, bondR, atom2.color); - } -}; - -GLmol.prototype.drawBondsAsStick = function(group, atomlist, bondR, atomR, ignoreNonbonded, multipleBonds, scale) { - var sphereGeometry = new THREE.SphereGeometry(1, this.sphereQuality, this.sphereQuality); - var nAtoms = atomlist.length, mp; - var forSpheres = []; - if (!!multipleBonds) bondR /= 2.5; - for (var _i = 0; _i < nAtoms; _i++) { - var i = atomlist[_i]; - var atom1 = this.atoms[i]; - if (atom1 == undefined) continue; - for (var _j = _i + 1; _j < _i + 30 && _j < nAtoms; _j++) { - var j = atomlist[_j]; - var atom2 = this.atoms[j]; - if (atom2 == undefined) continue; - var order = this.isConnected(atom1, atom2); - if (order == 0) continue; - atom1.connected = atom2.connected = true; - this.drawBondAsStickSub(group, atom1, atom2, bondR, (!!multipleBonds) ? order : 1); - } - for (var _j = 0; _j < atom1.bonds.length; _j++) { - var j = atom1.bonds[_j]; - if (j < i + 30) continue; // be conservative! - if (atomlist.indexOf(j) == -1) continue; - var atom2 = this.atoms[j]; - if (atom2 == undefined) continue; - atom1.connected = atom2.connected = true; - this.drawBondAsStickSub(group, atom1, atom2, bondR, (!!multipleBonds) ? atom1.bondOrder[_j] : 1); - } - if (atom1.connected) forSpheres.push(i); - } - this.drawAtomsAsSphere(group, forSpheres, atomR, !scale, scale); -}; - -GLmol.prototype.defineCell = function() { - var p = this.protein; - if (p.a == undefined) return; - - p.ax = p.a; - p.ay = 0; - p.az = 0; - p.bx = p.b * Math.cos(Math.PI / 180.0 * p.gamma); - p.by = p.b * Math.sin(Math.PI / 180.0 * p.gamma); - p.bz = 0; - p.cx = p.c * Math.cos(Math.PI / 180.0 * p.beta); - p.cy = p.c * (Math.cos(Math.PI / 180.0 * p.alpha) - - Math.cos(Math.PI / 180.0 * p.gamma) - * Math.cos(Math.PI / 180.0 * p.beta)) - / Math.sin(Math.PI / 180.0 * p.gamma); - p.cz = Math.sqrt(p.c * p.c * Math.sin(Math.PI / 180.0 * p.beta) - * Math.sin(Math.PI / 180.0 * p.beta) - p.cy * p.cy); -}; - -GLmol.prototype.drawUnitcell = function(group) { - var p = this.protein; - if (p.a == undefined) return; - - var vertices = [[0, 0, 0], [p.ax, p.ay, p.az], [p.bx, p.by, p.bz], [p.ax + p.bx, p.ay + p.by, p.az + p.bz], - [p.cx, p.cy, p.cz], [p.cx + p.ax, p.cy + p.ay, p.cz + p.az], [p.cx + p.bx, p.cy + p.by, p.cz + p.bz], [p.cx + p.ax + p.bx, p.cy + p.ay + p.by, p.cz + p.az + p.bz]]; - var edges = [0, 1, 0, 2, 1, 3, 2, 3, 4, 5, 4, 6, 5, 7, 6, 7, 0, 4, 1, 5, 2, 6, 3, 7]; - - var geo = new THREE.Geometry(); - for (var i = 0; i < edges.length; i++) { - geo.vertices.push(new TV3(vertices[edges[i]][0], vertices[edges[i]][1], vertices[edges[i]][2])); - } - var lineMaterial = new THREE.LineBasicMaterial({linewidth: 1, color: 0xcccccc}); - var line = new THREE.Line(geo, lineMaterial); - line.type = THREE.LinePieces; - group.add(line); -}; - -// TODO: Find inner side of a ring -GLmol.prototype.calcBondDelta = function(atom1, atom2, sep) { - var dot; - var axis = new TV3(atom1.x - atom2.x, atom1.y - atom2.y, atom1.z - atom2.z).normalize(); - var found = null; - for (var i = 0; i < atom1.bonds.length && !found; i++) { - var atom = this.atoms[atom1.bonds[i]]; if (!atom) continue; - if (atom.serial != atom2.serial && atom.elem != 'H') found = atom; - } - for (var i = 0; i < atom2.bonds.length && !found; i++) { - var atom = this.atoms[atom2.bonds[i]]; if (!atom) continue; - if (atom.serial != atom1.serial && atom.elem != 'H') found = atom; - } - if (found) { - var tmp = new TV3(atom1.x - found.x, atom1.y - found.y, atom1.z - found.z).normalize(); - dot = tmp.dot(axis); - delta = new TV3(tmp.x - axis.x * dot, tmp.y - axis.y * dot, tmp.z - axis.z * dot); - } - if (!found || Math.abs(dot - 1) < 0.001 || Math.abs(dot + 1) < 0.001) { - if (axis.x < 0.01 && axis.y < 0.01) { - delta = new TV3(0, -axis.z, axis.y); - } else { - delta = new TV3(-axis.y, axis.x, 0); - } - } - delta.normalize().multiplyScalar(sep); - return delta; -}; - -GLmol.prototype.drawBondsAsLineSub = function(geo, atom1, atom2, order) { - var delta, tmp, vs = geo.vertices, cs = geo.colors; - if (order > 1) delta = this.calcBondDelta(atom1, atom2, 0.15); - var p1 = new TV3(atom1.x, atom1.y, atom1.z); - var p2 = new TV3(atom2.x, atom2.y, atom2.z); - var mp = p1.clone().addSelf(p2).multiplyScalar(0.5); - - var c1 = new TCo(atom1.color), c2 = new TCo(atom2.color); - if (order == 1 || order == 3) { - vs.push(p1); cs.push(c1); vs.push(mp); cs.push(c1); - vs.push(p2); cs.push(c2); vs.push(mp); cs.push(c2); - } - if (order > 1) { - vs.push(p1.clone().addSelf(delta)); cs.push(c1); - vs.push(tmp = mp.clone().addSelf(delta)); cs.push(c1); - vs.push(p2.clone().addSelf(delta)); cs.push(c2); - vs.push(tmp); cs.push(c2); - vs.push(p1.clone().subSelf(delta)); cs.push(c1); - vs.push(tmp = mp.clone().subSelf(delta)); cs.push(c1); - vs.push(p2.clone().subSelf(delta)); cs.push(c2); - vs.push(tmp); cs.push(c2); - } -}; - -GLmol.prototype.drawBondsAsLine = function(group, atomlist, lineWidth) { - var geo = new THREE.Geometry(); - var nAtoms = atomlist.length; - - for (var _i = 0; _i < nAtoms; _i++) { - var i = atomlist[_i]; - var atom1 = this.atoms[i]; - if (atom1 == undefined) continue; - for (var _j = _i + 1; _j < _i + 30 && _j < nAtoms; _j++) { - var j = atomlist[_j]; - var atom2 = this.atoms[j]; - if (atom2 == undefined) continue; - var order = this.isConnected(atom1, atom2); - if (order == 0) continue; - - this.drawBondsAsLineSub(geo, atom1, atom2, order); - } - for (var _j = 0; _j < atom1.bonds.length; _j++) { - var j = atom1.bonds[_j]; - if (j < i + 30) continue; // be conservative! - if (atomlist.indexOf(j) == -1) continue; - var atom2 = this.atoms[j]; - if (atom2 == undefined) continue; - this.drawBondsAsLineSub(geo, atom1, atom2, atom1.bondOrder[_j]); - } - } - var lineMaterial = new THREE.LineBasicMaterial({linewidth: lineWidth}); - lineMaterial.vertexColors = true; - - var line = new THREE.Line(geo, lineMaterial); - line.type = THREE.LinePieces; - group.add(line); -}; - -GLmol.prototype.drawSmoothCurve = function(group, _points, width, colors, div) { - if (_points.length == 0) return; - - div = (div == undefined) ? 5 : div; - - var geo = new THREE.Geometry(); - var points = this.subdivide(_points, div); - - for (var i = 0; i < points.length; i++) { - geo.vertices.push(points[i]); - geo.colors.push(new TCo(colors[(i == 0) ? 0 : Math.round((i - 1) / div)])); - } - var lineMaterial = new THREE.LineBasicMaterial({linewidth: width}); - lineMaterial.vertexColors = true; - var line = new THREE.Line(geo, lineMaterial); - line.type = THREE.LineStrip; - group.add(line); -}; - -GLmol.prototype.drawAsCross = function(group, atomlist, delta) { - var geo = new THREE.Geometry(); - var points = [[delta, 0, 0], [-delta, 0, 0], [0, delta, 0], [0, -delta, 0], [0, 0, delta], [0, 0, -delta]]; - - for (var i = 0, lim = atomlist.length; i < lim; i++) { - var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; - - var c = new TCo(atom.color); - for (var j = 0; j < 6; j++) { - geo.vertices.push(new TV3(atom.x + points[j][0], atom.y + points[j][1], atom.z + points[j][2])); - geo.colors.push(c); - } - } - var lineMaterial = new THREE.LineBasicMaterial({linewidth: this.lineWidth}); - lineMaterial.vertexColors = true; - var line = new THREE.Line(geo, lineMaterial, THREE.LinePieces); - group.add(line); -}; - -// FIXME: Winkled... -GLmol.prototype.drawSmoothTube = function(group, _points, colors, radii) { - if (_points.length < 2) return; - - var circleDiv = this.tubeDIV, axisDiv = this.axisDIV; - var geo = new THREE.Geometry(); - var points = this.subdivide(_points, axisDiv); - var prevAxis1 = new TV3(), prevAxis2; - - for (var i = 0, lim = points.length; i < lim; i++) { - var r, idx = (i - 1) / axisDiv; - if (i == 0) r = radii[0]; - else { - if (idx % 1 == 0) r = radii[idx]; - else { - var floored = Math.floor(idx); - var tmp = idx - floored; - r = radii[floored] * tmp + radii[floored + 1] * (1 - tmp); - } - } - var delta, axis1, axis2; - - if (i < lim - 1) { - delta = new TV3().sub(points[i], points[i + 1]); - axis1 = new TV3(0, - delta.z, delta.y).normalize().multiplyScalar(r); - axis2 = new TV3().cross(delta, axis1).normalize().multiplyScalar(r); -// var dir = 1, offset = 0; - if (prevAxis1.dot(axis1) < 0) { - axis1.negate(); axis2.negate(); //dir = -1;//offset = 2 * Math.PI / axisDiv; - } - prevAxis1 = axis1; prevAxis2 = axis2; - } else { - axis1 = prevAxis1; axis2 = prevAxis2; - } - - for (var j = 0; j < circleDiv; j++) { - var angle = 2 * Math.PI / circleDiv * j; //* dir + offset; - var c = Math.cos(angle), s = Math.sin(angle); - geo.vertices.push(new TV3( - points[i].x + c * axis1.x + s * axis2.x, - points[i].y + c * axis1.y + s * axis2.y, - points[i].z + c * axis1.z + s * axis2.z)); - } - } - - var offset = 0; - for (var i = 0, lim = points.length - 1; i < lim; i++) { - var c = new TCo(colors[Math.round((i - 1)/ axisDiv)]); - - var reg = 0; - var r1 = new TV3().sub(geo.vertices[offset], geo.vertices[offset + circleDiv]).lengthSq(); - var r2 = new TV3().sub(geo.vertices[offset], geo.vertices[offset + circleDiv + 1]).lengthSq(); - if (r1 > r2) {r1 = r2; reg = 1;}; - for (var j = 0; j < circleDiv; j++) { - geo.faces.push(new TF3(offset + j, offset + (j + reg) % circleDiv + circleDiv, offset + (j + 1) % circleDiv)); - geo.faces.push(new TF3(offset + (j + 1) % circleDiv, offset + (j + reg) % circleDiv + circleDiv, offset + (j + reg + 1) % circleDiv + circleDiv)); - geo.faces[geo.faces.length -2].color = c; - geo.faces[geo.faces.length -1].color = c; - } - offset += circleDiv; - } - geo.computeFaceNormals(); - geo.computeVertexNormals(false); - var mat = new THREE.MeshLambertMaterial(); - mat.vertexColors = THREE.FaceColors; - var mesh = new THREE.Mesh(geo, mat); - mesh.doubleSided = true; - group.add(mesh); -}; - - -GLmol.prototype.drawMainchainCurve = function(group, atomlist, curveWidth, atomName, div) { - var points = [], colors = []; - var currentChain, currentResi; - if (div == undefined) div = 5; - - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; - if (atom == undefined) continue; - - if ((atom.atom == atomName) && !atom.hetflag) { - if (currentChain != atom.chain || currentResi + 1 != atom.resi) { - this.drawSmoothCurve(group, points, curveWidth, colors, div); - points = []; - colors = []; - } - points.push(new TV3(atom.x, atom.y, atom.z)); - colors.push(atom.color); - currentChain = atom.chain; - currentResi = atom.resi; - } - } - this.drawSmoothCurve(group, points, curveWidth, colors, div); -}; - -GLmol.prototype.drawMainchainTube = function(group, atomlist, atomName, radius) { - var points = [], colors = [], radii = []; - var currentChain, currentResi; - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; - if (atom == undefined) continue; - - if ((atom.atom == atomName) && !atom.hetflag) { - if (currentChain != atom.chain || currentResi + 1 != atom.resi) { - this.drawSmoothTube(group, points, colors, radii); - points = []; colors = []; radii = []; - } - points.push(new TV3(atom.x, atom.y, atom.z)); - if (radius == undefined) { - radii.push((atom.b > 0) ? atom.b / 100 : 0.3); - } else { - radii.push(radius); - } - colors.push(atom.color); - currentChain = atom.chain; - currentResi = atom.resi; - } - } - this.drawSmoothTube(group, points, colors, radii); -}; - -GLmol.prototype.drawStrip = function(group, p1, p2, colors, div, thickness) { - if ((p1.length) < 2) return; - div = div || this.axisDIV; - p1 = this.subdivide(p1, div); - p2 = this.subdivide(p2, div); - if (!thickness) return this.drawThinStrip(group, p1, p2, colors, div); - - var geo = new THREE.Geometry(); - var vs = geo.vertices, fs = geo.faces; - var axis, p1v, p2v, a1v, a2v; - for (var i = 0, lim = p1.length; i < lim; i++) { - vs.push(p1v = p1[i]); // 0 - vs.push(p1v); // 1 - vs.push(p2v = p2[i]); // 2 - vs.push(p2v); // 3 - if (i < lim - 1) { - var toNext = p1[i + 1].clone().subSelf(p1[i]); - var toSide = p2[i].clone().subSelf(p1[i]); - axis = toSide.crossSelf(toNext).normalize().multiplyScalar(thickness); - } - vs.push(a1v = p1[i].clone().addSelf(axis)); // 4 - vs.push(a1v); // 5 - vs.push(a2v = p2[i].clone().addSelf(axis)); // 6 - vs.push(a2v); // 7 - } - var faces = [[0, 2, -6, -8], [-4, -2, 6, 4], [7, 3, -5, -1], [-3, -7, 1, 5]]; - for (var i = 1, lim = p1.length; i < lim; i++) { - var offset = 8 * i, color = new TCo(colors[Math.round((i - 1)/ div)]); - for (var j = 0; j < 4; j++) { - var f = new THREE.Face4(offset + faces[j][0], offset + faces[j][1], offset + faces[j][2], offset + faces[j][3], undefined, color); - fs.push(f); - } - } - var vsize = vs.length - 8; // Cap - for (var i = 0; i < 4; i++) {vs.push(vs[i * 2]); vs.push(vs[vsize + i * 2])}; - vsize += 8; - fs.push(new THREE.Face4(vsize, vsize + 2, vsize + 6, vsize + 4, undefined, fs[0].color)); - fs.push(new THREE.Face4(vsize + 1, vsize + 5, vsize + 7, vsize + 3, undefined, fs[fs.length - 3].color)); - geo.computeFaceNormals(); - geo.computeVertexNormals(false); - var material = new THREE.MeshLambertMaterial(); - material.vertexColors = THREE.FaceColors; - var mesh = new THREE.Mesh(geo, material); - mesh.doubleSided = true; - group.add(mesh); -}; - - -GLmol.prototype.drawThinStrip = function(group, p1, p2, colors, div) { - var geo = new THREE.Geometry(); - for (var i = 0, lim = p1.length; i < lim; i++) { - geo.vertices.push(p1[i]); // 2i - geo.vertices.push(p2[i]); // 2i + 1 - } - for (var i = 1, lim = p1.length; i < lim; i++) { - var f = new THREE.Face4(2 * i, 2 * i + 1, 2 * i - 1, 2 * i - 2); - f.color = new TCo(colors[Math.round((i - 1)/ div)]); - geo.faces.push(f); - } - geo.computeFaceNormals(); - geo.computeVertexNormals(false); - var material = new THREE.MeshLambertMaterial(); - material.vertexColors = THREE.FaceColors; - var mesh = new THREE.Mesh(geo, material); - mesh.doubleSided = true; - group.add(mesh); -}; - - -GLmol.prototype.IcosahedronGeometry = function() { - if (!this.icosahedron) this.icosahedron = new THREE.IcosahedronGeometry(1); - return this.icosahedron; -}; - -GLmol.prototype.drawCylinder = function(group, from, to, radius, color, cap) { - if (!from || !to) return; - - var midpoint = new TV3().add(from, to).multiplyScalar(0.5); - var color = new TCo(color); - - if (!this.cylinderGeometry) { - this.cylinderGeometry = new THREE.CylinderGeometry(1, 1, 1, this.cylinderQuality, 1, !cap); - this.cylinderGeometry.faceUvs = []; - this.faceVertexUvs = []; - } - var cylinderMaterial = new THREE.MeshLambertMaterial({color: color.getHex()}); - var cylinder = new THREE.Mesh(this.cylinderGeometry, cylinderMaterial); - cylinder.position = midpoint; - cylinder.lookAt(from); - cylinder.updateMatrix(); - cylinder.matrixAutoUpdate = false; - var m = new THREE.Matrix4().makeScale(radius, radius, from.distanceTo(to)); - m.rotateX(Math.PI / 2); - cylinder.matrix.multiplySelf(m); - group.add(cylinder); -}; - -// FIXME: transition! -GLmol.prototype.drawHelixAsCylinder = function(group, atomlist, radius) { - var start = null; - var currentChain, currentResi; - - var others = [], beta = []; - - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; - if (atom == undefined || atom.hetflag) continue; - if ((atom.ss != 'h' && atom.ss != 's') || atom.ssend || atom.ssbegin) others.push(atom.serial); - if (atom.ss == 's') beta.push(atom.serial); - if (atom.atom != 'CA') continue; - - if (atom.ss == 'h' && atom.ssend) { - if (start != null) this.drawCylinder(group, new TV3(start.x, start.y, start.z), new TV3(atom.x, atom.y, atom.z), radius, atom.color, true); - start = null; - } - currentChain = atom.chain; - currentResi = atom.resi; - if (start == null && atom.ss == 'h' && atom.ssbegin) start = atom; - } - if (start != null) this.drawCylinder(group, new TV3(start.x, start.y, start.z), new TV3(atom.x, atom.y, atom.z), radius, atom.color); - this.drawMainchainTube(group, others, "CA", 0.3); - this.drawStrand(group, beta, undefined, undefined, true, 0, this.helixSheetWidth, false, this.thickness * 2); -}; - -GLmol.prototype.drawCartoon = function(group, atomlist, doNotSmoothen, thickness) { - this.drawStrand(group, atomlist, 2, undefined, true, undefined, undefined, doNotSmoothen, thickness); -}; - -GLmol.prototype.drawStrand = function(group, atomlist, num, div, fill, coilWidth, helixSheetWidth, doNotSmoothen, thickness) { - num = num || this.strandDIV; - div = div || this.axisDIV; - coilWidth = coilWidth || this.coilWidth; - doNotSmoothen == (doNotSmoothen == undefined) ? false : doNotSmoothen; - helixSheetWidth = helixSheetWidth || this.helixSheetWidth; - var points = []; for (var k = 0; k < num; k++) points[k] = []; - var colors = []; - var currentChain, currentResi, currentCA; - var prevCO = null, ss=null, ssborder = false; - - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; - if (atom == undefined) continue; - - if ((atom.atom == 'O' || atom.atom == 'CA') && !atom.hetflag) { - if (atom.atom == 'CA') { - if (currentChain != atom.chain || currentResi + 1 != atom.resi) { - for (var j = 0; !thickness && j < num; j++) - this.drawSmoothCurve(group, points[j], 1 ,colors, div); - if (fill) this.drawStrip(group, points[0], points[num - 1], colors, div, thickness); - var points = []; for (var k = 0; k < num; k++) points[k] = []; - colors = []; - prevCO = null; ss = null; ssborder = false; - } - currentCA = new TV3(atom.x, atom.y, atom.z); - currentChain = atom.chain; - currentResi = atom.resi; - ss = atom.ss; ssborder = atom.ssstart || atom.ssend; - colors.push(atom.color); - } else { // O - var O = new TV3(atom.x, atom.y, atom.z); - O.subSelf(currentCA); - O.normalize(); // can be omitted for performance - O.multiplyScalar((ss == 'c') ? coilWidth : helixSheetWidth); - if (prevCO != undefined && O.dot(prevCO) < 0) O.negate(); - prevCO = O; - for (var j = 0; j < num; j++) { - var delta = -1 + 2 / (num - 1) * j; - var v = new TV3(currentCA.x + prevCO.x * delta, - currentCA.y + prevCO.y * delta, currentCA.z + prevCO.z * delta); - if (!doNotSmoothen && ss == 's') v.smoothen = true; - points[j].push(v); - } - } - } - } - for (var j = 0; !thickness && j < num; j++) - this.drawSmoothCurve(group, points[j], 1 ,colors, div); - if (fill) this.drawStrip(group, points[0], points[num - 1], colors, div, thickness); -}; - -GLmol.prototype.drawNucleicAcidLadderSub = function(geo, lineGeo, atoms, color) { -// color.r *= 0.9; color.g *= 0.9; color.b *= 0.9; - if (atoms[0] != undefined && atoms[1] != undefined && atoms[2] != undefined && - atoms[3] != undefined && atoms[4] != undefined && atoms[5] != undefined) { - var baseFaceId = geo.vertices.length; - for (var i = 0; i <= 5; i++) geo.vertices.push(atoms[i]); - geo.faces.push(new TF3(baseFaceId, baseFaceId + 1, baseFaceId + 2)); - geo.faces.push(new TF3(baseFaceId, baseFaceId + 2, baseFaceId + 3)); - geo.faces.push(new TF3(baseFaceId, baseFaceId + 3, baseFaceId + 4)); - geo.faces.push(new TF3(baseFaceId, baseFaceId + 4, baseFaceId + 5)); - for (var j = geo.faces.length - 4, lim = geo.faces.length; j < lim; j++) geo.faces[j].color = color; - } - if (atoms[4] != undefined && atoms[3] != undefined && atoms[6] != undefined && - atoms[7] != undefined && atoms[8] != undefined) { - var baseFaceId = geo.vertices.length; - geo.vertices.push(atoms[4]); - geo.vertices.push(atoms[3]); - geo.vertices.push(atoms[6]); - geo.vertices.push(atoms[7]); - geo.vertices.push(atoms[8]); - for (var i = 0; i <= 4; i++) geo.colors.push(color); - geo.faces.push(new TF3(baseFaceId, baseFaceId + 1, baseFaceId + 2)); - geo.faces.push(new TF3(baseFaceId, baseFaceId + 2, baseFaceId + 3)); - geo.faces.push(new TF3(baseFaceId, baseFaceId + 3, baseFaceId + 4)); - for (var j = geo.faces.length - 3, lim = geo.faces.length; j < lim; j++) geo.faces[j].color = color; - } -}; - -GLmol.prototype.drawNucleicAcidLadder = function(group, atomlist) { - var geo = new THREE.Geometry(); - var lineGeo = new THREE.Geometry(); - var baseAtoms = ["N1", "C2", "N3", "C4", "C5", "C6", "N9", "C8", "N7"]; - var currentChain, currentResi, currentComponent = new Array(baseAtoms.length); - var color = new TCo(0xcc0000); - - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; - if (atom == undefined || atom.hetflag) continue; - - if (atom.resi != currentResi || atom.chain != currentChain) { - this.drawNucleicAcidLadderSub(geo, lineGeo, currentComponent, color); - currentComponent = new Array(baseAtoms.length); - } - var pos = baseAtoms.indexOf(atom.atom); - if (pos != -1) currentComponent[pos] = new TV3(atom.x, atom.y, atom.z); - if (atom.atom == 'O3\'') color = new TCo(atom.color); - currentResi = atom.resi; currentChain = atom.chain; - } - this.drawNucleicAcidLadderSub(geo, lineGeo, currentComponent, color); - geo.computeFaceNormals(); - var mat = new THREE.MeshLambertMaterial(); - mat.vertexColors = THREE.VertexColors; - var mesh = new THREE.Mesh(geo, mat); - mesh.doubleSided = true; - group.add(mesh); -}; - -GLmol.prototype.drawNucleicAcidStick = function(group, atomlist) { - var currentChain, currentResi, start = null, end = null; - - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; - if (atom == undefined || atom.hetflag) continue; - - if (atom.resi != currentResi || atom.chain != currentChain) { - if (start != null && end != null) - this.drawCylinder(group, new TV3(start.x, start.y, start.z), - new TV3(end.x, end.y, end.z), 0.3, start.color, true); - start = null; end = null; - } - if (atom.atom == 'O3\'') start = atom; - if (atom.resn == ' A' || atom.resn == ' G' || atom.resn == ' DA' || atom.resn == ' DG') { - if (atom.atom == 'N1') end = atom; // N1(AG), N3(CTU) - } else if (atom.atom == 'N3') { - end = atom; - } - currentResi = atom.resi; currentChain = atom.chain; - } - if (start != null && end != null) - this.drawCylinder(group, new TV3(start.x, start.y, start.z), - new TV3(end.x, end.y, end.z), 0.3, start.color, true); -}; - -GLmol.prototype.drawNucleicAcidLine = function(group, atomlist) { - var currentChain, currentResi, start = null, end = null; - var geo = new THREE.Geometry(); - - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; - if (atom == undefined || atom.hetflag) continue; - - if (atom.resi != currentResi || atom.chain != currentChain) { - if (start != null && end != null) { - geo.vertices.push(new TV3(start.x, start.y, start.z)); - geo.colors.push(new TCo(start.color)); - geo.vertices.push(new TV3(end.x, end.y, end.z)); - geo.colors.push(new TCo(start.color)); - } - start = null; end = null; - } - if (atom.atom == 'O3\'') start = atom; - if (atom.resn == ' A' || atom.resn == ' G' || atom.resn == ' DA' || atom.resn == ' DG') { - if (atom.atom == 'N1') end = atom; // N1(AG), N3(CTU) - } else if (atom.atom == 'N3') { - end = atom; - } - currentResi = atom.resi; currentChain = atom.chain; - } - if (start != null && end != null) { - geo.vertices.push(new TV3(start.x, start.y, start.z)); - geo.colors.push(new TCo(start.color)); - geo.vertices.push(new TV3(end.x, end.y, end.z)); - geo.colors.push(new TCo(start.color)); - } - var mat = new THREE.LineBasicMaterial({linewidth: 1, linejoin: false}); - mat.linewidth = 1.5; mat.vertexColors = true; - var line = new THREE.Line(geo, mat, THREE.LinePieces); - group.add(line); -}; - -GLmol.prototype.drawCartoonNucleicAcid = function(group, atomlist, div, thickness) { - this.drawStrandNucleicAcid(group, atomlist, 2, div, true, undefined, thickness); -}; - -GLmol.prototype.drawStrandNucleicAcid = function(group, atomlist, num, div, fill, nucleicAcidWidth, thickness) { - nucleicAcidWidth = nucleicAcidWidth || this.nucleicAcidWidth; - div = div || this.axisDIV; - num = num || this.nucleicAcidStrandDIV; - var points = []; for (var k = 0; k < num; k++) points[k] = []; - var colors = []; - var currentChain, currentResi, currentO3; - var prevOO = null; - - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; - if (atom == undefined) continue; - - if ((atom.atom == 'O3\'' || atom.atom == 'OP2') && !atom.hetflag) { - if (atom.atom == 'O3\'') { // to connect 3' end. FIXME: better way to do? - if (currentChain != atom.chain || currentResi + 1 != atom.resi) { - if (currentO3) { - for (var j = 0; j < num; j++) { - var delta = -1 + 2 / (num - 1) * j; - points[j].push(new TV3(currentO3.x + prevOO.x * delta, - currentO3.y + prevOO.y * delta, currentO3.z + prevOO.z * delta)); - } - } - if (fill) this.drawStrip(group, points[0], points[1], colors, div, thickness); - for (var j = 0; !thickness && j < num; j++) - this.drawSmoothCurve(group, points[j], 1 ,colors, div); - var points = []; for (var k = 0; k < num; k++) points[k] = []; - colors = []; - prevOO = null; - } - currentO3 = new TV3(atom.x, atom.y, atom.z); - currentChain = atom.chain; - currentResi = atom.resi; - colors.push(atom.color); - } else { // OP2 - if (!currentO3) {prevOO = null; continue;} // for 5' phosphate (e.g. 3QX3) - var O = new TV3(atom.x, atom.y, atom.z); - O.subSelf(currentO3); - O.normalize().multiplyScalar(nucleicAcidWidth); // TODO: refactor - if (prevOO != undefined && O.dot(prevOO) < 0) { - O.negate(); - } - prevOO = O; - for (var j = 0; j < num; j++) { - var delta = -1 + 2 / (num - 1) * j; - points[j].push(new TV3(currentO3.x + prevOO.x * delta, - currentO3.y + prevOO.y * delta, currentO3.z + prevOO.z * delta)); - } - currentO3 = null; - } - } - } - if (currentO3) { - for (var j = 0; j < num; j++) { - var delta = -1 + 2 / (num - 1) * j; - points[j].push(new TV3(currentO3.x + prevOO.x * delta, - currentO3.y + prevOO.y * delta, currentO3.z + prevOO.z * delta)); - } - } - if (fill) this.drawStrip(group, points[0], points[1], colors, div, thickness); - for (var j = 0; !thickness && j < num; j++) - this.drawSmoothCurve(group, points[j], 1 ,colors, div); -}; - -GLmol.prototype.drawDottedLines = function(group, points, color) { - var geo = new THREE.Geometry(); - var step = 0.3; - - for (var i = 0, lim = Math.floor(points.length / 2); i < lim; i++) { - var p1 = points[2 * i], p2 = points[2 * i + 1]; - var delta = p2.clone().subSelf(p1); - var dist = delta.length(); - delta.normalize().multiplyScalar(step); - var jlim = Math.floor(dist / step); - for (var j = 0; j < jlim; j++) { - var p = new TV3(p1.x + delta.x * j, p1.y + delta.y * j, p1.z + delta.z * j); - geo.vertices.push(p); - } - if (jlim % 2 == 1) geo.vertices.push(p2); - } - - var mat = new THREE.LineBasicMaterial({'color': color.getHex()}); - mat.linewidth = 2; - var line = new THREE.Line(geo, mat, THREE.LinePieces); - group.add(line); -}; - -GLmol.prototype.getAllAtoms = function() { - var ret = []; - for (var i in this.atoms) { - ret.push(this.atoms[i].serial); - } - return ret; -}; - -// Probably I can refactor using higher-order functions. -GLmol.prototype.getHetatms = function(atomlist) { - var ret = []; - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; - - if (atom.hetflag) ret.push(atom.serial); - } - return ret; -}; - -GLmol.prototype.removeSolvents = function(atomlist) { - var ret = []; - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; - - if (atom.resn != 'HOH') ret.push(atom.serial); - } - return ret; -}; - -GLmol.prototype.getProteins = function(atomlist) { - var ret = []; - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; - - if (!atom.hetflag) ret.push(atom.serial); - } - return ret; -}; - -// TODO: Test -GLmol.prototype.excludeAtoms = function(atomlist, deleteList) { - var ret = []; - var blackList = new Object(); - for (var _i in deleteList) blackList[deleteList[_i]] = true; - - for (var _i in atomlist) { - var i = atomlist[_i]; - - if (!blackList[i]) ret.push(i); - } - return ret; -}; - -GLmol.prototype.getSidechains = function(atomlist) { - var ret = []; - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; - - if (atom.hetflag) continue; - if (atom.atom == 'C' || atom.atom == 'O' || (atom.atom == 'N' && atom.resn != "PRO")) continue; - ret.push(atom.serial); - } - return ret; -}; - -GLmol.prototype.getAtomsWithin = function(atomlist, extent) { - var ret = []; - - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; - - if (atom.x < extent[0][0] || atom.x > extent[1][0]) continue; - if (atom.y < extent[0][1] || atom.y > extent[1][1]) continue; - if (atom.z < extent[0][2] || atom.z > extent[1][2]) continue; - ret.push(atom.serial); - } - return ret; -}; - -GLmol.prototype.getExtent = function(atomlist) { - var xmin = ymin = zmin = 9999; - var xmax = ymax = zmax = -9999; - var xsum = ysum = zsum = cnt = 0; - - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; - cnt++; - xsum += atom.x; ysum += atom.y; zsum += atom.z; - - xmin = (xmin < atom.x) ? xmin : atom.x; - ymin = (ymin < atom.y) ? ymin : atom.y; - zmin = (zmin < atom.z) ? zmin : atom.z; - xmax = (xmax > atom.x) ? xmax : atom.x; - ymax = (ymax > atom.y) ? ymax : atom.y; - zmax = (zmax > atom.z) ? zmax : atom.z; - } - return [[xmin, ymin, zmin], [xmax, ymax, zmax], [xsum / cnt, ysum / cnt, zsum / cnt]]; -}; - -GLmol.prototype.getResiduesById = function(atomlist, resi) { - var ret = []; - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; - - if (resi.indexOf(atom.resi) != -1) ret.push(atom.serial); - } - return ret; -}; - -GLmol.prototype.getResidueBySS = function(atomlist, ss) { - var ret = []; - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; - - if (ss.indexOf(atom.ss) != -1) ret.push(atom.serial); - } - return ret; -}; - -GLmol.prototype.getChain = function(atomlist, chain) { - var ret = [], chains = {}; - chain = chain.toString(); // concat if Array - for (var i = 0, lim = chain.length; i < lim; i++) chains[chain.substr(i, 1)] = true; - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; - - if (chains[atom.chain]) ret.push(atom.serial); - } - return ret; -}; - -// for HETATM only -GLmol.prototype.getNonbonded = function(atomlist, chain) { - var ret = []; - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; - - if (atom.hetflag && atom.bonds.length == 0) ret.push(atom.serial); - } - return ret; -}; - -GLmol.prototype.colorByAtom = function(atomlist, colors) { - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; - - var c = colors[atom.elem]; - if (c == undefined) c = this.ElementColors[atom.elem]; - if (c == undefined) c = this.defaultColor; - atom.color = c; - } -}; - - -// MEMO: Color only CA. maybe I should add atom.cartoonColor. -GLmol.prototype.colorByStructure = function(atomlist, helixColor, sheetColor, colorSidechains) { - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; - - if (!colorSidechains && (atom.atom != 'CA' || atom.hetflag)) continue; - if (atom.ss[0] == 's') atom.color = sheetColor; - else if (atom.ss[0] == 'h') atom.color = helixColor; - } -}; - -GLmol.prototype.colorByBFactor = function(atomlist, colorSidechains) { - var minB = 1000, maxB = -1000; - - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; - - if (atom.hetflag) continue; - if (colorSidechains || atom.atom == 'CA' || atom.atom == 'O3\'') { - if (minB > atom.b) minB = atom.b; - if (maxB < atom.b) maxB = atom.b; - } - } - - var mid = (maxB + minB) / 2; - - var range = (maxB - minB) / 2; - if (range < 0.01 && range > -0.01) return; - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; - - if (atom.hetflag) continue; - if (colorSidechains || atom.atom == 'CA' || atom.atom == 'O3\'') { - var color = new TCo(0); - if (atom.b < mid) - color.setHSV(0.667, (mid - atom.b) / range, 1); - else - color.setHSV(0, (atom.b - mid) / range, 1); - atom.color = color.getHex(); - } - } -}; - -GLmol.prototype.colorByChain = function(atomlist, colorSidechains) { - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; - - if (atom.hetflag) continue; - if (colorSidechains || atom.atom == 'CA' || atom.atom == 'O3\'') { - var color = new TCo(0); - color.setHSV((atom.chain.charCodeAt(0)) % 15 / 15.0, 1, 0.9); - atom.color = color.getHex(); - } - } -}; - -GLmol.prototype.colorByResidue = function(atomlist, residueColors) { - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; - - c = residueColors[atom.resn] - if (c != undefined) atom.color = c; - } -}; - -GLmol.prototype.colorAtoms = function(atomlist, c) { - for (var i in atomlist) { - var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; - - atom.color = c; - } -}; - -GLmol.prototype.colorByPolarity = function(atomlist, polar, nonpolar) { - var polarResidues = ['ARG', 'HIS', 'LYS', 'ASP', 'GLU', 'SER', 'THR', 'ASN', 'GLN', 'CYS']; - var nonPolarResidues = ['GLY', 'PRO', 'ALA', 'VAL', 'LEU', 'ILE', 'MET', 'PHE', 'TYR', 'TRP']; - var colorMap = {}; - for (var i in polarResidues) colorMap[polarResidues[i]] = polar; - for (i in nonPolarResidues) colorMap[nonPolarResidues[i]] = nonpolar; - this.colorByResidue(atomlist, colorMap); -}; - -// TODO: Add near(atomlist, neighbor, distanceCutoff) -// TODO: Add expandToResidue(atomlist) - -GLmol.prototype.colorChainbow = function(atomlist, colorSidechains) { - var cnt = 0; - var atom, i; - for (i in atomlist) { - atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; - - if ((colorSidechains || atom.atom != 'CA' || atom.atom != 'O3\'') && !atom.hetflag) - cnt++; - } - - var total = cnt; - cnt = 0; - for (i in atomlist) { - atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; - - if ((colorSidechains || atom.atom != 'CA' || atom.atom != 'O3\'') && !atom.hetflag) { - var color = new TCo(0); - color.setHSV(240.0 / 360 * (1 - cnt / total), 1, 0.9); - atom.color = color.getHex(); - cnt++; - } - } -}; - -GLmol.prototype.drawSymmetryMates2 = function(group, asu, matrices) { - if (matrices == undefined) return; - asu.matrixAutoUpdate = false; - - var cnt = 1; - this.protein.appliedMatrix = new THREE.Matrix4(); - for (var i = 0; i < matrices.length; i++) { - var mat = matrices[i]; - if (mat == undefined || mat.isIdentity()) continue; - console.log(mat); - var symmetryMate = THREE.SceneUtils.cloneObject(asu); - symmetryMate.matrix = mat; - group.add(symmetryMate); - for (var j = 0; j < 16; j++) this.protein.appliedMatrix.elements[j] += mat.elements[j]; - cnt++; - } - this.protein.appliedMatrix.multiplyScalar(1.0 / cnt); -}; - - -GLmol.prototype.drawSymmetryMatesWithTranslation2 = function(group, asu, matrices) { - if (matrices == undefined) return; - var p = this.protein; - asu.matrixAutoUpdate = false; - - for (var i = 0; i < matrices.length; i++) { - var mat = matrices[i]; - if (mat == undefined) continue; - - for (var a = -1; a <=0; a++) { - for (var b = -1; b <= 0; b++) { - for (var c = -1; c <= 0; c++) { - var translationMat = new THREE.Matrix4().makeTranslation( - p.ax * a + p.bx * b + p.cx * c, - p.ay * a + p.by * b + p.cy * c, - p.az * a + p.bz * b + p.cz * c); - var symop = mat.clone().multiplySelf(translationMat); - if (symop.isIdentity()) continue; - var symmetryMate = THREE.SceneUtils.cloneObject(asu); - symmetryMate.matrix = symop; - group.add(symmetryMate); - } - } - } - } -}; - -GLmol.prototype.defineRepresentation = function() { - var all = this.getAllAtoms(); - var hetatm = this.removeSolvents(this.getHetatms(all)); - this.colorByAtom(all, {}); - this.colorByChain(all); - - this.drawAtomsAsSphere(this.modelGroup, hetatm, this.sphereRadius); - this.drawMainchainCurve(this.modelGroup, all, this.curveWidth, 'P'); - this.drawCartoon(this.modelGroup, all, this.curveWidth); -}; - -GLmol.prototype.getView = function() { - if (!this.modelGroup) return [0, 0, 0, 0, 0, 0, 0, 1]; - var pos = this.modelGroup.position; - var q = this.rotationGroup.quaternion; - return [pos.x, pos.y, pos.z, this.rotationGroup.position.z, q.x, q.y, q.z, q.w]; -}; - -GLmol.prototype.setView = function(arg) { - if (!this.modelGroup || !this.rotationGroup) return; - this.modelGroup.position.x = arg[0]; - this.modelGroup.position.y = arg[1]; - this.modelGroup.position.z = arg[2]; - this.rotationGroup.position.z = arg[3]; - this.rotationGroup.quaternion.x = arg[4]; - this.rotationGroup.quaternion.y = arg[5]; - this.rotationGroup.quaternion.z = arg[6]; - this.rotationGroup.quaternion.w = arg[7]; - this.show(); -}; - -GLmol.prototype.setBackground = function(hex, a) { - a = a | 1.0; - this.bgColor = hex; - this.renderer.setClearColorHex(hex, a); - this.scene.fog.color = new TCo(hex); -}; - -GLmol.prototype.initializeScene = function() { - // CHECK: Should I explicitly call scene.deallocateObject? - this.scene = new THREE.Scene(); - this.scene.fog = new THREE.Fog(this.bgColor, 100, 200); - - this.modelGroup = new THREE.Object3D(); - this.rotationGroup = new THREE.Object3D(); - this.rotationGroup.useQuaternion = true; - this.rotationGroup.quaternion = new THREE.Quaternion(1, 0, 0, 0); - this.rotationGroup.add(this.modelGroup); - - this.scene.add(this.rotationGroup); - this.setupLights(this.scene); -}; - -GLmol.prototype.zoomInto = function(atomlist, keepSlab) { - // TODO: expand if symmetry mates are present - var tmp = this.getExtent(atomlist); // atomlist is the problem - var center = new TV3(tmp[2][0], tmp[2][1], tmp[2][2]); - center = new TV3((tmp[0][0] + tmp[1][0]) / 2, (tmp[0][1] + tmp[1][1]) / 2, (tmp[0][2] + tmp[1][2]) / 2); - console.log(center.x, center.y, center.z); - console.log(this.protein.appliedMatrix); - if (this.protein.appliedMatrix) {center = this.protein.appliedMatrix.multiplyVector3(center);} - console.log(center.x, center.y, center.z); - this.modelGroup.position = center.multiplyScalar(-1); - var x = tmp[1][0] - tmp[0][0], y = tmp[1][1] - tmp[0][1], z = tmp[1][2] - tmp[0][2]; - - var maxD = Math.sqrt(x * x + y * y + z * z); - if (maxD < 25) maxD = 25; - - if (!keepSlab) { - this.slabNear = -maxD / 1.9; - this.slabFar = maxD / 3; - } - - this.rotationGroup.position.z = maxD * 0.35 / Math.tan(Math.PI / 180.0 * this.camera.fov / 2) - 150; - this.rotationGroup.quaternion = new THREE.Quaternion(1, 0, 0, 0); -}; - -GLmol.prototype.rebuildScene = function() { - time = new Date(); - - var view = this.getView(); - this.initializeScene(); - this.defineRepresentation(); - this.setView(view); - - console.log("builded scene in " + (+new Date() - time) + "ms"); -}; - -GLmol.prototype.loadMolecule = function(repressZoom) { - this.loadMoleculeStr(repressZoom, $('#' + this.id + '_src').val()); -}; - -GLmol.prototype.loadMoleculeStr = function(repressZoom, source) { - var time = new Date(); - - this.protein = {sheet: [], helix: [], biomtChains: '', biomtMatrices: [], symMat: [], pdbID: '', title: ''}; - this.atoms = []; - - this.parsePDB2(source); - this.parseSDF(source); - this.parseXYZ(source); - console.log("parsed in " + (+new Date() - time) + "ms"); - - var title = $('#' + this.id + '_pdbTitle'); - var titleStr = ''; - if (this.protein.pdbID != '') titleStr += '' + this.protein.pdbID + ''; - if (this.protein.title != '') titleStr += '
' + this.protein.title; - title.html(titleStr); - - this.rebuildScene(true); - if (repressZoom == undefined || !repressZoom) this.zoomInto(this.getAllAtoms()); - - this.show(); - }; - -GLmol.prototype.setSlabAndFog = function() { - var center = this.rotationGroup.position.z - this.camera.position.z; - if (center < 1) center = 1; - this.camera.near = center + this.slabNear; - if (this.camera.near < 1) this.camera.near = 1; - this.camera.far = center + this.slabFar; - if (this.camera.near + 1 > this.camera.far) this.camera.far = this.camera.near + 1; - if (this.camera instanceof THREE.PerspectiveCamera) { - this.camera.fov = this.fov; - } else { - this.camera.right = center * Math.tan(Math.PI / 180 * this.fov); - this.camera.left = - this.camera.right; - this.camera.top = this.camera.right / this.ASPECT; - this.camera.bottom = - this.camera.top; - } - this.camera.updateProjectionMatrix(); - this.scene.fog.near = this.camera.near + this.fogStart * (this.camera.far - this.camera.near); -// if (this.scene.fog.near > center) this.scene.fog.near = center; - this.scene.fog.far = this.camera.far; -}; - -GLmol.prototype.enableMouse = function() { - var me = this, glDOM = $(this.renderer.domElement); - - // TODO: Better touch panel support. - // Contribution is needed as I don't own any iOS or Android device with WebGL support. - glDOM.bind('mousedown touchstart', function(ev) { - ev.preventDefault(); - if (!me.scene) return; - var x = ev.pageX, y = ev.pageY; - if (ev.originalEvent.targetTouches && ev.originalEvent.targetTouches[0]) { - x = ev.originalEvent.targetTouches[0].pageX; - y = ev.originalEvent.targetTouches[0].pageY; - } - if (x == undefined) return; - me.isDragging = true; - me.mouseButton = ev.which; - me.mouseStartX = x; - me.mouseStartY = y; - me.cq = me.rotationGroup.quaternion; - me.cz = me.rotationGroup.position.z; - me.currentModelPos = me.modelGroup.position.clone(); - me.cslabNear = me.slabNear; - me.cslabFar = me.slabFar; - }); - - glDOM.bind('DOMMouseScroll mousewheel', function(ev) { // Zoom - ev.preventDefault(); - if (!me.scene) return; - var scaleFactor = (me.rotationGroup.position.z - me.CAMERA_Z) * 0.85; - if (ev.originalEvent.detail) { // Webkit - me.rotationGroup.position.z += scaleFactor * ev.originalEvent.detail / 10; - } else if (ev.originalEvent.wheelDelta) { // Firefox - me.rotationGroup.position.z -= scaleFactor * ev.originalEvent.wheelDelta / 400; - } - console.log(ev.originalEvent.wheelDelta, ev.originalEvent.detail, me.rotationGroup.position.z); - me.show(); - }); - glDOM.bind("contextmenu", function(ev) {ev.preventDefault();}); - $('body').bind('mouseup touchend', function(ev) { - me.isDragging = false; - if (me.translate_callback) me.translate_callback() - }); - - glDOM.bind('mousemove touchmove', function(ev) { // touchmove - ev.preventDefault(); - if (!me.scene) return; - if (!me.isDragging) return; - var mode = 0; - var modeRadio = $('input[name=' + me.id + '_mouseMode]:checked'); - if (modeRadio.length > 0) mode = parseInt(modeRadio.val()); - - var x = ev.pageX, y = ev.pageY; - if (ev.originalEvent.targetTouches && ev.originalEvent.targetTouches[0]) { - x = ev.originalEvent.targetTouches[0].pageX; - y = ev.originalEvent.targetTouches[0].pageY; - } - if (x == undefined) return; - var dx = (x - me.mouseStartX) / me.WIDTH; - var dy = (y - me.mouseStartY) / me.HEIGHT; - var r = Math.sqrt(dx * dx + dy * dy); - if (mode == 3 || (me.mouseButton == 3 && ev.ctrlKey)) { // Slab - me.slabNear = me.cslabNear + dx * 100; - me.slabFar = me.cslabFar + dy * 100; - } else if (mode == 2 || me.mouseButton == 3 || ev.shiftKey) { // Zoom - var scaleFactor = (me.rotationGroup.position.z - me.CAMERA_Z) * 0.85; - if (scaleFactor < 80) scaleFactor = 80; - me.rotationGroup.position.z = me.cz - dy * scaleFactor; - } else if (mode == 1 || me.mouseButton == 2 || ev.ctrlKey) { // Translate - var scaleFactor = (me.rotationGroup.position.z - me.CAMERA_Z) * 0.85; - if (scaleFactor < 20) scaleFactor = 20; - var translationByScreen = new TV3(- dx * scaleFactor, - dy * scaleFactor, 0); - var q = me.rotationGroup.quaternion; - var qinv = new THREE.Quaternion(q.x, q.y, q.z, q.w).inverse().normalize(); - var translation = qinv.multiplyVector3(translationByScreen); - me.modelGroup.position.x = me.currentModelPos.x + translation.x; - me.modelGroup.position.y = me.currentModelPos.y + translation.y; - me.modelGroup.position.z = me.currentModelPos.z + translation.z; - } else if ((mode == 0 || me.mouseButton == 1) && r != 0) { // Rotate - var rs = Math.sin(r * Math.PI) / r; - me.dq.x = Math.cos(r * Math.PI); - me.dq.y = 0; - me.dq.z = rs * dx; - me.dq.w = rs * dy; - me.rotationGroup.quaternion = new THREE.Quaternion(1, 0, 0, 0); - me.rotationGroup.quaternion.multiplySelf(me.dq); - me.rotationGroup.quaternion.multiplySelf(me.cq); - } - me.show(); - }); -}; - - -GLmol.prototype.show = function() { - if (!this.scene) return; - - var time = new Date(); - this.setSlabAndFog(); - this.renderer.render(this.scene, this.camera); - - console.log("rendered in " + (+new Date() - time) + "ms"); -}; - -// For scripting -GLmol.prototype.doFunc = function(func) { - func(this); -}; - -return GLmol; -}()); diff --git a/client/src/js/vendor/MarchingSquares.js b/client/src/js/vendor/MarchingSquares.js deleted file mode 100644 index 786562540..000000000 --- a/client/src/js/vendor/MarchingSquares.js +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Initially based on Three.js's implementation of Marching Cubes by - * alteredq http://alteredqualia.com/ - * http://github.com/mrdoob/three.js/blob/master/examples/js/MarchingCubes.js - * - * , which is port of greggman's ThreeD version of marching cubes to Three.js - * http://webglsamples.googlecode.com/hg/blob/blob.html - * - * Then @biochem_fan modified it into Marching Squares as implemented in - * Cuemol http://www.cuemol.org/ja/. - */ - -THREE.MarchingCubes = function (map, nc, nr, ns, ncstart, nrstart, nsstart) { - this.init = function() { - this.geo = new THREE.Geometry(); - this.vertices = this.geo.vertices; - this.ncstart = ncstart, this.nrstart = nrstart, this.nsstart = nsstart; - - this.size = nc; - this.size2 = this.size * nr; - this.size3 = this.size2 * ns; - - this.yd = this.size; - this.zd = this.size2; - - this.vlist = new Float32Array( 12 * 3 ); - this.field = map; - - this.count = 0; - }; - - this.VIntX = function(pout, offset, isol, x, y, z, valp1, valp2 ) { - pout[offset] = x + (isol - valp1) / (valp2 - valp1); - pout[offset + 1] = y; - pout[offset + 2] = z; - }; - - this.VIntY = function(pout, offset, isol, x, y, z, valp1, valp2) { - pout[offset] = x; - pout[offset + 1] = y + (isol - valp1) / (valp2 - valp1); - pout[offset + 2] = z; - }; - - this.VIntZ = function(pout, offset, isol, x, y, z, valp1, valp2) { - pout[offset] = x; - pout[offset + 1] = y; - pout[offset + 2] = z + (isol - valp1) / (valp2 - valp1); - }; - - this.polygonizeYZ = function(fx, fy, fz, q, isol) { - var q1 = q + this.zd, // TODO: fix variable names! - qy = q + this.yd, - q1y = q1 + this.yd; - - var cubeindex = 0, - field0 = this.field[ q ], - field1 = this.field[ q1 ], - field2 = this.field[ qy ], - field3 = this.field[ q1y ]; - - var s0 = ((field1 - isol) * (field0 - isol) > 0) ? 0 : 1, - s1 = ((field3 - isol) * (field1 - isol) > 0) ? 0 : 1, - s2 = ((field2 - isol) * (field3 - isol) > 0) ? 0 : 1, - s3 = ((field0 - isol) * (field2 - isol) > 0) ? 0 : 1; - var fz2 = fz + 1, fy2 = fy + 1; - - if (s0 == 0 && s1 == 0 && s2 == 0 && s3 == 0) return; - if (s0 != 0 && s1 != 0 && s2 != 0 && s3 != 0) { - this.VIntZ(this.vlist, 0, isol, fx, fy, fz, field0, field1); // s0 - this.VIntZ(this.vlist, 3, isol, fx, fy2, fz, field2, field3); // s2 - this.VIntY(this.vlist, 6, isol, fx, fy, fz2, field1, field3); // s1 - this.VIntY(this.vlist, 9, isol, fx, fy, fz, field0, field2); // s3 - this.vertices[this.count++] = (new THREE.Vector3(this.vlist[0], this.vlist[1], this.vlist[2])); - this.vertices[this.count++] = (new THREE.Vector3(this.vlist[3], this.vlist[4], this.vlist[5])); - this.vertices[this.count++] = (new THREE.Vector3(this.vlist[6], this.vlist[7], this.vlist[8])); - this.vertices[this.count++] = (new THREE.Vector3(this.vlist[9], this.vlist[10], this.vlist[11])); - return; - } - - if (s0 != 0 && s1 == 0 && s2 != 0 && s3 == 0) { - this.VIntZ(this.vlist, 0, isol, fx, fy, fz, field0, field1); // s0 - this.VIntZ(this.vlist, 3, isol, fx, fy2, fz, field2, field3); // s2 - } else if (s0 == 0 && s1 != 0 && s2 == 0 && s3 != 0) { - this.VIntY(this.vlist, 0, isol, fx, fy, fz2, field1, field3); // s1 - this.VIntY(this.vlist, 3, isol, fx, fy, fz, field0, field2); // s3 - } else if (s0 == 0 && s1 == 0 && s2 != 0 && s3 != 0) { - this.VIntZ(this.vlist, 0, isol, fx, fy2, fz, field2, field3); // s2 - this.VIntY(this.vlist, 3, isol, fx, fy, fz, field0, field2); // s3 - } else if (s0 == 0 && s1 != 0 && s2 != 0 && s3 == 0) { - this.VIntY(this.vlist, 0, isol, fx, fy, fz2, field1, field3); // s1 - this.VIntZ(this.vlist, 3, isol, fx, fy2, fz, field2, field3); // s2 - } else if (s0 != 0 && s1 != 0 && s2 == 0 && s3 == 0) { - this.VIntZ(this.vlist, 0, isol, fx, fy, fz, field0, field1); // s0 - this.VIntY(this.vlist, 3, isol, fx, fy, fz2, field1, field3); // s1 - } else if (s0 != 0 && s1 == 0 && s2 == 0 && s3 != 0) { - this.VIntZ(this.vlist, 0, isol, fx, fy, fz, field0, field1); // s0 - this.VIntY(this.vlist, 3, isol, fx, fy, fz, field0, field2); // s3 - } - - this.vertices[this.count++] = (new THREE.Vector3(this.vlist[0], this.vlist[1], this.vlist[2])); - this.vertices[this.count++] = (new THREE.Vector3(this.vlist[3], this.vlist[4], this.vlist[5])); - }; - - this.polygonizeXY = function(fx, fy, fz, q, isol) { - var q1 = q + 1, - qy = q + this.yd, - q1y = q1 + this.yd; - - var cubeindex = 0, - field0 = this.field[ q ], // x, y, z - field1 = this.field[ q1 ], // x + 1, y, z - field2 = this.field[ qy ], // x, y + 1, z - field3 = this.field[ q1y ]; // x + 1, y + 1, z - - var s0 = ((field1 - isol) * (field0 - isol) > 0) ? 0 : 1, - s1 = ((field3 - isol) * (field1 - isol) > 0) ? 0 : 1, - s2 = ((field2 - isol) * (field3 - isol) > 0) ? 0 : 1, - s3 = ((field0 - isol) * (field2 - isol) > 0) ? 0 : 1; - var fx2 = fx + 1, fy2 = fy + 1; - - if (s0 == 0 && s1 == 0 && s2 == 0 && s3 == 0) return; - if (s0 != 0 && s1 != 0 && s2 != 0 && s3 != 0) { - this.VIntX(this.vlist, 0, isol, fx, fy, fz, field0, field1); // s0 - this.VIntX(this.vlist, 3, isol, fx, fy2, fz, field2, field3); // s2 - this.VIntY(this.vlist, 6, isol, fx2, fy, fz, field1, field3); // s1 - this.VIntY(this.vlist, 9, isol, fx, fy, fz, field0, field2); // s3 - this.vertices[this.count++] = (new THREE.Vector3(this.vlist[0], this.vlist[1], this.vlist[2])); - this.vertices[this.count++] = (new THREE.Vector3(this.vlist[3], this.vlist[4], this.vlist[5])); - this.vertices[this.count++] = (new THREE.Vector3(this.vlist[6], this.vlist[7], this.vlist[8])); - this.vertices[this.count++] = (new THREE.Vector3(this.vlist[9], this.vlist[10], this.vlist[11])); - return; - } - - if (s0 != 0 && s1 == 0 && s2 != 0 && s3 == 0) { - this.VIntX(this.vlist, 0, isol, fx, fy, fz, field0, field1); // s0 - this.VIntX(this.vlist, 3, isol, fx, fy2, fz, field2, field3); // s2 - } else if (s0 == 0 && s1 != 0 && s2 == 0 && s3 != 0) { - this.VIntY(this.vlist, 0, isol, fx2, fy, fz, field1, field3); // s1 - this.VIntY(this.vlist, 3, isol, fx, fy, fz, field0, field2); // s3 - } else if (s0 == 0 && s1 == 0 && s2 != 0 && s3 != 0) { - this.VIntX(this.vlist, 0, isol, fx, fy2, fz, field2, field3); // s2 - this.VIntY(this.vlist, 3, isol, fx, fy, fz, field0, field2); // s3 - } else if (s0 == 0 && s1 != 0 && s2 != 0 && s3 == 0) { - this.VIntY(this.vlist, 0, isol, fx2, fy, fz, field1, field3); // s1 - this.VIntX(this.vlist, 3, isol, fx, fy2, fz, field2, field3); // s2 - } else if (s0 != 0 && s1 != 0 && s2 == 0 && s3 == 0) { - this.VIntX(this.vlist, 0, isol, fx, fy, fz, field0, field1); // s0 - this.VIntY(this.vlist, 3, isol, fx2, fy, fz, field1, field3); // s1 - } else if (s0 != 0 && s1 == 0 && s2 == 0 && s3 != 0) { - this.VIntX(this.vlist, 0, isol, fx, fy, fz, field0, field1); // s0 - this.VIntY(this.vlist, 3, isol, fx, fy, fz, field0, field2); // s3 - } - - this.vertices[this.count++] = (new THREE.Vector3(this.vlist[0], this.vlist[1], this.vlist[2])); - this.vertices[this.count++] = (new THREE.Vector3(this.vlist[3], this.vlist[4], this.vlist[5])); - }; - - this.polygonizeXZ = function(fx, fy, fz, q, isol) { - var q1 = q + 1, - qy = q + this.zd, - q1y = q1 + this.zd; - - var cubeindex = 0, - field0 = this.field[ q ], - field1 = this.field[ q1 ], - field2 = this.field[ qy ], - field3 = this.field[ q1y ]; - - var s0 = ((field1 - isol) * (field0 - isol) > 0) ? 0 : 1, - s1 = ((field3 - isol) * (field1 - isol) > 0) ? 0 : 1, - s2 = ((field2 - isol) * (field3 - isol) > 0) ? 0 : 1, - s3 = ((field0 - isol) * (field2 - isol) > 0) ? 0 : 1; - var fx2 = fx + 1, fz2 = fz + 1; - - if (s0 == 0 && s1 == 0 && s2 == 0 && s3 == 0) return; - if (s0 != 0 && s1 != 0 && s2 != 0 && s3 != 0) { - this.VIntX(this.vlist, 0, isol, fx, fy, fz, field0, field1); // s0 - this.VIntX(this.vlist, 3, isol, fx, fy, fz2, field2, field3); // s2 - this.VIntZ(this.vlist, 6, isol, fx2, fy, fz, field1, field3); // s1 - this.VIntZ(this.vlist, 9, isol, fx, fy, fz, field0, field2); // s3 - this.vertices[this.count++] = (new THREE.Vector3(this.vlist[0], this.vlist[1], this.vlist[2])); - this.vertices[this.count++] = (new THREE.Vector3(this.vlist[3], this.vlist[4], this.vlist[5])); - this.vertices[this.count++] = (new THREE.Vector3(this.vlist[6], this.vlist[7], this.vlist[8])); - this.vertices[this.count++] = (new THREE.Vector3(this.vlist[9], this.vlist[10], this.vlist[11])); - return; - } - - if (s0 != 0 && s1 == 0 && s2 != 0 && s3 == 0) { - this.VIntX(this.vlist, 0, isol, fx, fy, fz, field0, field1); // s0 - this.VIntX(this.vlist, 3, isol, fx, fy, fz2, field2, field3); // s2 - } else if (s0 == 0 && s1 != 0 && s2 == 0 && s3 != 0) { - this.VIntZ(this.vlist, 0, isol, fx2, fy, fz, field1, field3); // s1 - this.VIntZ(this.vlist, 3, isol, fx, fy, fz, field0, field2); // s3 - } else if (s0 == 0 && s1 == 0 && s2 != 0 && s3 != 0) { - this.VIntX(this.vlist, 0, isol, fx, fy, fz2, field2, field3); // s2 - this.VIntZ(this.vlist, 3, isol, fx, fy, fz, field0, field2); // s3 - } else if (s0 == 0 && s1 != 0 && s2 != 0 && s3 == 0) { - this.VIntZ(this.vlist, 0, isol, fx2, fy, fz, field1, field3); // s1 - this.VIntX(this.vlist, 3, isol, fx, fy, fz2, field2, field3); // s2 - } else if (s0 != 0 && s1 != 0 && s2 == 0 && s3 == 0) { - this.VIntX(this.vlist, 0, isol, fx, fy, fz, field0, field1); // s0 - this.VIntZ(this.vlist, 3, isol, fx2, fy, fz, field1, field3); // s1 - } else if (s0 != 0 && s1 == 0 && s2 == 0 && s3 != 0) { - this.VIntX(this.vlist, 0, isol, fx, fy, fz, field0, field1); // s0 - this.VIntZ(this.vlist, 3, isol, fx, fy, fz, field0, field2); // s3 - } - - this.vertices[this.count++] = (new THREE.Vector3(this.vlist[0], this.vlist[1], this.vlist[2])); - this.vertices[this.count++] = (new THREE.Vector3(this.vlist[3], this.vlist[4], this.vlist[5])); - }; - - this.build = function(cc, cr, cs, radius) { - var q, x, y, z, y_offset, z_offset; - var xlo = cc - radius, xhi = cc + radius, - ylo = cr - radius, yhi = cr + radius, - zlo = cs - radius, zhi = cs + radius; - if (xlo < 0) xlo = 0; - if (ylo < 0) ylo = 0; - if (zlo < 0) zlo = 0; - if (xhi > nc - 2) xhi = nc - 2; - if (yhi > nr - 2) yhi = nr - 2; - if (zhi > ns - 2) zhi = ns - 2; - console.log('Mesh Range: ', xlo, xhi, ylo, yhi, zlo, zhi); - - for (z = zlo; z <= zhi ; z++) { - z_offset = this.size2 * z; - for (y = ylo; y <= yhi; y ++) { - y_offset = z_offset + this.size * y; - for (x = xlo; x <= xhi; x ++) { - q = y_offset + x; - this.polygonizeXY((x + ncstart), (y + nrstart), (z + nsstart), q, this.isol); - this.polygonizeYZ((x + ncstart), (y + nrstart), (z + nsstart), q, this.isol); - this.polygonizeXZ((x + ncstart), (y + nrstart), (z + nsstart), q, this.isol); - } - } - } - }; - - this.generateGeometry = function(cc, cr, cs, radius, isol) { - this.count = 0; - this.isol = isol; this.cc = cc; this.cr = cr, this.cs = cs; - var maxvert = 2500000, i = 0; - - this.vertices.length = maxvert; - this.build(cc, cr, cs, radius); - var dummy = new THREE.Vector3(0, 0, 0); - for (i = this.count; i < maxvert; i++) this.vertices[i] = dummy; - - // TODO: FIXME: if this.count > maxvert, Geometry object has to be rebuilded, - // since Three.js doesn't support changes of vertex counts. - this.geo.verticesNeedUpdate = true; - - return this.geo; - }; - - this.init(); -}; - diff --git a/client/src/js/vendor/Three49custom.js b/client/src/js/vendor/Three49custom.js deleted file mode 100644 index 01abdece7..000000000 --- a/client/src/js/vendor/Three49custom.js +++ /dev/null @@ -1,382 +0,0 @@ -// Three.js - http://github.com/mrdoob/three.js -'use strict';var THREE=THREE||{REVISION:"49"};self.Int32Array||(self.Int32Array=Array,self.Float32Array=Array); -(function(){for(var a=0,b=["ms","moz","webkit","o"],c=0;c>16&255)/255;this.g=(a>>8&255)/255;this.b=(a&255)/255;return this},lerpSelf:function(a,b){this.r=this.r+(a.r-this.r)*b;this.g=this.g+(a.g-this.g)*b;this.b=this.b+(a.b-this.b)*b;return this},getHex:function(){return Math.floor(this.r*255)<<16^Math.floor(this.g*255)<<8^Math.floor(this.b*255)},getContextStyle:function(){return"rgb("+Math.floor(this.r*255)+","+Math.floor(this.g*255)+","+Math.floor(this.b*255)+")"},clone:function(){return(new THREE.Color).setRGB(this.r,this.g,this.b)}}; -THREE.Vector2=function(a,b){this.x=a||0;this.y=b||0}; -THREE.Vector2.prototype={constructor:THREE.Vector2,set:function(a,b){this.x=a;this.y=b;return this},copy:function(a){this.x=a.x;this.y=a.y;return this},add:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;return this},addSelf:function(a){this.x=this.x+a.x;this.y=this.y+a.y;return this},sub:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;return this},subSelf:function(a){this.x=this.x-a.x;this.y=this.y-a.y;return this},multiplyScalar:function(a){this.x=this.x*a;this.y=this.y*a;return this},divideScalar:function(a){if(a){this.x= -this.x/a;this.y=this.y/a}else this.set(0,0);return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y},lengthSq:function(){return this.x*this.x+this.y*this.y},length:function(){return Math.sqrt(this.lengthSq())},normalize:function(){return this.divideScalar(this.length())},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,a=this.y-a.y;return b*b+a*a},setLength:function(a){return this.normalize().multiplyScalar(a)}, -lerpSelf:function(a,b){this.x=this.x+(a.x-this.x)*b;this.y=this.y+(a.y-this.y)*b;return this},equals:function(a){return a.x===this.x&&a.y===this.y},isZero:function(){return this.lengthSq()<1.0E-4},clone:function(){return new THREE.Vector2(this.x,this.y)}};THREE.Vector3=function(a,b,c){this.x=a||0;this.y=b||0;this.z=c||0}; -THREE.Vector3.prototype={constructor:THREE.Vector3,set:function(a,b,c){this.x=a;this.y=b;this.z=c;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this},add:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;return this},addSelf:function(a){this.x=this.x+a.x;this.y=this.y+a.y;this.z=this.z+a.z;return this},addScalar:function(a){this.x=this.x+a;this.y=this.y+ -a;this.z=this.z+a;return this},sub:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;return this},subSelf:function(a){this.x=this.x-a.x;this.y=this.y-a.y;this.z=this.z-a.z;return this},multiply:function(a,b){this.x=a.x*b.x;this.y=a.y*b.y;this.z=a.z*b.z;return this},multiplySelf:function(a){this.x=this.x*a.x;this.y=this.y*a.y;this.z=this.z*a.z;return this},multiplyScalar:function(a){this.x=this.x*a;this.y=this.y*a;this.z=this.z*a;return this},divideSelf:function(a){this.x=this.x/a.x;this.y= -this.y/a.y;this.z=this.z/a.z;return this},divideScalar:function(a){if(a){this.x=this.x/a;this.y=this.y/a;this.z=this.z/a}else this.z=this.y=this.x=0;return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z},length:function(){return Math.sqrt(this.lengthSq())},lengthManhattan:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)},normalize:function(){return this.divideScalar(this.length())}, -setLength:function(a){return this.normalize().multiplyScalar(a)},lerpSelf:function(a,b){this.x=this.x+(a.x-this.x)*b;this.y=this.y+(a.y-this.y)*b;this.z=this.z+(a.z-this.z)*b;return this},cross:function(a,b){this.x=a.y*b.z-a.z*b.y;this.y=a.z*b.x-a.x*b.z;this.z=a.x*b.y-a.y*b.x;return this},crossSelf:function(a){var b=this.x,c=this.y,d=this.z;this.x=c*a.z-d*a.y;this.y=d*a.x-b*a.z;this.z=b*a.y-c*a.x;return this},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){return(new THREE.Vector3).sub(this, -a).lengthSq()},getPositionFromMatrix:function(a){this.x=a.elements[12];this.y=a.elements[13];this.z=a.elements[14];return this},getRotationFromMatrix:function(a,b){var c=b?b.x:1,d=b?b.y:1,e=b?b.z:1,f=a.elements[0]/c,h=a.elements[4]/d,c=a.elements[1]/c,d=a.elements[5]/d,i=a.elements[9]/e,l=a.elements[10]/e;this.y=Math.asin(a.elements[8]/e);e=Math.cos(this.y);if(Math.abs(e)>1.0E-5){this.x=Math.atan2(-i/e,l/e);this.z=Math.atan2(-h/e,f/e)}else{this.x=0;this.z=Math.atan2(c,d)}return this},getScaleFromMatrix:function(a){var b= -this.set(a.elements[0],a.elements[1],a.elements[2]).length(),c=this.set(a.elements[4],a.elements[5],a.elements[6]).length(),a=this.set(a.elements[8],a.elements[9],a.elements[10]).length();this.x=b;this.y=c;this.z=a},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z},isZero:function(){return this.lengthSq()<1.0E-4},clone:function(){return new THREE.Vector3(this.x,this.y,this.z)}};THREE.Vector4=function(a,b,c,d){this.x=a||0;this.y=b||0;this.z=c||0;this.w=d!==void 0?d:1}; -THREE.Vector4.prototype={constructor:THREE.Vector4,set:function(a,b,c,d){this.x=a;this.y=b;this.z=c;this.w=d;return this},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=a.w!==void 0?a.w:1;return this},add:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;this.w=a.w+b.w;return this},addSelf:function(a){this.x=this.x+a.x;this.y=this.y+a.y;this.z=this.z+a.z;this.w=this.w+a.w;return this},sub:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;this.w=a.w-b.w;return this},subSelf:function(a){this.x= -this.x-a.x;this.y=this.y-a.y;this.z=this.z-a.z;this.w=this.w-a.w;return this},multiplyScalar:function(a){this.x=this.x*a;this.y=this.y*a;this.z=this.z*a;this.w=this.w*a;return this},divideScalar:function(a){if(a){this.x=this.x/a;this.y=this.y/a;this.z=this.z/a;this.w=this.w/a}else{this.z=this.y=this.x=0;this.w=1}return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z+this.w*a.w},lengthSq:function(){return this.dot(this)},length:function(){return Math.sqrt(this.lengthSq())}, -normalize:function(){return this.divideScalar(this.length())},setLength:function(a){return this.normalize().multiplyScalar(a)},lerpSelf:function(a,b){this.x=this.x+(a.x-this.x)*b;this.y=this.y+(a.y-this.y)*b;this.z=this.z+(a.z-this.z)*b;this.w=this.w+(a.w-this.w)*b;return this},clone:function(){return new THREE.Vector4(this.x,this.y,this.z,this.w)}};THREE.Frustum=function(){this.planes=[new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4]}; -THREE.Frustum.prototype.setFromMatrix=function(a){var b,c=this.planes,d=a.elements,a=d[0];b=d[1];var e=d[2],f=d[3],h=d[4],i=d[5],l=d[6],k=d[7],j=d[8],m=d[9],n=d[10],o=d[11],s=d[12],p=d[13],q=d[14],d=d[15];c[0].set(f-a,k-h,o-j,d-s);c[1].set(f+a,k+h,o+j,d+s);c[2].set(f+b,k+i,o+m,d+p);c[3].set(f-b,k-i,o-m,d-p);c[4].set(f-e,k-l,o-n,d-q);c[5].set(f+e,k+l,o+n,d+q);for(a=0;a<6;a++){b=c[a];b.divideScalar(Math.sqrt(b.x*b.x+b.y*b.y+b.z*b.z))}}; -THREE.Frustum.prototype.contains=function(a){for(var b=this.planes,c=a.matrixWorld,d=c.elements,c=-a.geometry.boundingSphere.radius*c.getMaxScaleOnAxis(),e=0;e<6;e++){a=b[e].x*d[12]+b[e].y*d[13]+b[e].z*d[14]+b[e].w;if(a<=c)return false}return true};THREE.Frustum.__v1=new THREE.Vector3; -THREE.Ray=function(a,b){function c(a,b,c){s.sub(c,a);w=s.dot(b);A=p.add(a,q.copy(b).multiplyScalar(w));return y=c.distanceTo(A)}function d(a,b,c,d){s.sub(d,b);p.sub(c,b);q.sub(a,b);u=s.dot(s);H=s.dot(p);B=s.dot(q);K=p.dot(p);N=p.dot(q);Y=1/(u*K-H*H);ca=(K*B-H*N)*Y;I=(u*N-H*B)*Y;return ca>=0&&I>=0&&ca+I<1}this.origin=a||new THREE.Vector3;this.direction=b||new THREE.Vector3;var e=1.0E-4;this.setPrecision=function(a){e=a};var f=new THREE.Vector3,h=new THREE.Vector3,i=new THREE.Vector3,l=new THREE.Vector3, -k=new THREE.Vector3,j=new THREE.Vector3,m=new THREE.Vector3,n=new THREE.Vector3,o=new THREE.Vector3;this.intersectObject=function(a){var b,s=[];if(a instanceof THREE.Particle){var p=c(this.origin,this.direction,a.matrixWorld.getPosition());if(p>a.scale.x)return[];b={distance:p,point:a.position,face:null,object:a};s.push(b)}else if(a instanceof THREE.Mesh){var p=c(this.origin,this.direction,a.matrixWorld.getPosition()),g=THREE.Frustum.__v1.set(a.matrixWorld.getColumnX().length(),a.matrixWorld.getColumnY().length(), -a.matrixWorld.getColumnZ().length());if(p>a.geometry.boundingSphere.radius*Math.max(g.x,Math.max(g.y,g.z)))return s;var q,u,y=a.geometry,w=y.vertices,A;a.matrixRotationWorld.extractRotation(a.matrixWorld);p=0;for(g=y.faces.length;p0:q<0))){o.add(k,j.multiplyScalar(u));if(b instanceof THREE.Face3){f=A.multiplyVector3(f.copy(w[b.a]));h=A.multiplyVector3(h.copy(w[b.b]));i=A.multiplyVector3(i.copy(w[b.c]));if(d(o,f,h,i)){b={distance:k.distanceTo(o),point:o.clone(),face:b,object:a};s.push(b)}}else if(b instanceof THREE.Face4){f=A.multiplyVector3(f.copy(w[b.a]));h=A.multiplyVector3(h.copy(w[b.b]));i=A.multiplyVector3(i.copy(w[b.c]));l=A.multiplyVector3(l.copy(w[b.d]));if(d(o,f,h,l)||d(o,h,i,l)){b={distance:k.distanceTo(o),point:o.clone(), -face:b,object:a};s.push(b)}}}}}}return s};this.intersectObjects=function(a){for(var b=[],c=0,d=a.length;cf?d:f;e=e>h? -e:h}a()};this.add3Points=function(f,h,j,m,n,o){if(i){i=false;b=fj?f>n?f:n:j>n?j:n;e=h>m?h>o?h:o:m>o?m:o}else{b=fj?f>n?f>d?f:d:n>d?n:d:j>n?j>d?j:d:n>d?n:d;e=h>m?h>o?h>e?h:e:o>e?o:e:m>o?m>e?m:e:o>e?o:e}a()};this.addRectangle=function(f){if(i){i=false;b=f.getLeft();c=f.getTop();d=f.getRight();e=f.getBottom()}else{b=bf.getRight()?d:f.getRight();e=e>f.getBottom()?e:f.getBottom()}a()};this.inflate=function(f){b=b-f;c=c-f;d=d+f;e=e+f;a()};this.minSelf=function(f){b=b>f.getLeft()?b:f.getLeft();c=c>f.getTop()?c:f.getTop();d=da.getRight()||ea.getBottom()?false:true};this.empty=function(){i=true;e=d=c=b=0;a()};this.isEmpty=function(){return i}}; -THREE.Math={clamp:function(a,b,c){return ac?c:a},clampBottom:function(a,b){return a0?1:0}};THREE.Matrix3=function(){this.elements=new Float32Array(9)}; -THREE.Matrix3.prototype={constructor:THREE.Matrix3,getInverse:function(a){var b=a.elements,a=b[10]*b[5]-b[6]*b[9],c=-b[10]*b[1]+b[2]*b[9],d=b[6]*b[1]-b[2]*b[5],e=-b[10]*b[4]+b[6]*b[8],f=b[10]*b[0]-b[2]*b[8],h=-b[6]*b[0]+b[2]*b[4],i=b[9]*b[4]-b[5]*b[8],l=-b[9]*b[0]+b[1]*b[8],k=b[5]*b[0]-b[1]*b[4],b=b[0]*a+b[1]*e+b[2]*i;b===0&&console.warn("Matrix3.getInverse(): determinant == 0");var b=1/b,j=this.elements;j[0]=b*a;j[1]=b*c;j[2]=b*d;j[3]=b*e;j[4]=b*f;j[5]=b*h;j[6]=b*i;j[7]=b*l;j[8]=b*k;return this}, -transpose:function(){var a,b=this.elements;a=b[1];b[1]=b[3];b[3]=a;a=b[2];b[2]=b[6];b[6]=a;a=b[5];b[5]=b[7];b[7]=a;return this},transposeIntoArray:function(a){var b=this.m;a[0]=b[0];a[1]=b[3];a[2]=b[6];a[3]=b[1];a[4]=b[4];a[5]=b[7];a[6]=b[2];a[7]=b[5];a[8]=b[8];return this}};THREE.Matrix4=function(a,b,c,d,e,f,h,i,l,k,j,m,n,o,s,p){this.elements=new Float32Array(16);this.set(a!==void 0?a:1,b||0,c||0,d||0,e||0,f!==void 0?f:1,h||0,i||0,l||0,k||0,j!==void 0?j:1,m||0,n||0,o||0,s||0,p!==void 0?p:1)}; -THREE.Matrix4.prototype={constructor:THREE.Matrix4,set:function(a,b,c,d,e,f,h,i,l,k,j,m,n,o,s,p){var q=this.elements;q[0]=a;q[4]=b;q[8]=c;q[12]=d;q[1]=e;q[5]=f;q[9]=h;q[13]=i;q[2]=l;q[6]=k;q[10]=j;q[14]=m;q[3]=n;q[7]=o;q[11]=s;q[15]=p;return this},identity:function(){this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);return this},copy:function(a){a=a.elements;this.set(a[0],a[4],a[8],a[12],a[1],a[5],a[9],a[13],a[2],a[6],a[10],a[14],a[3],a[7],a[11],a[15]);return this},lookAt:function(a,b,c){var d=this.elements, -e=THREE.Matrix4.__v1,f=THREE.Matrix4.__v2,h=THREE.Matrix4.__v3;h.sub(a,b).normalize();if(h.length()===0)h.z=1;e.cross(c,h).normalize();if(e.length()===0){h.x=h.x+1.0E-4;e.cross(c,h).normalize()}f.cross(h,e);d[0]=e.x;d[4]=f.x;d[8]=h.x;d[1]=e.y;d[5]=f.y;d[9]=h.y;d[2]=e.z;d[6]=f.z;d[10]=h.z;return this},multiply:function(a,b){var c=a.elements,d=b.elements,e=this.elements,f=c[0],h=c[4],i=c[8],l=c[12],k=c[1],j=c[5],m=c[9],n=c[13],o=c[2],s=c[6],p=c[10],q=c[14],w=c[3],A=c[7],y=c[11],c=c[15],u=d[0],H=d[4], -B=d[8],K=d[12],N=d[1],Y=d[5],ca=d[9],I=d[13],ba=d[2],ja=d[6],ya=d[10],D=d[14],g=d[3],Na=d[7],za=d[11],d=d[15];e[0]=f*u+h*N+i*ba+l*g;e[4]=f*H+h*Y+i*ja+l*Na;e[8]=f*B+h*ca+i*ya+l*za;e[12]=f*K+h*I+i*D+l*d;e[1]=k*u+j*N+m*ba+n*g;e[5]=k*H+j*Y+m*ja+n*Na;e[9]=k*B+j*ca+m*ya+n*za;e[13]=k*K+j*I+m*D+n*d;e[2]=o*u+s*N+p*ba+q*g;e[6]=o*H+s*Y+p*ja+q*Na;e[10]=o*B+s*ca+p*ya+q*za;e[14]=o*K+s*I+p*D+q*d;e[3]=w*u+A*N+y*ba+c*g;e[7]=w*H+A*Y+y*ja+c*Na;e[11]=w*B+A*ca+y*ya+c*za;e[15]=w*K+A*I+y*D+c*d;return this},multiplySelf:function(a){return this.multiply(this, -a)},multiplyToArray:function(a,b,c){var d=this.elements;this.multiply(a,b);c[0]=d[0];c[1]=d[1];c[2]=d[2];c[3]=d[3];c[4]=d[4];c[5]=d[5];c[6]=d[6];c[7]=d[7];c[8]=d[8];c[9]=d[9];c[10]=d[10];c[11]=d[11];c[12]=d[12];c[13]=d[13];c[14]=d[14];c[15]=d[15];return this},multiplyScalar:function(a){var b=this.elements;b[0]=b[0]*a;b[4]=b[4]*a;b[8]=b[8]*a;b[12]=b[12]*a;b[1]=b[1]*a;b[5]=b[5]*a;b[9]=b[9]*a;b[13]=b[13]*a;b[2]=b[2]*a;b[6]=b[6]*a;b[10]=b[10]*a;b[14]=b[14]*a;b[3]=b[3]*a;b[7]=b[7]*a;b[11]=b[11]*a;b[15]= -b[15]*a;return this},multiplyVector3:function(a){var b=this.elements,c=a.x,d=a.y,e=a.z,f=1/(b[3]*c+b[7]*d+b[11]*e+b[15]);a.x=(b[0]*c+b[4]*d+b[8]*e+b[12])*f;a.y=(b[1]*c+b[5]*d+b[9]*e+b[13])*f;a.z=(b[2]*c+b[6]*d+b[10]*e+b[14])*f;return a},multiplyVector4:function(a){var b=this.elements,c=a.x,d=a.y,e=a.z,f=a.w;a.x=b[0]*c+b[4]*d+b[8]*e+b[12]*f;a.y=b[1]*c+b[5]*d+b[9]*e+b[13]*f;a.z=b[2]*c+b[6]*d+b[10]*e+b[14]*f;a.w=b[3]*c+b[7]*d+b[11]*e+b[15]*f;return a},rotateAxis:function(a){var b=this.elements,c=a.x, -d=a.y,e=a.z;a.x=c*b[0]+d*b[4]+e*b[8];a.y=c*b[1]+d*b[5]+e*b[9];a.z=c*b[2]+d*b[6]+e*b[10];a.normalize();return a},crossVector:function(a){var b=this.elements,c=new THREE.Vector4;c.x=b[0]*a.x+b[4]*a.y+b[8]*a.z+b[12]*a.w;c.y=b[1]*a.x+b[5]*a.y+b[9]*a.z+b[13]*a.w;c.z=b[2]*a.x+b[6]*a.y+b[10]*a.z+b[14]*a.w;c.w=a.w?b[3]*a.x+b[7]*a.y+b[11]*a.z+b[15]*a.w:1;return c},determinant:function(){var a=this.elements,b=a[0],c=a[4],d=a[8],e=a[12],f=a[1],h=a[5],i=a[9],l=a[13],k=a[2],j=a[6],m=a[10],n=a[14],o=a[3],s=a[7], -p=a[11],a=a[15];return e*i*j*o-d*l*j*o-e*h*m*o+c*l*m*o+d*h*n*o-c*i*n*o-e*i*k*s+d*l*k*s+e*f*m*s-b*l*m*s-d*f*n*s+b*i*n*s+e*h*k*p-c*l*k*p-e*f*j*p+b*l*j*p+c*f*n*p-b*h*n*p-d*h*k*a+c*i*k*a+d*f*j*a-b*i*j*a-c*f*m*a+b*h*m*a},transpose:function(){var a=this.elements,b;b=a[1];a[1]=a[4];a[4]=b;b=a[2];a[2]=a[8];a[8]=b;b=a[6];a[6]=a[9];a[9]=b;b=a[3];a[3]=a[12];a[12]=b;b=a[7];a[7]=a[13];a[13]=b;b=a[11];a[11]=a[14];a[14]=b;return this},flattenToArray:function(a){var b=this.elements;a[0]=b[0];a[1]=b[1];a[2]=b[2]; -a[3]=b[3];a[4]=b[4];a[5]=b[5];a[6]=b[6];a[7]=b[7];a[8]=b[8];a[9]=b[9];a[10]=b[10];a[11]=b[11];a[12]=b[12];a[13]=b[13];a[14]=b[14];a[15]=b[15];return a},flattenToArrayOffset:function(a,b){var c=this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4];a[b+5]=c[5];a[b+6]=c[6];a[b+7]=c[7];a[b+8]=c[8];a[b+9]=c[9];a[b+10]=c[10];a[b+11]=c[11];a[b+12]=c[12];a[b+13]=c[13];a[b+14]=c[14];a[b+15]=c[15];return a},getPosition:function(){var a=this.elements;return THREE.Matrix4.__v1.set(a[12],a[13], -a[14])},setPosition:function(a){var b=this.elements;b[12]=a.x;b[13]=a.y;b[14]=a.z;return this},getColumnX:function(){var a=this.elements;return THREE.Matrix4.__v1.set(a[0],a[1],a[2])},getColumnY:function(){var a=this.elements;return THREE.Matrix4.__v1.set(a[4],a[5],a[6])},getColumnZ:function(){var a=this.elements;return THREE.Matrix4.__v1.set(a[8],a[9],a[10])},getInverse:function(a){var b=this.elements,c=a.elements,d=c[0],e=c[4],f=c[8],h=c[12],i=c[1],l=c[5],k=c[9],j=c[13],m=c[2],n=c[6],o=c[10],s= -c[14],p=c[3],q=c[7],w=c[11],c=c[15];b[0]=k*s*q-j*o*q+j*n*w-l*s*w-k*n*c+l*o*c;b[4]=h*o*q-f*s*q-h*n*w+e*s*w+f*n*c-e*o*c;b[8]=f*j*q-h*k*q+h*l*w-e*j*w-f*l*c+e*k*c;b[12]=h*k*n-f*j*n-h*l*o+e*j*o+f*l*s-e*k*s;b[1]=j*o*p-k*s*p-j*m*w+i*s*w+k*m*c-i*o*c;b[5]=f*s*p-h*o*p+h*m*w-d*s*w-f*m*c+d*o*c;b[9]=h*k*p-f*j*p-h*i*w+d*j*w+f*i*c-d*k*c;b[13]=f*j*m-h*k*m+h*i*o-d*j*o-f*i*s+d*k*s;b[2]=l*s*p-j*n*p+j*m*q-i*s*q-l*m*c+i*n*c;b[6]=h*n*p-e*s*p-h*m*q+d*s*q+e*m*c-d*n*c;b[10]=e*j*p-h*l*p+h*i*q-d*j*q-e*i*c+d*l*c;b[14]=h*l*m- -e*j*m-h*i*n+d*j*n+e*i*s-d*l*s;b[3]=k*n*p-l*o*p-k*m*q+i*o*q+l*m*w-i*n*w;b[7]=e*o*p-f*n*p+f*m*q-d*o*q-e*m*w+d*n*w;b[11]=f*l*p-e*k*p-f*i*q+d*k*q+e*i*w-d*l*w;b[15]=e*k*m-f*l*m+f*i*n-d*k*n-e*i*o+d*l*o;this.multiplyScalar(1/a.determinant());return this},setRotationFromEuler:function(a,b){var c=this.elements,d=a.x,e=a.y,f=a.z,h=Math.cos(d),d=Math.sin(d),i=Math.cos(e),e=Math.sin(e),l=Math.cos(f),f=Math.sin(f);switch(b){case "YXZ":var k=i*l,j=i*f,m=e*l,n=e*f;c[0]=k+n*d;c[4]=m*d-j;c[8]=h*e;c[1]=h*f;c[5]=h* -l;c[9]=-d;c[2]=j*d-m;c[6]=n+k*d;c[10]=h*i;break;case "ZXY":k=i*l;j=i*f;m=e*l;n=e*f;c[0]=k-n*d;c[4]=-h*f;c[8]=m+j*d;c[1]=j+m*d;c[5]=h*l;c[9]=n-k*d;c[2]=-h*e;c[6]=d;c[10]=h*i;break;case "ZYX":k=h*l;j=h*f;m=d*l;n=d*f;c[0]=i*l;c[4]=m*e-j;c[8]=k*e+n;c[1]=i*f;c[5]=n*e+k;c[9]=j*e-m;c[2]=-e;c[6]=d*i;c[10]=h*i;break;case "YZX":k=h*i;j=h*e;m=d*i;n=d*e;c[0]=i*l;c[4]=n-k*f;c[8]=m*f+j;c[1]=f;c[5]=h*l;c[9]=-d*l;c[2]=-e*l;c[6]=j*f+m;c[10]=k-n*f;break;case "XZY":k=h*i;j=h*e;m=d*i;n=d*e;c[0]=i*l;c[4]=-f;c[8]=e*l; -c[1]=k*f+n;c[5]=h*l;c[9]=j*f-m;c[2]=m*f-j;c[6]=d*l;c[10]=n*f+k;break;default:k=h*l;j=h*f;m=d*l;n=d*f;c[0]=i*l;c[4]=-i*f;c[8]=e;c[1]=j+m*e;c[5]=k-n*e;c[9]=-d*i;c[2]=n-k*e;c[6]=m+j*e;c[10]=h*i}return this},setRotationFromQuaternion:function(a){var b=this.elements,c=a.x,d=a.y,e=a.z,f=a.w,h=c+c,i=d+d,l=e+e,a=c*h,k=c*i,c=c*l,j=d*i,d=d*l,e=e*l,h=f*h,i=f*i,f=f*l;b[0]=1-(j+e);b[4]=k-f;b[8]=c+i;b[1]=k+f;b[5]=1-(a+e);b[9]=d-h;b[2]=c-i;b[6]=d+h;b[10]=1-(a+j);return this},compose:function(a,b,c){var d=this.elements, -e=THREE.Matrix4.__m1,f=THREE.Matrix4.__m2;e.identity();e.setRotationFromQuaternion(b);f.makeScale(c.x,c.y,c.z);this.multiply(e,f);d[12]=a.x;d[13]=a.y;d[14]=a.z;return this},decompose:function(a,b,c){var d=this.elements,e=THREE.Matrix4.__v1,f=THREE.Matrix4.__v2,h=THREE.Matrix4.__v3;e.set(d[0],d[1],d[2]);f.set(d[4],d[5],d[6]);h.set(d[8],d[9],d[10]);a=a instanceof THREE.Vector3?a:new THREE.Vector3;b=b instanceof THREE.Quaternion?b:new THREE.Quaternion;c=c instanceof THREE.Vector3?c:new THREE.Vector3; -c.x=e.length();c.y=f.length();c.z=h.length();a.x=d[12];a.y=d[13];a.z=d[14];d=THREE.Matrix4.__m1;d.copy(this);d.elements[0]=d.elements[0]/c.x;d.elements[1]=d.elements[1]/c.x;d.elements[2]=d.elements[2]/c.x;d.elements[4]=d.elements[4]/c.y;d.elements[5]=d.elements[5]/c.y;d.elements[6]=d.elements[6]/c.y;d.elements[8]=d.elements[8]/c.z;d.elements[9]=d.elements[9]/c.z;d.elements[10]=d.elements[10]/c.z;b.setFromRotationMatrix(d);return[a,b,c]},extractPosition:function(a){var b=this.elements,a=a.elements; -b[12]=a[12];b[13]=a[13];b[14]=a[14];return this},extractRotation:function(a){var b=this.elements,a=a.elements,c=THREE.Matrix4.__v1,d=1/c.set(a[0],a[1],a[2]).length(),e=1/c.set(a[4],a[5],a[6]).length(),c=1/c.set(a[8],a[9],a[10]).length();b[0]=a[0]*d;b[1]=a[1]*d;b[2]=a[2]*d;b[4]=a[4]*e;b[5]=a[5]*e;b[6]=a[6]*e;b[8]=a[8]*c;b[9]=a[9]*c;b[10]=a[10]*c;return this},translate:function(a){var b=this.elements,c=a.x,d=a.y,a=a.z;b[12]=b[0]*c+b[4]*d+b[8]*a+b[12];b[13]=b[1]*c+b[5]*d+b[9]*a+b[13];b[14]=b[2]*c+b[6]* -d+b[10]*a+b[14];b[15]=b[3]*c+b[7]*d+b[11]*a+b[15];return this},rotateX:function(a){var b=this.elements,c=b[4],d=b[5],e=b[6],f=b[7],h=b[8],i=b[9],l=b[10],k=b[11],j=Math.cos(a),a=Math.sin(a);b[4]=j*c+a*h;b[5]=j*d+a*i;b[6]=j*e+a*l;b[7]=j*f+a*k;b[8]=j*h-a*c;b[9]=j*i-a*d;b[10]=j*l-a*e;b[11]=j*k-a*f;return this},rotateY:function(a){var b=this.elements,c=b[0],d=b[1],e=b[2],f=b[3],h=b[8],i=b[9],l=b[10],k=b[11],j=Math.cos(a),a=Math.sin(a);b[0]=j*c-a*h;b[1]=j*d-a*i;b[2]=j*e-a*l;b[3]=j*f-a*k;b[8]=j*h+a*c;b[9]= -j*i+a*d;b[10]=j*l+a*e;b[11]=j*k+a*f;return this},rotateZ:function(a){var b=this.elements,c=b[0],d=b[1],e=b[2],f=b[3],h=b[4],i=b[5],l=b[6],k=b[7],j=Math.cos(a),a=Math.sin(a);b[0]=j*c+a*h;b[1]=j*d+a*i;b[2]=j*e+a*l;b[3]=j*f+a*k;b[4]=j*h-a*c;b[5]=j*i-a*d;b[6]=j*l-a*e;b[7]=j*k-a*f;return this},rotateByAxis:function(a,b){var c=this.elements;if(a.x===1&&a.y===0&&a.z===0)return this.rotateX(b);if(a.x===0&&a.y===1&&a.z===0)return this.rotateY(b);if(a.x===0&&a.y===0&&a.z===1)return this.rotateZ(b);var d=a.x, -e=a.y,f=a.z,h=Math.sqrt(d*d+e*e+f*f),d=d/h,e=e/h,f=f/h,h=d*d,i=e*e,l=f*f,k=Math.cos(b),j=Math.sin(b),m=1-k,n=d*e*m,o=d*f*m,m=e*f*m,d=d*j,s=e*j,j=f*j,f=h+(1-h)*k,h=n+j,e=o-s,n=n-j,i=i+(1-i)*k,j=m+d,o=o+s,m=m-d,l=l+(1-l)*k,k=c[0],d=c[1],s=c[2],p=c[3],q=c[4],w=c[5],A=c[6],y=c[7],u=c[8],H=c[9],B=c[10],K=c[11];c[0]=f*k+h*q+e*u;c[1]=f*d+h*w+e*H;c[2]=f*s+h*A+e*B;c[3]=f*p+h*y+e*K;c[4]=n*k+i*q+j*u;c[5]=n*d+i*w+j*H;c[6]=n*s+i*A+j*B;c[7]=n*p+i*y+j*K;c[8]=o*k+m*q+l*u;c[9]=o*d+m*w+l*H;c[10]=o*s+m*A+l*B;c[11]= -o*p+m*y+l*K;return this},scale:function(a){var b=this.elements,c=a.x,d=a.y,a=a.z;b[0]=b[0]*c;b[4]=b[4]*d;b[8]=b[8]*a;b[1]=b[1]*c;b[5]=b[5]*d;b[9]=b[9]*a;b[2]=b[2]*c;b[6]=b[6]*d;b[10]=b[10]*a;b[3]=b[3]*c;b[7]=b[7]*d;b[11]=b[11]*a;return this},getMaxScaleOnAxis:function(){var a=this.elements;return Math.sqrt(Math.max(a[0]*a[0]+a[1]*a[1]+a[2]*a[2],Math.max(a[4]*a[4]+a[5]*a[5]+a[6]*a[6],a[8]*a[8]+a[9]*a[9]+a[10]*a[10])))},makeTranslation:function(a,b,c){this.set(1,0,0,a,0,1,0,b,0,0,1,c,0,0,0,1);return this}, -makeRotationX:function(a){var b=Math.cos(a),a=Math.sin(a);this.set(1,0,0,0,0,b,-a,0,0,a,b,0,0,0,0,1);return this},makeRotationY:function(a){var b=Math.cos(a),a=Math.sin(a);this.set(b,0,a,0,0,1,0,0,-a,0,b,0,0,0,0,1);return this},makeRotationZ:function(a){var b=Math.cos(a),a=Math.sin(a);this.set(b,-a,0,0,a,b,0,0,0,0,1,0,0,0,0,1);return this},makeRotationAxis:function(a,b){var c=Math.cos(b),d=Math.sin(b),e=1-c,f=a.x,h=a.y,i=a.z,l=e*f,k=e*h;this.set(l*f+c,l*h-d*i,l*i+d*h,0,l*h+d*i,k*h+c,k*i-d*f,0,l*i- -d*h,k*i+d*f,e*i*i+c,0,0,0,0,1);return this},makeScale:function(a,b,c){this.set(a,0,0,0,0,b,0,0,0,0,c,0,0,0,0,1);return this},makeFrustum:function(a,b,c,d,e,f){var h=this.elements;h[0]=2*e/(b-a);h[4]=0;h[8]=(b+a)/(b-a);h[12]=0;h[1]=0;h[5]=2*e/(d-c);h[9]=(d+c)/(d-c);h[13]=0;h[2]=0;h[6]=0;h[10]=-(f+e)/(f-e);h[14]=-2*f*e/(f-e);h[3]=0;h[7]=0;h[11]=-1;h[15]=0;return this},makePerspective:function(a,b,c,d){var a=c*Math.tan(a*Math.PI/360),e=-a;return this.makeFrustum(e*b,a*b,e,a,c,d)},makeOrthographic:function(a, -b,c,d,e,f){var h=this.elements,i=b-a,l=c-d,k=f-e;h[0]=2/i;h[4]=0;h[8]=0;h[12]=-((b+a)/i);h[1]=0;h[5]=2/l;h[9]=0;h[13]=-((c+d)/l);h[2]=0;h[6]=0;h[10]=-2/k;h[14]=-((f+e)/k);h[3]=0;h[7]=0;h[11]=0;h[15]=1;return this},clone:function(){var a=this.elements;return new THREE.Matrix4(a[0],a[4],a[8],a[12],a[1],a[5],a[9],a[13],a[2],a[6],a[10],a[14],a[3],a[7],a[11],a[15])}};THREE.Matrix4.__v1=new THREE.Vector3;THREE.Matrix4.__v2=new THREE.Vector3;THREE.Matrix4.__v3=new THREE.Vector3;THREE.Matrix4.__m1=new THREE.Matrix4; -THREE.Matrix4.__m2=new THREE.Matrix4; -THREE.Object3D=function(){this.id=THREE.Object3DCount++;this.name="";this.parent=void 0;this.children=[];this.up=new THREE.Vector3(0,1,0);this.position=new THREE.Vector3;this.rotation=new THREE.Vector3;this.eulerOrder="XYZ";this.scale=new THREE.Vector3(1,1,1);this.flipSided=this.doubleSided=false;this.renderDepth=null;this.rotationAutoUpdate=true;this.matrix=new THREE.Matrix4;this.matrixWorld=new THREE.Matrix4;this.matrixRotationWorld=new THREE.Matrix4;this.matrixWorldNeedsUpdate=this.matrixAutoUpdate= -true;this.quaternion=new THREE.Quaternion;this.useQuaternion=false;this.boundRadius=0;this.boundRadiusScale=1;this.visible=true;this.receiveShadow=this.castShadow=false;this.frustumCulled=true;this._vector=new THREE.Vector3}; -THREE.Object3D.prototype={constructor:THREE.Object3D,applyMatrix:function(a){this.matrix.multiply(a,this.matrix);this.scale.getScaleFromMatrix(this.matrix);this.rotation.getRotationFromMatrix(this.matrix,this.scale);this.position.getPositionFromMatrix(this.matrix)},translate:function(a,b){this.matrix.rotateAxis(b);this.position.addSelf(b.multiplyScalar(a))},translateX:function(a){this.translate(a,this._vector.set(1,0,0))},translateY:function(a){this.translate(a,this._vector.set(0,1,0))},translateZ:function(a){this.translate(a, -this._vector.set(0,0,1))},lookAt:function(a){this.matrix.lookAt(a,this.position,this.up);this.rotationAutoUpdate&&this.rotation.getRotationFromMatrix(this.matrix)},add:function(a){if(a===this)console.warn("THREE.Object3D.add: An object can't be added as a child of itself.");else if(a instanceof THREE.Object3D){a.parent!==void 0&&a.parent.remove(a);a.parent=this;this.children.push(a);for(var b=this;b.parent!==void 0;)b=b.parent;b!==void 0&&b instanceof THREE.Scene&&b.__addObject(a)}},remove:function(a){var b= -this.children.indexOf(a);if(b!==-1){a.parent=void 0;this.children.splice(b,1);for(b=this;b.parent!==void 0;)b=b.parent;b!==void 0&&b instanceof THREE.Scene&&b.__removeObject(a)}},getChildByName:function(a,b){var c,d,e;c=0;for(d=this.children.length;c=0&&e>=0&&f>=0&&h>=0)return true;if(g<0&&e<0||f<0&&h<0)return false;g<0?c=Math.max(c,g/(g-e)):e<0&&(d=Math.min(d,g/(g-e)));f<0?c=Math.max(c,f/(f-h)):h<0&&(d=Math.min(d,f/(f-h)));if(dD&&h.positionScreen.z0)){Z=l[i-2];ca.copy(J.positionScreen);I.copy(Z.positionScreen);if(c(ca,I)){ca.multiplyScalar(1/ca.w);I.multiplyScalar(1/I.w);Ha=q[p]=q[p]||new THREE.RenderableLine;p++;s=Ha;s.v1.positionScreen.copy(ca);s.v2.positionScreen.copy(I);s.z=Math.max(ca.z,I.z);s.material=O.material;u.elements.push(s)}}}}}d=0;for(za=u.sprites.length;d0&&B.z<1){D=y[A]=y[A]||new THREE.RenderableParticle;A++;w=D;w.x=B.x/B.w;w.y=B.y/B.w;w.z=B.z;w.rotation=O.rotation.z;w.scale.x=O.scale.x*Math.abs(w.x-(B.x+e.projectionMatrix.elements[0])/(B.w+e.projectionMatrix.elements[12]));w.scale.y=O.scale.y*Math.abs(w.y-(B.y+e.projectionMatrix.elements[5])/(B.w+e.projectionMatrix.elements[13]));w.material=O.material;u.elements.push(w)}}}f&&u.elements.sort(b);return u}}; -THREE.Quaternion=function(a,b,c,d){this.x=a||0;this.y=b||0;this.z=c||0;this.w=d!==void 0?d:1}; -THREE.Quaternion.prototype={constructor:THREE.Quaternion,set:function(a,b,c,d){this.x=a;this.y=b;this.z=c;this.w=d;return this},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=a.w;return this},setFromEuler:function(a){var b=Math.PI/360,c=a.x*b,d=a.y*b,e=a.z*b,a=Math.cos(d),d=Math.sin(d),b=Math.cos(-e),e=Math.sin(-e),f=Math.cos(c),c=Math.sin(c),h=a*b,i=d*e;this.w=h*f-i*c;this.x=h*c+i*f;this.y=d*b*f+a*e*c;this.z=a*e*f-d*b*c;return this},setFromAxisAngle:function(a,b){var c=b/2,d=Math.sin(c); -this.x=a.x*d;this.y=a.y*d;this.z=a.z*d;this.w=Math.cos(c);return this},setFromRotationMatrix:function(a){var b=Math.pow(a.determinant(),1/3);this.w=Math.sqrt(Math.max(0,b+a.elements[0]+a.elements[5]+a.elements[10]))/2;this.x=Math.sqrt(Math.max(0,b+a.elements[0]-a.elements[5]-a.elements[10]))/2;this.y=Math.sqrt(Math.max(0,b-a.elements[0]+a.elements[5]-a.elements[10]))/2;this.z=Math.sqrt(Math.max(0,b-a.elements[0]-a.elements[5]+a.elements[10]))/2;this.x=a.elements[6]-a.elements[9]<0?-Math.abs(this.x): -Math.abs(this.x);this.y=a.elements[8]-a.elements[2]<0?-Math.abs(this.y):Math.abs(this.y);this.z=a.elements[1]-a.elements[4]<0?-Math.abs(this.z):Math.abs(this.z);this.normalize();return this},calculateW:function(){this.w=-Math.sqrt(Math.abs(1-this.x*this.x-this.y*this.y-this.z*this.z));return this},inverse:function(){this.x=this.x*-1;this.y=this.y*-1;this.z=this.z*-1;return this},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)},normalize:function(){var a= -Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w);if(a===0)this.w=this.z=this.y=this.x=0;else{a=1/a;this.x=this.x*a;this.y=this.y*a;this.z=this.z*a;this.w=this.w*a}return this},multiply:function(a,b){this.x=a.x*b.w+a.y*b.z-a.z*b.y+a.w*b.x;this.y=-a.x*b.z+a.y*b.w+a.z*b.x+a.w*b.y;this.z=a.x*b.y-a.y*b.x+a.z*b.w+a.w*b.z;this.w=-a.x*b.x-a.y*b.y-a.z*b.z+a.w*b.w;return this},multiplySelf:function(a){var b=this.x,c=this.y,d=this.z,e=this.w,f=a.x,h=a.y,i=a.z,a=a.w;this.x=b*a+e*f+c*i-d*h;this.y= -c*a+e*h+d*f-b*i;this.z=d*a+e*i+b*h-c*f;this.w=e*a-b*f-c*h-d*i;return this},multiplyVector3:function(a,b){b||(b=a);var c=a.x,d=a.y,e=a.z,f=this.x,h=this.y,i=this.z,l=this.w,k=l*c+h*e-i*d,j=l*d+i*c-f*e,m=l*e+f*d-h*c,c=-f*c-h*d-i*e;b.x=k*l+c*-f+j*-i-m*-h;b.y=j*l+c*-h+m*-f-k*-i;b.z=m*l+c*-i+k*-h-j*-f;return b},clone:function(){return new THREE.Quaternion(this.x,this.y,this.z,this.w)}}; -THREE.Quaternion.slerp=function(a,b,c,d){var e=a.w*b.w+a.x*b.x+a.y*b.y+a.z*b.z;if(e<0){c.w=-b.w;c.x=-b.x;c.y=-b.y;c.z=-b.z;e=-e}else c.copy(b);if(Math.abs(e)>=1){c.w=a.w;c.x=a.x;c.y=a.y;c.z=a.z;return c}var f=Math.acos(e),e=Math.sqrt(1-e*e);if(Math.abs(e)<0.001){c.w=0.5*(a.w+b.w);c.x=0.5*(a.x+b.x);c.y=0.5*(a.y+b.y);c.z=0.5*(a.z+b.z);return c}b=Math.sin((1-d)*f)/e;d=Math.sin(d*f)/e;c.w=a.w*b+c.w*d;c.x=a.x*b+c.x*d;c.y=a.y*b+c.y*d;c.z=a.z*b+c.z*d;return c};THREE.Vertex=function(){console.warn("THREE.Vertex has been DEPRECATED. Use THREE.Vector3 instead.")}; -THREE.Face3=function(a,b,c,d,e,f){this.a=a;this.b=b;this.c=c;this.normal=d instanceof THREE.Vector3?d:new THREE.Vector3;this.vertexNormals=d instanceof Array?d:[];this.color=e instanceof THREE.Color?e:new THREE.Color;this.vertexColors=e instanceof Array?e:[];this.vertexTangents=[];this.materialIndex=f;this.centroid=new THREE.Vector3}; -THREE.Face3.prototype={constructor:THREE.Face3,clone:function(){var a=new THREE.Face3(this.a,this.b,this.c);a.normal.copy(this.normal);a.color.copy(this.color);a.centroid.copy(this.centroid);a.materialIndex=this.materialIndex;var b,c;b=0;for(c=this.vertexNormals.length;b0){var a;a=this.vertices[0];this.boundingBox.min.copy(a);this.boundingBox.max.copy(a);for(var b=this.boundingBox.min,c=this.boundingBox.max,d=1,e=this.vertices.length;d -c.x)c.x=a.x;if(a.yc.y)c.y=a.y;if(a.zc.z)c.z=a.z}}else{this.boundingBox.min.set(0,0,0);this.boundingBox.max.set(0,0,0)}},computeBoundingSphere:function(){if(!this.boundingSphere)this.boundingSphere={radius:0};for(var a,b=0,c=0,d=this.vertices.length;cb&&(b=a)}this.boundingSphere.radius=b},mergeVertices:function(){var a={},b=[],c=[],d,e=Math.pow(10,4),f,h,i;f=0;for(h=this.vertices.length;f0;a--)if(d.indexOf(e["abcd"[a]])!=a){d.splice(a,1);this.faces[f]=new THREE.Face3(d[0],d[1],d[2]);e=0;for(d=this.faceVertexUvs.length;e< -d;e++)(i=this.faceVertexUvs[e][f])&&i.splice(a,1);break}}}c=this.vertices.length-b.length;this.vertices=b;return c}};THREE.GeometryCount=0; -THREE.Spline=function(a){function b(a,b,c,d,e,f,h){a=(c-a)*0.5;d=(d-b)*0.5;return(2*(b-c)+a+d)*h+(-3*(b-c)-2*a-d)*f+a*e+b}this.points=a;var c=[],d={x:0,y:0,z:0},e,f,h,i,l,k,j,m,n;this.initFromArray=function(a){this.points=[];for(var b=0;bthis.points.length-2?this.points.length-1:f+1;c[3]=f>this.points.length-3?this.points.length-1: -f+2;k=this.points[c[0]];j=this.points[c[1]];m=this.points[c[2]];n=this.points[c[3]];i=h*h;l=h*i;d.x=b(k.x,j.x,m.x,n.x,h,i,l);d.y=b(k.y,j.y,m.y,n.y,h,i,l);d.z=b(k.z,j.z,m.z,n.z,h,i,l);return d};this.getControlPointsArray=function(){var a,b,c=this.points.length,d=[];for(a=0;a1){a.matrixWorldInverse.getInverse(a.matrixWorld);a=a.matrixWorldInverse;a=-(a.elements[2]*this.matrixWorld.elements[12]+a.elements[6]*this.matrixWorld.elements[13]+a.elements[10]*this.matrixWorld.elements[14]+a.elements[14]);this.LODs[0].object3D.visible=true;for(var b=1;b=this.LODs[b].visibleAtDistance){this.LODs[b-1].object3D.visible=false;this.LODs[b].object3D.visible=true}else break;for(;b 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\nuniform float spotLightAngle[ MAX_SPOT_LIGHTS ];\nuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif", -lights_lambert_vertex:"vLightFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\nvLightBack = vec3( 0.0 );\n#endif\ntransformedNormal = normalize( transformedNormal );\n#if MAX_DIR_LIGHTS > 0\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( transformedNormal, dirVector );\nvec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );\n#ifdef DOUBLE_SIDED\nvec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n#ifdef WRAP_AROUND\nvec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n#endif\n#endif\n#ifdef WRAP_AROUND\nvec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\ndirectionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );\n#ifdef DOUBLE_SIDED\ndirectionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );\n#endif\n#endif\nvLightFront += directionalLightColor[ i ] * directionalLightWeighting;\n#ifdef DOUBLE_SIDED\nvLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;\n#endif\n}\n#endif\n#if MAX_POINT_LIGHTS > 0\nfor( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\nfloat dotProduct = dot( transformedNormal, lVector );\nvec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );\n#ifdef DOUBLE_SIDED\nvec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n#ifdef WRAP_AROUND\nvec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n#endif\n#endif\n#ifdef WRAP_AROUND\nvec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\npointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );\n#ifdef DOUBLE_SIDED\npointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );\n#endif\n#endif\nvLightFront += pointLightColor[ i ] * pointLightWeighting * lDistance;\n#ifdef DOUBLE_SIDED\nvLightBack += pointLightColor[ i ] * pointLightWeightingBack * lDistance;\n#endif\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nfor( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nlVector = normalize( lVector );\nfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - mPosition.xyz ) );\nif ( spotEffect > spotLightAngle[ i ] ) {\nspotEffect = pow( spotEffect, spotLightExponent[ i ] );\nfloat lDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );\nfloat dotProduct = dot( transformedNormal, lVector );\nvec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );\n#ifdef DOUBLE_SIDED\nvec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n#ifdef WRAP_AROUND\nvec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n#endif\n#endif\n#ifdef WRAP_AROUND\nvec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\nspotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );\n#ifdef DOUBLE_SIDED\nspotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );\n#endif\n#endif\nvLightFront += spotLightColor[ i ] * spotLightWeighting * lDistance * spotEffect;\n#ifdef DOUBLE_SIDED\nvLightBack += spotLightColor[ i ] * spotLightWeightingBack * lDistance * spotEffect;\n#endif\n}\n}\n#endif\nvLightFront = vLightFront * diffuse + ambient * ambientLightColor + emissive;\n#ifdef DOUBLE_SIDED\nvLightBack = vLightBack * diffuse + ambient * ambientLightColor + emissive;\n#endif", -lights_phong_pars_vertex:"#ifndef PHONG_PER_PIXEL\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\nvarying vec4 vPointLight[ MAX_POINT_LIGHTS ];\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\nvarying vec4 vSpotLight[ MAX_SPOT_LIGHTS ];\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0\nvarying vec3 vWorldPosition;\n#endif",lights_phong_vertex:"#ifndef PHONG_PER_PIXEL\n#if MAX_POINT_LIGHTS > 0\nfor( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nvPointLight[ i ] = vec4( lVector, lDistance );\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nfor( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );\nvSpotLight[ i ] = vec4( lVector, lDistance );\n}\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0\nvWorldPosition = mPosition.xyz;\n#endif", -lights_phong_pars_fragment:"uniform vec3 ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n#ifdef PHONG_PER_PIXEL\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#else\nvarying vec4 vPointLight[ MAX_POINT_LIGHTS ];\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\nuniform float spotLightAngle[ MAX_SPOT_LIGHTS ];\nuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n#ifdef PHONG_PER_PIXEL\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n#else\nvarying vec4 vSpotLight[ MAX_SPOT_LIGHTS ];\n#endif\nvarying vec3 vWorldPosition;\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif\nvarying vec3 vViewPosition;\nvarying vec3 vNormal;", -lights_phong_fragment:"vec3 normal = normalize( vNormal );\nvec3 viewPosition = normalize( vViewPosition );\n#ifdef DOUBLE_SIDED\nnormal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n#endif\n#if MAX_POINT_LIGHTS > 0\nvec3 pointDiffuse = vec3( 0.0 );\nvec3 pointSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n#ifdef PHONG_PER_PIXEL\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz + vViewPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\n#else\nvec3 lVector = normalize( vPointLight[ i ].xyz );\nfloat lDistance = vPointLight[ i ].w;\n#endif\nfloat dotProduct = dot( normal, lVector );\n#ifdef WRAP_AROUND\nfloat pointDiffuseWeightFull = max( dotProduct, 0.0 );\nfloat pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\nvec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n#else\nfloat pointDiffuseWeight = max( dotProduct, 0.0 );\n#endif\npointDiffuse += diffuse * pointLightColor[ i ] * pointDiffuseWeight * lDistance;\nvec3 pointHalfVector = normalize( lVector + viewPosition );\nfloat pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\nfloat pointSpecularWeight = max( pow( pointDotNormalHalf, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, pointHalfVector ), 5.0 );\npointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance * specularNormalization;\n#else\npointSpecular += specular * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance;\n#endif\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nvec3 spotDiffuse = vec3( 0.0 );\nvec3 spotSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n#ifdef PHONG_PER_PIXEL\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz + vViewPosition.xyz;\nfloat lDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\n#else\nvec3 lVector = normalize( vSpotLight[ i ].xyz );\nfloat lDistance = vSpotLight[ i ].w;\n#endif\nfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );\nif ( spotEffect > spotLightAngle[ i ] ) {\nspotEffect = pow( spotEffect, spotLightExponent[ i ] );\nfloat dotProduct = dot( normal, lVector );\n#ifdef WRAP_AROUND\nfloat spotDiffuseWeightFull = max( dotProduct, 0.0 );\nfloat spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\nvec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );\n#else\nfloat spotDiffuseWeight = max( dotProduct, 0.0 );\n#endif\nspotDiffuse += diffuse * spotLightColor[ i ] * spotDiffuseWeight * lDistance * spotEffect;\nvec3 spotHalfVector = normalize( lVector + viewPosition );\nfloat spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );\nfloat spotSpecularWeight = max( pow( spotDotNormalHalf, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, spotHalfVector ), 5.0 );\nspotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * specularNormalization * spotEffect;\n#else\nspotSpecular += specular * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * spotEffect;\n#endif\n}\n}\n#endif\n#if MAX_DIR_LIGHTS > 0\nvec3 dirDiffuse = vec3( 0.0 );\nvec3 dirSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( normal, dirVector );\n#ifdef WRAP_AROUND\nfloat dirDiffuseWeightFull = max( dotProduct, 0.0 );\nfloat dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\nvec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );\n#else\nfloat dirDiffuseWeight = max( dotProduct, 0.0 );\n#endif\ndirDiffuse += diffuse * directionalLightColor[ i ] * dirDiffuseWeight;\nvec3 dirHalfVector = normalize( dirVector + viewPosition );\nfloat dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\nfloat dirSpecularWeight = max( pow( dirDotNormalHalf, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );\ndirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\n#else\ndirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight;\n#endif\n}\n#endif\nvec3 totalDiffuse = vec3( 0.0 );\nvec3 totalSpecular = vec3( 0.0 );\n#if MAX_DIR_LIGHTS > 0\ntotalDiffuse += dirDiffuse;\ntotalSpecular += dirSpecular;\n#endif\n#if MAX_POINT_LIGHTS > 0\ntotalDiffuse += pointDiffuse;\ntotalSpecular += pointSpecular;\n#endif\n#if MAX_SPOT_LIGHTS > 0\ntotalDiffuse += spotDiffuse;\ntotalSpecular += spotSpecular;\n#endif\n#ifdef METAL\ngl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient + totalSpecular );\n#else\ngl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient ) + totalSpecular;\n#endif", -color_pars_fragment:"#ifdef USE_COLOR\nvarying vec3 vColor;\n#endif",color_fragment:"#ifdef USE_COLOR\ngl_FragColor = gl_FragColor * vec4( vColor, opacity );\n#endif",color_pars_vertex:"#ifdef USE_COLOR\nvarying vec3 vColor;\n#endif",color_vertex:"#ifdef USE_COLOR\n#ifdef GAMMA_INPUT\nvColor = color * color;\n#else\nvColor = color;\n#endif\n#endif",skinning_pars_vertex:"#ifdef USE_SKINNING\nuniform mat4 boneGlobalMatrices[ MAX_BONES ];\n#endif",skinning_vertex:"#ifdef USE_SKINNING\ngl_Position = ( boneGlobalMatrices[ int( skinIndex.x ) ] * skinVertexA ) * skinWeight.x;\ngl_Position += ( boneGlobalMatrices[ int( skinIndex.y ) ] * skinVertexB ) * skinWeight.y;\ngl_Position = projectionMatrix * modelViewMatrix * gl_Position;\n#endif", -morphtarget_pars_vertex:"#ifdef USE_MORPHTARGETS\n#ifndef USE_MORPHNORMALS\nuniform float morphTargetInfluences[ 8 ];\n#else\nuniform float morphTargetInfluences[ 4 ];\n#endif\n#endif",morphtarget_vertex:"#ifdef USE_MORPHTARGETS\nvec3 morphed = vec3( 0.0 );\nmorphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\nmorphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\nmorphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\nmorphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n#ifndef USE_MORPHNORMALS\nmorphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\nmorphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\nmorphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\nmorphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n#endif\nmorphed += position;\ngl_Position = projectionMatrix * modelViewMatrix * vec4( morphed, 1.0 );\n#endif", -default_vertex:"#ifndef USE_MORPHTARGETS\n#ifndef USE_SKINNING\ngl_Position = projectionMatrix * mvPosition;\n#endif\n#endif",morphnormal_vertex:"#ifdef USE_MORPHNORMALS\nvec3 morphedNormal = vec3( 0.0 );\nmorphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\nmorphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\nmorphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\nmorphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\nmorphedNormal += normal;\nvec3 transformedNormal = normalMatrix * morphedNormal;\n#else\nvec3 transformedNormal = normalMatrix * normal;\n#endif", -shadowmap_pars_fragment:"#ifdef USE_SHADOWMAP\nuniform sampler2D shadowMap[ MAX_SHADOWS ];\nuniform vec2 shadowMapSize[ MAX_SHADOWS ];\nuniform float shadowDarkness[ MAX_SHADOWS ];\nuniform float shadowBias[ MAX_SHADOWS ];\nvarying vec4 vShadowCoord[ MAX_SHADOWS ];\nfloat unpackDepth( const in vec4 rgba_depth ) {\nconst vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );\nfloat depth = dot( rgba_depth, bit_shift );\nreturn depth;\n}\n#endif",shadowmap_fragment:"#ifdef USE_SHADOWMAP\n#ifdef SHADOWMAP_DEBUG\nvec3 frustumColors[3];\nfrustumColors[0] = vec3( 1.0, 0.5, 0.0 );\nfrustumColors[1] = vec3( 0.0, 1.0, 0.8 );\nfrustumColors[2] = vec3( 0.0, 0.5, 1.0 );\n#endif\n#ifdef SHADOWMAP_CASCADE\nint inFrustumCount = 0;\n#endif\nfloat fDepth;\nvec3 shadowColor = vec3( 1.0 );\nfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\nvec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;\nbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\nbool inFrustum = all( inFrustumVec );\n#ifdef SHADOWMAP_CASCADE\ninFrustumCount += int( inFrustum );\nbvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );\n#else\nbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n#endif\nbool frustumTest = all( frustumTestVec );\nif ( frustumTest ) {\nshadowCoord.z += shadowBias[ i ];\n#ifdef SHADOWMAP_SOFT\nfloat shadow = 0.0;\nconst float shadowDelta = 1.0 / 9.0;\nfloat xPixelOffset = 1.0 / shadowMapSize[ i ].x;\nfloat yPixelOffset = 1.0 / shadowMapSize[ i ].y;\nfloat dx0 = -1.25 * xPixelOffset;\nfloat dy0 = -1.25 * yPixelOffset;\nfloat dx1 = 1.25 * xPixelOffset;\nfloat dy1 = 1.25 * yPixelOffset;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nshadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n#else\nvec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );\nfloat fDepth = unpackDepth( rgbaDepth );\nif ( fDepth < shadowCoord.z )\nshadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );\n#endif\n}\n#ifdef SHADOWMAP_DEBUG\n#ifdef SHADOWMAP_CASCADE\nif ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];\n#else\nif ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];\n#endif\n#endif\n}\n#ifdef GAMMA_OUTPUT\nshadowColor *= shadowColor;\n#endif\ngl_FragColor.xyz = gl_FragColor.xyz * shadowColor;\n#endif", -shadowmap_pars_vertex:"#ifdef USE_SHADOWMAP\nvarying vec4 vShadowCoord[ MAX_SHADOWS ];\nuniform mat4 shadowMatrix[ MAX_SHADOWS ];\n#endif",shadowmap_vertex:"#ifdef USE_SHADOWMAP\nfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\n#ifdef USE_MORPHTARGETS\nvShadowCoord[ i ] = shadowMatrix[ i ] * objectMatrix * vec4( morphed, 1.0 );\n#else\nvShadowCoord[ i ] = shadowMatrix[ i ] * objectMatrix * vec4( position, 1.0 );\n#endif\n}\n#endif",alphatest_fragment:"#ifdef ALPHATEST\nif ( gl_FragColor.a < ALPHATEST ) discard;\n#endif", -linear_to_gamma_fragment:"#ifdef GAMMA_OUTPUT\ngl_FragColor.xyz = sqrt( gl_FragColor.xyz );\n#endif"}; -THREE.UniformsUtils={merge:function(a){var b,c,d,e={};for(b=0;b=0)return a.geometry.materials[b.materialIndex]}function d(a){return a instanceof THREE.MeshBasicMaterial&&!a.envMap||a instanceof THREE.MeshDepthMaterial?false:a&&a.shading!==void 0&&a.shading===THREE.SmoothShading?THREE.SmoothShading:THREE.FlatShading}function e(a){return a.map||a.lightMap||a instanceof THREE.ShaderMaterial?true:false}function f(a,b,c){var d,e,f,h,i=a.vertices;h=i.length; -var k=a.colors,j=k.length,l=a.__vertexArray,n=a.__colorArray,o=a.__sortArray,m=a.verticesNeedUpdate,p=a.colorsNeedUpdate,s=a.__webglCustomAttributesList;if(c.sortParticles){Ub.copy(qb);Ub.multiplySelf(c.matrixWorld);for(d=0;d0};this.setSize= -function(a,b){H.width=a;H.height=b;this.setViewport(0,0,H.width,H.height)};this.setViewport=function(a,b,c,d){Eb=a;Fb=b;Xb=c;Gb=d;g.viewport(Eb,Fb,Xb,Gb)};this.setScissor=function(a,b,c,d){g.scissor(a,b,c,d)};this.enableScissorTest=function(a){a?g.enable(g.SCISSOR_TEST):g.disable(g.SCISSOR_TEST)};this.setClearColorHex=function(a,b){ba.setHex(a);ja=b;g.clearColor(ba.r,ba.g,ba.b,ja)};this.setClearColor=function(a,b){ba.copy(a);ja=b;g.clearColor(ba.r,ba.g,ba.b,ja)};this.getClearColor=function(){return ba}; -this.getClearAlpha=function(){return ja};this.clear=function(a,b,c){var d=0;if(a===void 0||a)d=d|g.COLOR_BUFFER_BIT;if(b===void 0||b)d=d|g.DEPTH_BUFFER_BIT;if(c===void 0||c)d=d|g.STENCIL_BUFFER_BIT;g.clear(d)};this.clearTarget=function(a,b,c,d){this.setRenderTarget(a);this.clear(b,c,d)};this.addPostPlugin=function(a){a.init(this);this.renderPluginsPost.push(a)};this.addPrePlugin=function(a){a.init(this);this.renderPluginsPre.push(a)};this.deallocateObject=function(a){if(a.__webglInit){a.__webglInit= -false;delete a._modelViewMatrix;delete a._normalMatrix;delete a._normalMatrixArray;delete a._modelViewMatrixArray;delete a._objectMatrixArray;if(a instanceof THREE.Mesh)for(var b in a.geometry.geometryGroups){var c=a.geometry.geometryGroups[b];g.deleteBuffer(c.__webglVertexBuffer);g.deleteBuffer(c.__webglNormalBuffer);g.deleteBuffer(c.__webglTangentBuffer);g.deleteBuffer(c.__webglColorBuffer);g.deleteBuffer(c.__webglUVBuffer);g.deleteBuffer(c.__webglUV2Buffer);g.deleteBuffer(c.__webglSkinVertexABuffer); -g.deleteBuffer(c.__webglSkinVertexBBuffer);g.deleteBuffer(c.__webglSkinIndicesBuffer);g.deleteBuffer(c.__webglSkinWeightsBuffer);g.deleteBuffer(c.__webglFaceBuffer);g.deleteBuffer(c.__webglLineBuffer);var d=void 0,e=void 0;if(c.numMorphTargets){d=0;for(e=c.numMorphTargets;d= -0&&e.vertexNormalBuffer){g.bindBuffer(g.ARRAY_BUFFER,e.vertexNormalBuffer);g.vertexAttribPointer(a.normal,e.vertexNormalBuffer.itemSize,g.FLOAT,false,0,f[d].index*12)}if(a.uv>=0&&e.vertexUvBuffer)if(e.vertexUvBuffer){g.bindBuffer(g.ARRAY_BUFFER,e.vertexUvBuffer);g.vertexAttribPointer(a.uv,e.vertexUvBuffer.itemSize,g.FLOAT,false,0,f[d].index*8);g.enableVertexAttribArray(a.uv)}else g.disableVertexAttribArray(a.uv);if(a.color>=0&&e.vertexColorBuffer){g.bindBuffer(g.ARRAY_BUFFER,e.vertexColorBuffer); -g.vertexAttribPointer(a.color,e.vertexColorBuffer.itemSize,g.FLOAT,false,0,f[d].index*16)}g.bindBuffer(g.ELEMENT_ARRAY_BUFFER,e.vertexIndexBuffer)}g.drawElements(g.TRIANGLES,f[d].count,g.UNSIGNED_SHORT,f[d].start*2);D.info.render.calls++;D.info.render.vertices=D.info.render.vertices+f[d].count;D.info.render.faces=D.info.render.faces+f[d].count/3}}}};this.renderBuffer=function(a,b,c,d,e,f){if(d.visible!==false){var h,i,c=o(a,b,c,d,f),b=c.attributes,a=false,c=e.id*16777215+c.id*2+(d.wireframe?1:0); -if(c!==R){R=c;a=true}if(!d.morphTargets&&b.position>=0){if(a){g.bindBuffer(g.ARRAY_BUFFER,e.__webglVertexBuffer);g.vertexAttribPointer(b.position,3,g.FLOAT,false,0,0)}}else if(f.morphTargetBase){c=d.program.attributes;if(f.morphTargetBase!==-1){g.bindBuffer(g.ARRAY_BUFFER,e.__webglMorphTargetsBuffers[f.morphTargetBase]);g.vertexAttribPointer(c.position,3,g.FLOAT,false,0,0)}else if(c.position>=0){g.bindBuffer(g.ARRAY_BUFFER,e.__webglVertexBuffer);g.vertexAttribPointer(c.position,3,g.FLOAT,false,0, -0)}if(f.morphTargetForcedOrder.length){h=0;var k=f.morphTargetForcedOrder;for(i=f.morphTargetInfluences;hj){l=n;j=i[l]}g.bindBuffer(g.ARRAY_BUFFER,e.__webglMorphTargetsBuffers[l]);g.vertexAttribPointer(c["morphTarget"+h],3,g.FLOAT,false,0,0);if(d.morphNormals){g.bindBuffer(g.ARRAY_BUFFER,e.__webglMorphNormalsBuffers[l]);g.vertexAttribPointer(c["morphNormal"+h],3,g.FLOAT,false,0,0)}f.__webglMorphTargetInfluences[h]=j;k[l]=1;j=-1;h++}}d.program.uniforms.morphTargetInfluences!== -null&&g.uniform1fv(d.program.uniforms.morphTargetInfluences,f.__webglMorphTargetInfluences)}if(a){if(e.__webglCustomAttributesList){h=0;for(i=e.__webglCustomAttributesList.length;h=0){g.bindBuffer(g.ARRAY_BUFFER,c.buffer);g.vertexAttribPointer(b[c.buffer.belongsToAttribute],c.size,g.FLOAT,false,0,0)}}}if(b.color>=0){g.bindBuffer(g.ARRAY_BUFFER,e.__webglColorBuffer);g.vertexAttribPointer(b.color,3,g.FLOAT,false,0,0)}if(b.normal>= -0){g.bindBuffer(g.ARRAY_BUFFER,e.__webglNormalBuffer);g.vertexAttribPointer(b.normal,3,g.FLOAT,false,0,0)}if(b.tangent>=0){g.bindBuffer(g.ARRAY_BUFFER,e.__webglTangentBuffer);g.vertexAttribPointer(b.tangent,4,g.FLOAT,false,0,0)}if(b.uv>=0)if(e.__webglUVBuffer){g.bindBuffer(g.ARRAY_BUFFER,e.__webglUVBuffer);g.vertexAttribPointer(b.uv,2,g.FLOAT,false,0,0);g.enableVertexAttribArray(b.uv)}else g.disableVertexAttribArray(b.uv);if(b.uv2>=0)if(e.__webglUV2Buffer){g.bindBuffer(g.ARRAY_BUFFER,e.__webglUV2Buffer); -g.vertexAttribPointer(b.uv2,2,g.FLOAT,false,0,0);g.enableVertexAttribArray(b.uv2)}else g.disableVertexAttribArray(b.uv2);if(d.skinning&&b.skinVertexA>=0&&b.skinVertexB>=0&&b.skinIndex>=0&&b.skinWeight>=0){g.bindBuffer(g.ARRAY_BUFFER,e.__webglSkinVertexABuffer);g.vertexAttribPointer(b.skinVertexA,4,g.FLOAT,false,0,0);g.bindBuffer(g.ARRAY_BUFFER,e.__webglSkinVertexBBuffer);g.vertexAttribPointer(b.skinVertexB,4,g.FLOAT,false,0,0);g.bindBuffer(g.ARRAY_BUFFER,e.__webglSkinIndicesBuffer);g.vertexAttribPointer(b.skinIndex, -4,g.FLOAT,false,0,0);g.bindBuffer(g.ARRAY_BUFFER,e.__webglSkinWeightsBuffer);g.vertexAttribPointer(b.skinWeight,4,g.FLOAT,false,0,0)}}if(f instanceof THREE.Mesh){if(d.wireframe){d=d.wireframeLinewidth;if(d!==Db){g.lineWidth(d);Db=d}a&&g.bindBuffer(g.ELEMENT_ARRAY_BUFFER,e.__webglLineBuffer);g.drawElements(g.LINES,e.__webglLineCount,g.UNSIGNED_SHORT,0)}else{a&&g.bindBuffer(g.ELEMENT_ARRAY_BUFFER,e.__webglFaceBuffer);g.drawElements(g.TRIANGLES,e.__webglFaceCount,g.UNSIGNED_SHORT,0)}D.info.render.calls++; -D.info.render.vertices=D.info.render.vertices+e.__webglFaceCount;D.info.render.faces=D.info.render.faces+e.__webglFaceCount/3}else if(f instanceof THREE.Line){f=f.type===THREE.LineStrip?g.LINE_STRIP:g.LINES;d=d.linewidth;if(d!==Db){g.lineWidth(d);Db=d}g.drawArrays(f,0,e.__webglLineCount);D.info.render.calls++}}};this.render=function(a,b,c,d){var e,f,j,n,m=a.__lights,o=a.fog;$=-1;rb=true;if(b.parent===void 0){console.warn("DEPRECATED: Camera hasn't been added to a Scene. Adding it...");a.add(b)}this.autoUpdateScene&& -a.updateMatrixWorld();if(!b._viewMatrixArray)b._viewMatrixArray=new Float32Array(16);if(!b._projectionMatrixArray)b._projectionMatrixArray=new Float32Array(16);b.matrixWorldInverse.getInverse(b.matrixWorld);b.matrixWorldInverse.flattenToArray(b._viewMatrixArray);b.projectionMatrix.flattenToArray(b._projectionMatrixArray);qb.multiply(b.projectionMatrix,b.matrixWorldInverse);Yb.setFromMatrix(qb);this.autoUpdateObjects&&this.initWebGLObjects(a);i(this.renderPluginsPre,a,b);D.info.render.calls=0;D.info.render.vertices= -0;D.info.render.faces=0;D.info.render.points=0;this.setRenderTarget(c);(this.autoClear||d)&&this.clear(this.autoClearColor,this.autoClearDepth,this.autoClearStencil);n=a.__webglObjects;d=0;for(e=n.length;d=0){w=u.geometry.materials[w]; -if(w.transparent){q.transparent=w;q.opaque=null}else{q.opaque=w;q.transparent=null}}}else if(w)if(w.transparent){q.transparent=w;q.opaque=null}else{q.opaque=w;q.transparent=null}f.render=true;if(this.sortObjects)if(j.renderDepth)f.z=j.renderDepth;else{Ra.copy(j.matrixWorld.getPosition());qb.multiplyVector3(Ra);f.z=Ra.z}}}this.sortObjects&&n.sort(h);n=a.__webglObjectsImmediate;d=0;for(e=n.length;d65535){H[A].counter=H[A].counter+1;B=H[A].hash+"_"+H[A].counter;q.geometryGroups[B]===void 0&&(q.geometryGroups[B]={faces3:[],faces4:[],materialIndex:w,vertices:0,numMorphTargets:K,numMorphNormals:Y})}u instanceof THREE.Face3?q.geometryGroups[B].faces3.push(p):q.geometryGroups[B].faces4.push(p);q.geometryGroups[B].vertices= -q.geometryGroups[B].vertices+y}q.geometryGroupsList=[];var J=void 0;for(J in q.geometryGroups){q.geometryGroups[J].id=Z++;q.geometryGroupsList.push(q.geometryGroups[J])}}for(k in l.geometryGroups){o=l.geometryGroups[k];if(!o.__webglVertexBuffer){var N=o;N.__webglVertexBuffer=g.createBuffer();N.__webglNormalBuffer=g.createBuffer();N.__webglTangentBuffer=g.createBuffer();N.__webglColorBuffer=g.createBuffer();N.__webglUVBuffer=g.createBuffer();N.__webglUV2Buffer=g.createBuffer();N.__webglSkinVertexABuffer= -g.createBuffer();N.__webglSkinVertexBBuffer=g.createBuffer();N.__webglSkinIndicesBuffer=g.createBuffer();N.__webglSkinWeightsBuffer=g.createBuffer();N.__webglFaceBuffer=g.createBuffer();N.__webglLineBuffer=g.createBuffer();var O=void 0,R=void 0;if(N.numMorphTargets){N.__webglMorphTargetsBuffers=[];O=0;for(R=N.numMorphTargets;O0||ja.faceVertexUvs.length>0)I.__uvArray=new Float32Array(Q*2);if(ja.faceUvs.length>1||ja.faceVertexUvs.length> -1)I.__uv2Array=new Float32Array(Q*2)}if(ba.geometry.skinWeights.length&&ba.geometry.skinIndices.length){I.__skinVertexAArray=new Float32Array(Q*4);I.__skinVertexBArray=new Float32Array(Q*4);I.__skinIndexArray=new Float32Array(Q*4);I.__skinWeightArray=new Float32Array(Q*4)}I.__faceArray=new Uint16Array(za*3);I.__lineArray=new Uint16Array(pa*2);var sa=void 0,Ca=void 0;if(I.numMorphTargets){I.__morphTargetsArrays=[];sa=0;for(Ca=I.numMorphTargets;sa=0;nc--)Fb[nc].object===Xb&&Fb.splice(nc,1);mc.__webglActive=false;a.__objectsRemoved.splice(0,1)}for(var Gb=0,Yb=a.__webglObjects.length;Gb0){g.bindBuffer(g.ARRAY_BUFFER,M.__webglSkinVertexABuffer);g.bufferData(g.ARRAY_BUFFER,ea,Ia);g.bindBuffer(g.ARRAY_BUFFER,M.__webglSkinVertexBBuffer);g.bufferData(g.ARRAY_BUFFER,fa,Ia);g.bindBuffer(g.ARRAY_BUFFER,M.__webglSkinIndicesBuffer);g.bufferData(g.ARRAY_BUFFER,ga,Ia);g.bindBuffer(g.ARRAY_BUFFER,M.__webglSkinWeightsBuffer);g.bufferData(g.ARRAY_BUFFER,ha,Ia)}}if(Pc&&Ac){v=0;for(C=T.length;v0){g.bindBuffer(g.ARRAY_BUFFER,M.__webglColorBuffer);g.bufferData(g.ARRAY_BUFFER,va,Ia)}}if(Oc&&Ba.hasTangents){v=0;for(C=T.length;v0){g.bindBuffer(g.ARRAY_BUFFER,M.__webglUVBuffer);g.bufferData(g.ARRAY_BUFFER,fc,Ia)}}if(Jc&&Fc&&Wb){v=0;for(C=T.length;v0){g.bindBuffer(g.ARRAY_BUFFER,M.__webglUV2Buffer);g.bufferData(g.ARRAY_BUFFER,gc,Ia)}}if(yc){v=0;for(C=T.length;v0?"#define VERTEX_TEXTURES":"",D.gammaInput?"#define GAMMA_INPUT":"",D.gammaOutput?"#define GAMMA_OUTPUT":"",D.physicallyBasedShading?"#define PHYSICALLY_BASED_SHADING":"","#define MAX_DIR_LIGHTS "+c.maxDirLights,"#define MAX_POINT_LIGHTS "+c.maxPointLights,"#define MAX_SPOT_LIGHTS "+c.maxSpotLights,"#define MAX_SHADOWS "+c.maxShadows,"#define MAX_BONES "+c.maxBones,c.map?"#define USE_MAP": -"",c.envMap?"#define USE_ENVMAP":"",c.lightMap?"#define USE_LIGHTMAP":"",c.vertexColors?"#define USE_COLOR":"",c.skinning?"#define USE_SKINNING":"",c.morphTargets?"#define USE_MORPHTARGETS":"",c.morphNormals?"#define USE_MORPHNORMALS":"",c.perPixel?"#define PHONG_PER_PIXEL":"",c.wrapAround?"#define WRAP_AROUND":"",c.doubleSided?"#define DOUBLE_SIDED":"",c.shadowMapEnabled?"#define USE_SHADOWMAP":"",c.shadowMapSoft?"#define SHADOWMAP_SOFT":"",c.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",c.shadowMapCascade? -"#define SHADOWMAP_CASCADE":"",c.sizeAttenuation?"#define USE_SIZEATTENUATION":"","uniform mat4 objectMatrix;\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform mat4 viewMatrix;\nuniform mat3 normalMatrix;\nuniform vec3 cameraPosition;\nattribute vec3 position;\nattribute vec3 normal;\nattribute vec2 uv;\nattribute vec2 uv2;\n#ifdef USE_COLOR\nattribute vec3 color;\n#endif\n#ifdef USE_MORPHTARGETS\nattribute vec3 morphTarget0;\nattribute vec3 morphTarget1;\nattribute vec3 morphTarget2;\nattribute vec3 morphTarget3;\n#ifdef USE_MORPHNORMALS\nattribute vec3 morphNormal0;\nattribute vec3 morphNormal1;\nattribute vec3 morphNormal2;\nattribute vec3 morphNormal3;\n#else\nattribute vec3 morphTarget4;\nattribute vec3 morphTarget5;\nattribute vec3 morphTarget6;\nattribute vec3 morphTarget7;\n#endif\n#endif\n#ifdef USE_SKINNING\nattribute vec4 skinVertexA;\nattribute vec4 skinVertexB;\nattribute vec4 skinIndex;\nattribute vec4 skinWeight;\n#endif\n"].join("\n"); -j=["precision "+B+" float;","#define MAX_DIR_LIGHTS "+c.maxDirLights,"#define MAX_POINT_LIGHTS "+c.maxPointLights,"#define MAX_SPOT_LIGHTS "+c.maxSpotLights,"#define MAX_SHADOWS "+c.maxShadows,c.alphaTest?"#define ALPHATEST "+c.alphaTest:"",D.gammaInput?"#define GAMMA_INPUT":"",D.gammaOutput?"#define GAMMA_OUTPUT":"",D.physicallyBasedShading?"#define PHYSICALLY_BASED_SHADING":"",c.useFog&&c.fog?"#define USE_FOG":"",c.useFog&&c.fog instanceof THREE.FogExp2?"#define FOG_EXP2":"",c.map?"#define USE_MAP": -"",c.envMap?"#define USE_ENVMAP":"",c.lightMap?"#define USE_LIGHTMAP":"",c.vertexColors?"#define USE_COLOR":"",c.metal?"#define METAL":"",c.perPixel?"#define PHONG_PER_PIXEL":"",c.wrapAround?"#define WRAP_AROUND":"",c.doubleSided?"#define DOUBLE_SIDED":"",c.shadowMapEnabled?"#define USE_SHADOWMAP":"",c.shadowMapSoft?"#define SHADOWMAP_SOFT":"",c.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",c.shadowMapCascade?"#define SHADOWMAP_CASCADE":"","uniform mat4 viewMatrix;\nuniform vec3 cameraPosition;\n"].join("\n"); -g.attachShader(s,q("fragment",j+m));g.attachShader(s,q("vertex",d+k));g.linkProgram(s);g.getProgramParameter(s,g.LINK_STATUS)||console.error("Could not initialise shader\nVALIDATE_STATUS: "+g.getProgramParameter(s,g.VALIDATE_STATUS)+", gl error ["+g.getError()+"]");s.uniforms={};s.attributes={};var u,d=["viewMatrix","modelViewMatrix","projectionMatrix","normalMatrix","objectMatrix","cameraPosition","boneGlobalMatrices","morphTargetInfluences"];for(u in i)d.push(u);u=d;d=0;for(i=u.length;d=0&&g.enableVertexAttribArray(p.position); -p.color>=0&&g.enableVertexAttribArray(p.color);p.normal>=0&&g.enableVertexAttribArray(p.normal);p.tangent>=0&&g.enableVertexAttribArray(p.tangent);if(a.skinning&&p.skinVertexA>=0&&p.skinVertexB>=0&&p.skinIndex>=0&&p.skinWeight>=0){g.enableVertexAttribArray(p.skinVertexA);g.enableVertexAttribArray(p.skinVertexB);g.enableVertexAttribArray(p.skinIndex);g.enableVertexAttribArray(p.skinWeight)}if(a.attributes)for(f in a.attributes)p[f]!==void 0&&p[f]>=0&&g.enableVertexAttribArray(p[f]);if(a.morphTargets){a.numSupportedMorphTargets= -0;s="morphTarget";for(f=0;f=0){g.enableVertexAttribArray(p[u]);a.numSupportedMorphTargets++}}}if(a.morphNormals){a.numSupportedMorphNormals=0;s="morphNormal";for(f=0;f=0){g.enableVertexAttribArray(p[u]);a.numSupportedMorphNormals++}}}a.uniformsList=[];for(e in a.uniforms)a.uniformsList.push([a.uniforms[e],e])};this.setFaceCulling=function(a,b){if(a){!b||b==="ccw"?g.frontFace(g.CCW):g.frontFace(g.CW);a==="back"?g.cullFace(g.BACK): -a==="front"?g.cullFace(g.FRONT):g.cullFace(g.FRONT_AND_BACK);g.enable(g.CULL_FACE)}else g.disable(g.CULL_FACE)};this.setObjectFaces=function(a){if(Q!==a.doubleSided){a.doubleSided?g.disable(g.CULL_FACE):g.enable(g.CULL_FACE);Q=a.doubleSided}if(pa!==a.flipSided){a.flipSided?g.frontFace(g.CW):g.frontFace(g.CCW);pa=a.flipSided}};this.setDepthTest=function(a){if(La!==a){a?g.enable(g.DEPTH_TEST):g.disable(g.DEPTH_TEST);La=a}};this.setDepthWrite=function(a){if(Oa!==a){g.depthMask(a);Oa=a}};this.setBlending= -function(a,b,c,d){if(a!==O){switch(a){case THREE.NoBlending:g.disable(g.BLEND);break;case THREE.AdditiveBlending:g.enable(g.BLEND);g.blendEquation(g.FUNC_ADD);g.blendFunc(g.SRC_ALPHA,g.ONE);break;case THREE.SubtractiveBlending:g.enable(g.BLEND);g.blendEquation(g.FUNC_ADD);g.blendFunc(g.ZERO,g.ONE_MINUS_SRC_COLOR);break;case THREE.MultiplyBlending:g.enable(g.BLEND);g.blendEquation(g.FUNC_ADD);g.blendFunc(g.ZERO,g.SRC_COLOR);break;case THREE.CustomBlending:g.enable(g.BLEND);break;default:g.enable(g.BLEND); -g.blendEquationSeparate(g.FUNC_ADD,g.FUNC_ADD);g.blendFuncSeparate(g.SRC_ALPHA,g.ONE_MINUS_SRC_ALPHA,g.ONE,g.ONE_MINUS_SRC_ALPHA)}O=a}if(a===THREE.CustomBlending){if(b!==sa){g.blendEquation(u(b));sa=b}if(c!==Ga||d!==Ha){g.blendFunc(u(c),u(d));Ga=c;Ha=d}}else Ha=Ga=sa=null};this.setTexture=function(a,b){if(a.needsUpdate){if(!a.__webglInit){a.__webglInit=true;a.__webglTexture=g.createTexture();D.info.memory.textures++}g.activeTexture(g.TEXTURE0+b);g.bindTexture(g.TEXTURE_2D,a.__webglTexture);g.pixelStorei(g.UNPACK_PREMULTIPLY_ALPHA_WEBGL, -a.premultiplyAlpha);var c=a.image,d=(c.width&c.width-1)===0&&(c.height&c.height-1)===0,e=u(a.format),f=u(a.type);w(g.TEXTURE_2D,a,d);a instanceof THREE.DataTexture?g.texImage2D(g.TEXTURE_2D,0,e,c.width,c.height,0,e,f,c.data):g.texImage2D(g.TEXTURE_2D,0,e,e,f,a.image);a.generateMipmaps&&d&&g.generateMipmap(g.TEXTURE_2D);a.needsUpdate=false;if(a.onUpdate)a.onUpdate()}else{g.activeTexture(g.TEXTURE0+b);g.bindTexture(g.TEXTURE_2D,a.__webglTexture)}};this.setRenderTarget=function(a){var b=a instanceof -THREE.WebGLRenderTargetCube;if(a&&!a.__webglFramebuffer){if(a.depthBuffer===void 0)a.depthBuffer=true;if(a.stencilBuffer===void 0)a.stencilBuffer=true;a.__webglTexture=g.createTexture();var c=(a.width&a.width-1)===0&&(a.height&a.height-1)===0,d=u(a.format),e=u(a.type);if(b){a.__webglFramebuffer=[];a.__webglRenderbuffer=[];g.bindTexture(g.TEXTURE_CUBE_MAP,a.__webglTexture);w(g.TEXTURE_CUBE_MAP,a,c);for(var f=0;f<6;f++){a.__webglFramebuffer[f]=g.createFramebuffer();a.__webglRenderbuffer[f]=g.createRenderbuffer(); -g.texImage2D(g.TEXTURE_CUBE_MAP_POSITIVE_X+f,0,d,a.width,a.height,0,d,e,null);var h=a,i=g.TEXTURE_CUBE_MAP_POSITIVE_X+f;g.bindFramebuffer(g.FRAMEBUFFER,a.__webglFramebuffer[f]);g.framebufferTexture2D(g.FRAMEBUFFER,g.COLOR_ATTACHMENT0,i,h.__webglTexture,0);A(a.__webglRenderbuffer[f],a)}c&&g.generateMipmap(g.TEXTURE_CUBE_MAP)}else{a.__webglFramebuffer=g.createFramebuffer();a.__webglRenderbuffer=g.createRenderbuffer();g.bindTexture(g.TEXTURE_2D,a.__webglTexture);w(g.TEXTURE_2D,a,c);g.texImage2D(g.TEXTURE_2D, -0,d,a.width,a.height,0,d,e,null);d=g.TEXTURE_2D;g.bindFramebuffer(g.FRAMEBUFFER,a.__webglFramebuffer);g.framebufferTexture2D(g.FRAMEBUFFER,g.COLOR_ATTACHMENT0,d,a.__webglTexture,0);A(a.__webglRenderbuffer,a);c&&g.generateMipmap(g.TEXTURE_2D)}b?g.bindTexture(g.TEXTURE_CUBE_MAP,null):g.bindTexture(g.TEXTURE_2D,null);g.bindRenderbuffer(g.RENDERBUFFER,null);g.bindFramebuffer(g.FRAMEBUFFER,null)}if(a){b=b?a.__webglFramebuffer[a.activeCubeFace]:a.__webglFramebuffer;c=a.width;a=a.height;e=d=0}else{b=null; -c=Xb;a=Gb;d=Eb;e=Fb}if(b!==Da){g.bindFramebuffer(g.FRAMEBUFFER,b);g.viewport(d,e,c,a);Da=b}jc=c;kc=a}}; -THREE.WebGLRenderTarget=function(a,b,c){this.width=a;this.height=b;c=c||{};this.wrapS=c.wrapS!==void 0?c.wrapS:THREE.ClampToEdgeWrapping;this.wrapT=c.wrapT!==void 0?c.wrapT:THREE.ClampToEdgeWrapping;this.magFilter=c.magFilter!==void 0?c.magFilter:THREE.LinearFilter;this.minFilter=c.minFilter!==void 0?c.minFilter:THREE.LinearMipMapLinearFilter;this.offset=new THREE.Vector2(0,0);this.repeat=new THREE.Vector2(1,1);this.format=c.format!==void 0?c.format:THREE.RGBAFormat;this.type=c.type!==void 0?c.type: -THREE.UnsignedByteType;this.depthBuffer=c.depthBuffer!==void 0?c.depthBuffer:true;this.stencilBuffer=c.stencilBuffer!==void 0?c.stencilBuffer:true;this.generateMipmaps=true}; -THREE.WebGLRenderTarget.prototype.clone=function(){var a=new THREE.WebGLRenderTarget(this.width,this.height);a.wrapS=this.wrapS;a.wrapT=this.wrapT;a.magFilter=this.magFilter;a.minFilter=this.minFilter;a.offset.copy(this.offset);a.repeat.copy(this.repeat);a.format=this.format;a.type=this.type;a.depthBuffer=this.depthBuffer;a.stencilBuffer=this.stencilBuffer;return a};THREE.WebGLRenderTargetCube=function(a,b,c){THREE.WebGLRenderTarget.call(this,a,b,c);this.activeCubeFace=0}; -THREE.WebGLRenderTargetCube.prototype=new THREE.WebGLRenderTarget;THREE.WebGLRenderTargetCube.prototype.constructor=THREE.WebGLRenderTargetCube;THREE.RenderableVertex=function(){this.positionWorld=new THREE.Vector3;this.positionScreen=new THREE.Vector4;this.visible=true};THREE.RenderableVertex.prototype.copy=function(a){this.positionWorld.copy(a.positionWorld);this.positionScreen.copy(a.positionScreen)}; -THREE.RenderableFace3=function(){this.v1=new THREE.RenderableVertex;this.v2=new THREE.RenderableVertex;this.v3=new THREE.RenderableVertex;this.centroidWorld=new THREE.Vector3;this.centroidScreen=new THREE.Vector3;this.normalWorld=new THREE.Vector3;this.vertexNormalsWorld=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];this.faceMaterial=this.material=null;this.uvs=[[]];this.z=null}; -THREE.RenderableFace4=function(){this.v1=new THREE.RenderableVertex;this.v2=new THREE.RenderableVertex;this.v3=new THREE.RenderableVertex;this.v4=new THREE.RenderableVertex;this.centroidWorld=new THREE.Vector3;this.centroidScreen=new THREE.Vector3;this.normalWorld=new THREE.Vector3;this.vertexNormalsWorld=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];this.faceMaterial=this.material=null;this.uvs=[[]];this.z=null};THREE.RenderableObject=function(){this.z=this.object=null}; -THREE.RenderableLine=function(){this.z=null;this.v1=new THREE.RenderableVertex;this.v2=new THREE.RenderableVertex;this.material=null}; -THREE.GeometryUtils={merge:function(a,b){for(var c,d,e=a.vertices.length,f=b instanceof THREE.Mesh?b.geometry:b,h=a.vertices,i=f.vertices,l=a.faces,k=f.faces,j=a.faceVertexUvs[0],m=f.faceVertexUvs[0],n={},o=0;o1){d=1-d;e=1-e}f=1-d-e;h.copy(a);h.multiplyScalar(d);i.copy(b);i.multiplyScalar(e);h.addSelf(i);i.copy(c);i.multiplyScalar(f);h.addSelf(i);return h},randomPointInFace:function(a,b,c){var d,e,f;if(a instanceof -THREE.Face3){d=b.vertices[a.a];e=b.vertices[a.b];f=b.vertices[a.c];return THREE.GeometryUtils.randomPointInTriangle(d,e,f)}if(a instanceof THREE.Face4){d=b.vertices[a.a];e=b.vertices[a.b];f=b.vertices[a.c];var b=b.vertices[a.d],h;if(c)if(a._area1&&a._area2){c=a._area1;h=a._area2}else{c=THREE.GeometryUtils.triangleArea(d,e,b);h=THREE.GeometryUtils.triangleArea(e,f,b);a._area1=c;a._area2=h}else{c=THREE.GeometryUtils.triangleArea(d,e,b);h=THREE.GeometryUtils.triangleArea(e,f,b)}return THREE.GeometryUtils.random()* -(c+h)a?b(c,e-1):k[e] -b||s>b||n>b){l=a.vertices.length;y=e.clone();u=e.clone();if(o>=s&&o>=n){k=k.clone();k.lerpSelf(j,0.5);y.a=f;y.b=l;y.c=i;u.a=l;u.b=h;u.c=i;if(e.vertexNormals.length===3){f=e.vertexNormals[0].clone();f.lerpSelf(e.vertexNormals[1],0.5);y.vertexNormals[1].copy(f);u.vertexNormals[0].copy(f)}if(e.vertexColors.length===3){f=e.vertexColors[0].clone();f.lerpSelf(e.vertexColors[1],0.5);y.vertexColors[1].copy(f);u.vertexColors[0].copy(f)}e=0}else if(s>=o&&s>=n){k=j.clone();k.lerpSelf(m,0.5);y.a=f;y.b=h;y.c= -l;u.a=l;u.b=i;u.c=f;if(e.vertexNormals.length===3){f=e.vertexNormals[1].clone();f.lerpSelf(e.vertexNormals[2],0.5);y.vertexNormals[2].copy(f);u.vertexNormals[0].copy(f);u.vertexNormals[1].copy(e.vertexNormals[2]);u.vertexNormals[2].copy(e.vertexNormals[0])}if(e.vertexColors.length===3){f=e.vertexColors[1].clone();f.lerpSelf(e.vertexColors[2],0.5);y.vertexColors[2].copy(f);u.vertexColors[0].copy(f);u.vertexColors[1].copy(e.vertexColors[2]);u.vertexColors[2].copy(e.vertexColors[0])}e=1}else{k=k.clone(); -k.lerpSelf(m,0.5);y.a=f;y.b=h;y.c=l;u.a=l;u.b=h;u.c=i;if(e.vertexNormals.length===3){f=e.vertexNormals[0].clone();f.lerpSelf(e.vertexNormals[2],0.5);y.vertexNormals[2].copy(f);u.vertexNormals[0].copy(f)}if(e.vertexColors.length===3){f=e.vertexColors[0].clone();f.lerpSelf(e.vertexColors[2],0.5);y.vertexColors[2].copy(f);u.vertexColors[0].copy(f)}e=2}H.push(y,u);a.vertices.push(k);f=0;for(h=a.faceVertexUvs.length;fb||s>b||p>b||q>b){w=a.vertices.length;A=a.vertices.length+1;y=e.clone();u=e.clone();if(o>=s&&o>=p&&o>=q||p>=s&&p>=o&&p>=q){o=k.clone();o.lerpSelf(j,0.5);j=m.clone();j.lerpSelf(n,0.5);y.a=f;y.b=w;y.c=A;y.d=l;u.a=w;u.b=h;u.c=i;u.d=A;if(e.vertexNormals.length===4){f=e.vertexNormals[0].clone();f.lerpSelf(e.vertexNormals[1],0.5);h=e.vertexNormals[2].clone();h.lerpSelf(e.vertexNormals[3],0.5);y.vertexNormals[1].copy(f); -y.vertexNormals[2].copy(h);u.vertexNormals[0].copy(f);u.vertexNormals[3].copy(h)}if(e.vertexColors.length===4){f=e.vertexColors[0].clone();f.lerpSelf(e.vertexColors[1],0.5);h=e.vertexColors[2].clone();h.lerpSelf(e.vertexColors[3],0.5);y.vertexColors[1].copy(f);y.vertexColors[2].copy(h);u.vertexColors[0].copy(f);u.vertexColors[3].copy(h)}e=0}else{o=j.clone();o.lerpSelf(m,0.5);j=n.clone();j.lerpSelf(k,0.5);y.a=f;y.b=h;y.c=w;y.d=A;u.a=A;u.b=w;u.c=i;u.d=l;if(e.vertexNormals.length===4){f=e.vertexNormals[1].clone(); -f.lerpSelf(e.vertexNormals[2],0.5);h=e.vertexNormals[3].clone();h.lerpSelf(e.vertexNormals[0],0.5);y.vertexNormals[2].copy(f);y.vertexNormals[3].copy(h);u.vertexNormals[0].copy(h);u.vertexNormals[1].copy(f)}if(e.vertexColors.length===4){f=e.vertexColors[1].clone();f.lerpSelf(e.vertexColors[2],0.5);h=e.vertexColors[3].clone();h.lerpSelf(e.vertexColors[0],0.5);y.vertexColors[2].copy(f);y.vertexColors[3].copy(h);u.vertexColors[0].copy(h);u.vertexColors[1].copy(f)}e=1}H.push(y,u);a.vertices.push(o,j); -f=0;for(h=a.faceVertexUvs.length;fe-1?e-1:m+1,s=j-1<0?0:j-1,p=j+1>d-1?d-1:j+1,q=[],w=[0,0,i[(m*d+j)*4]/255*b];q.push([-1,0,i[(m*d+s)*4]/255*b]);q.push([-1,-1,i[(n*d+s)*4]/255*b]);q.push([0, --1,i[(n*d+j)*4]/255*b]);q.push([1,-1,i[(n*d+p)*4]/255*b]);q.push([1,0,i[(m*d+p)*4]/255*b]);q.push([1,1,i[(o*d+p)*4]/255*b]);q.push([0,1,i[(o*d+j)*4]/255*b]);q.push([-1,1,i[(o*d+s)*4]/255*b]);n=[];s=q.length;for(o=0;o 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\nvarying vec4 vPointLight[ MAX_POINT_LIGHTS ];\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif\nvarying vec3 vViewPosition;", -THREE.ShaderChunk.shadowmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,"void main() {\ngl_FragColor = vec4( vec3( 1.0 ), uOpacity );\nvec3 specularTex = vec3( 1.0 );\nvec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;\nnormalTex.xy *= uNormalScale;\nnormalTex = normalize( normalTex );\nif( enableDiffuse ) {\n#ifdef GAMMA_INPUT\nvec4 texelColor = texture2D( tDiffuse, vUv );\ntexelColor.xyz *= texelColor.xyz;\ngl_FragColor = gl_FragColor * texelColor;\n#else\ngl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );\n#endif\n}\nif( enableAO ) {\n#ifdef GAMMA_INPUT\nvec4 aoColor = texture2D( tAO, vUv );\naoColor.xyz *= aoColor.xyz;\ngl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;\n#else\ngl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;\n#endif\n}\nif( enableSpecular )\nspecularTex = texture2D( tSpecular, vUv ).xyz;\nmat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );\nvec3 finalNormal = tsb * normalTex;\nvec3 normal = normalize( finalNormal );\nvec3 viewPosition = normalize( vViewPosition );\n#if MAX_POINT_LIGHTS > 0\nvec3 pointDiffuse = vec3( 0.0 );\nvec3 pointSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec3 pointVector = normalize( vPointLight[ i ].xyz );\nfloat pointDistance = vPointLight[ i ].w;\n#ifdef WRAP_AROUND\nfloat pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );\nfloat pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );\nvec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n#else\nfloat pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );\n#endif\npointDiffuse += pointDistance * pointLightColor[ i ] * uDiffuseColor * pointDiffuseWeight;\nvec3 pointHalfVector = normalize( pointVector + viewPosition );\nfloat pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\nfloat pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, uShininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( uShininess + 2.0001 ) / 8.0;\nvec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( pointVector, pointHalfVector ), 5.0 );\npointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;\n#else\npointSpecular += pointDistance * pointLightColor[ i ] * uSpecularColor * pointSpecularWeight * pointDiffuseWeight;\n#endif\n}\n#endif\n#if MAX_DIR_LIGHTS > 0\nvec3 dirDiffuse = vec3( 0.0 );\nvec3 dirSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\n#ifdef WRAP_AROUND\nfloat directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );\nfloat directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );\nvec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );\n#else\nfloat dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );\n#endif\ndirDiffuse += directionalLightColor[ i ] * uDiffuseColor * dirDiffuseWeight;\nvec3 dirHalfVector = normalize( dirVector + viewPosition );\nfloat dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\nfloat dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, uShininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( uShininess + 2.0001 ) / 8.0;\nvec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );\ndirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\n#else\ndirSpecular += directionalLightColor[ i ] * uSpecularColor * dirSpecularWeight * dirDiffuseWeight;\n#endif\n}\n#endif\nvec3 totalDiffuse = vec3( 0.0 );\nvec3 totalSpecular = vec3( 0.0 );\n#if MAX_DIR_LIGHTS > 0\ntotalDiffuse += dirDiffuse;\ntotalSpecular += dirSpecular;\n#endif\n#if MAX_POINT_LIGHTS > 0\ntotalDiffuse += pointDiffuse;\ntotalSpecular += pointSpecular;\n#endif\ngl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor) + totalSpecular;\nif ( enableReflection ) {\nvec3 wPos = cameraPosition - vViewPosition;\nvec3 vReflect = reflect( normalize( wPos ), normal );\nvec4 cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );\n#ifdef GAMMA_INPUT\ncubeColor.xyz *= cubeColor.xyz;\n#endif\ngl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * uReflectivity );\n}", -THREE.ShaderChunk.shadowmap_fragment,THREE.ShaderChunk.linear_to_gamma_fragment,THREE.ShaderChunk.fog_fragment,"}"].join("\n"),vertexShader:["attribute vec4 tangent;\nuniform vec2 uOffset;\nuniform vec2 uRepeat;\n#ifdef VERTEX_TEXTURES\nuniform sampler2D tDisplacement;\nuniform float uDisplacementScale;\nuniform float uDisplacementBias;\n#endif\nvarying vec3 vTangent;\nvarying vec3 vBinormal;\nvarying vec3 vNormal;\nvarying vec2 vUv;\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\nvarying vec4 vPointLight[ MAX_POINT_LIGHTS ];\n#endif\nvarying vec3 vViewPosition;", -THREE.ShaderChunk.shadowmap_pars_vertex,"void main() {\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\nvViewPosition = -mvPosition.xyz;\nvNormal = normalMatrix * normal;\nvTangent = normalMatrix * tangent.xyz;\nvBinormal = cross( vNormal, vTangent ) * tangent.w;\nvUv = uv * uRepeat + uOffset;\n#if MAX_POINT_LIGHTS > 0\nfor( int i = 0; i < MAX_POINT_LIGHTS; i++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\nvPointLight[ i ] = vec4( lVector, lDistance );\n}\n#endif\n#ifdef VERTEX_TEXTURES\nvec3 dv = texture2D( tDisplacement, uv ).xyz;\nfloat df = uDisplacementScale * dv.x + uDisplacementBias;\nvec4 displacedPosition = vec4( normalize( vNormal.xyz ) * df, 0.0 ) + mvPosition;\ngl_Position = projectionMatrix * displacedPosition;\n#else\ngl_Position = projectionMatrix * mvPosition;\n#endif", -THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n")},cube:{uniforms:{tCube:{type:"t",value:1,texture:null},tFlip:{type:"f",value:-1}},vertexShader:"varying vec3 vViewPosition;\nvoid main() {\nvec4 mPosition = objectMatrix * vec4( position, 1.0 );\nvViewPosition = cameraPosition - mPosition.xyz;\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform samplerCube tCube;\nuniform float tFlip;\nvarying vec3 vViewPosition;\nvoid main() {\nvec3 wPos = cameraPosition - vViewPosition;\ngl_FragColor = textureCube( tCube, vec3( tFlip * wPos.x, wPos.yz ) );\n}"}}}); -THREE.BufferGeometry=function(){this.id=THREE.GeometryCount++;this.vertexColorArray=this.vertexUvArray=this.vertexNormalArray=this.vertexPositionArray=this.vertexIndexArray=this.vertexColorBuffer=this.vertexUvBuffer=this.vertexNormalBuffer=this.vertexPositionBuffer=this.vertexIndexBuffer=null;this.dynamic=false;this.boundingSphere=this.boundingBox=null;this.morphTargets=[]};THREE.BufferGeometry.prototype={constructor:THREE.BufferGeometry,computeBoundingBox:function(){},computeBoundingSphere:function(){}}; -THREE.CubeGeometry=function(a,b,c,d,e,f,h,i){function l(a,b,c,h,i,j,l,n){var m,o=d||1,p=e||1,q=i/2,g=j/2,s=k.vertices.length;if(a==="x"&&b==="y"||a==="y"&&b==="x")m="z";else if(a==="x"&&b==="z"||a==="z"&&b==="x"){m="y";p=f||1}else if(a==="z"&&b==="y"||a==="y"&&b==="z"){m="x";o=f||1}var w=o+1,y=p+1,A=i/o,R=j/p,J=new THREE.Vector3;J[m]=l>0?1:-1;for(i=0;i0){this.vertices.push(new THREE.Vector3(0, -h,0));for(i=0;i0){this.vertices.push(new THREE.Vector3(0,-h,0));for(i=0;i 0) { - return result.invalidAttrs; - } - } - }; - }; - - // Helper to mix in validation on a model - var bindModel = function(view, model, options) { - _.extend(model, mixin(view, options)); - }; - - // Removes the methods added to a model - var unbindModel = function(model) { - delete model.validate; - delete model.preValidate; - delete model.isValid; - }; - - // Mix in validation on a model whenever a model is - // added to a collection - var collectionAdd = function(model) { - bindModel(this.view, model, this.options); - }; - - // Remove validation from a model whenever a model is - // removed from a collection - var collectionRemove = function(model) { - unbindModel(model); - }; - - // Returns the public methods on Backbone.Validation - return { - - // Current version of the library - version: '0.9.1', - - // Called to configure the default options - configure: function(options) { - _.extend(defaultOptions, options); - }, - - // Hooks up validation on a view with a model - // or collection - bind: function(view, options) { - options = _.extend({}, defaultOptions, defaultCallbacks, options); - - var model = options.model || view.model, - collection = options.collection || view.collection; - - if(typeof model === 'undefined' && typeof collection === 'undefined'){ - throw 'Before you execute the binding your view must have a model or a collection.\n' + - 'See http://thedersen.com/projects/backbone-validation/#using-form-model-validation for more information.'; - } - - if(model) { - bindModel(view, model, options); - } - else if(collection) { - collection.each(function(model){ - bindModel(view, model, options); - }); - collection.bind('add', collectionAdd, {view: view, options: options}); - collection.bind('remove', collectionRemove); - } - }, - - // Removes validation from a view with a model - // or collection - unbind: function(view, options) { - options = _.extend({}, options); - var model = options.model || view.model, - collection = options.collection || view.collection; - - if(model) { - unbindModel(model); - } - else if(collection) { - collection.each(function(model){ - unbindModel(model); - }); - collection.unbind('add', collectionAdd); - collection.unbind('remove', collectionRemove); - } - }, - - // Used to extend the Backbone.Model.prototype - // with validation - mixin: mixin(null, defaultOptions) - }; - }()); - - - // Callbacks - // --------- - - var defaultCallbacks = Validation.callbacks = { - - // Gets called when a previously invalid field in the - // view becomes valid. Removes any error message. - // Should be overridden with custom functionality. - valid: function(view, attr, selector) { - view.$('[' + selector + '~="' + attr + '"]') - .removeClass('invalid') - .removeAttr('data-error'); - }, - - // Gets called when a field in the view becomes invalid. - // Adds a error message. - // Should be overridden with custom functionality. - invalid: function(view, attr, error, selector) { - view.$('[' + selector + '~="' + attr + '"]') - .addClass('invalid') - .attr('data-error', error); - } - }; - - - // Patterns - // -------- - - var defaultPatterns = Validation.patterns = { - // Matches any digit(s) (i.e. 0-9) - digits: /^\d+$/, - - // Matches any number (e.g. 100.000) - number: /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/, - - // Matches a valid email address (e.g. mail@example.com) - email: /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i, - - // Mathes any valid url (e.g. http://www.xample.com) - url: /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i - }; - - - // Error messages - // -------------- - - // Error message for the build in validators. - // {x} gets swapped out with arguments form the validator. - var defaultMessages = Validation.messages = { - required: '{0} is required', - acceptance: '{0} must be accepted', - min: '{0} must be greater than or equal to {1}', - max: '{0} must be less than or equal to {1}', - range: '{0} must be between {1} and {2}', - length: '{0} must be {1} characters', - minLength: '{0} must be at least {1} characters', - maxLength: '{0} must be at most {1} characters', - rangeLength: '{0} must be between {1} and {2} characters', - oneOf: '{0} must be one of: {1}', - equalTo: '{0} must be the same as {1}', - digits: '{0} must only contain digits', - number: '{0} must be a number', - email: '{0} must be a valid email', - url: '{0} must be a valid url', - inlinePattern: '{0} is invalid' - }; - - // Label formatters - // ---------------- - - // Label formatters are used to convert the attribute name - // to a more human friendly label when using the built in - // error messages. - // Configure which one to use with a call to - // - // Backbone.Validation.configure({ - // labelFormatter: 'label' - // }); - var defaultLabelFormatters = Validation.labelFormatters = { - - // Returns the attribute name with applying any formatting - none: function(attrName) { - return attrName; - }, - - // Converts attributeName or attribute_name to Attribute name - sentenceCase: function(attrName) { - return attrName.replace(/(?:^\w|[A-Z]|\b\w)/g, function(match, index) { - return index === 0 ? match.toUpperCase() : ' ' + match.toLowerCase(); - }).replace(/_/g, ' '); - }, - - // Looks for a label configured on the model and returns it - // - // var Model = Backbone.Model.extend({ - // validation: { - // someAttribute: { - // required: true - // } - // }, - // - // labels: { - // someAttribute: 'Custom label' - // } - // }); - label: function(attrName, model) { - return (model.labels && model.labels[attrName]) || defaultLabelFormatters.sentenceCase(attrName, model); - } - }; - - - // Built in validators - // ------------------- - - var defaultValidators = Validation.validators = (function(){ - // Use native trim when defined - var trim = String.prototype.trim ? - function(text) { - return text === null ? '' : String.prototype.trim.call(text); - } : - function(text) { - var trimLeft = /^\s+/, - trimRight = /\s+$/; - - return text === null ? '' : text.toString().replace(trimLeft, '').replace(trimRight, ''); - }; - - // Determines whether or not a value is a number - var isNumber = function(value){ - return _.isNumber(value) || (_.isString(value) && value.match(defaultPatterns.number)); - }; - - // Determines whether or not a value is empty - var hasValue = function(value) { - return !(_.isNull(value) || _.isUndefined(value) || (_.isString(value) && trim(value) === '') || (_.isArray(value) && _.isEmpty(value))); - }; - - return { - // Function validator - // Lets you implement a custom function used for validation - fn: function(value, attr, fn, model, computed) { - if(_.isString(fn)){ - fn = model[fn]; - } - return fn.call(model, value, attr, computed); - }, - - // Required validator - // Validates if the attribute is required or not - // This can be specified as either a boolean value or a function that returns a boolean value - required: function(value, attr, required, model, computed) { - var isRequired = _.isFunction(required) ? required.call(model, value, attr, computed) : required; - if(!isRequired && !hasValue(value)) { - return false; // overrides all other validators - } - if (isRequired && !hasValue(value)) { - return this.format(defaultMessages.required, this.formatLabel(attr, model)); - } - }, - - // Acceptance validator - // Validates that something has to be accepted, e.g. terms of use - // `true` or 'true' are valid - acceptance: function(value, attr, accept, model) { - if(value !== 'true' && (!_.isBoolean(value) || value === false)) { - return this.format(defaultMessages.acceptance, this.formatLabel(attr, model)); - } - }, - - // Min validator - // Validates that the value has to be a number and equal to or greater than - // the min value specified - min: function(value, attr, minValue, model) { - if (!isNumber(value) || value < minValue) { - return this.format(defaultMessages.min, this.formatLabel(attr, model), minValue); - } - }, - - // Max validator - // Validates that the value has to be a number and equal to or less than - // the max value specified - max: function(value, attr, maxValue, model) { - if (!isNumber(value) || value > maxValue) { - return this.format(defaultMessages.max, this.formatLabel(attr, model), maxValue); - } - }, - - // Range validator - // Validates that the value has to be a number and equal to or between - // the two numbers specified - range: function(value, attr, range, model) { - if(!isNumber(value) || value < range[0] || value > range[1]) { - return this.format(defaultMessages.range, this.formatLabel(attr, model), range[0], range[1]); - } - }, - - // Length validator - // Validates that the value has to be a string with length equal to - // the length value specified - length: function(value, attr, length, model) { - if (!_.isString(value) || value.length !== length) { - return this.format(defaultMessages.length, this.formatLabel(attr, model), length); - } - }, - - // Min length validator - // Validates that the value has to be a string with length equal to or greater than - // the min length value specified - minLength: function(value, attr, minLength, model) { - if (!_.isString(value) || value.length < minLength) { - return this.format(defaultMessages.minLength, this.formatLabel(attr, model), minLength); - } - }, - - // Max length validator - // Validates that the value has to be a string with length equal to or less than - // the max length value specified - maxLength: function(value, attr, maxLength, model) { - if (!_.isString(value) || value.length > maxLength) { - return this.format(defaultMessages.maxLength, this.formatLabel(attr, model), maxLength); - } - }, - - // Range length validator - // Validates that the value has to be a string and equal to or between - // the two numbers specified - rangeLength: function(value, attr, range, model) { - if (!_.isString(value) || value.length < range[0] || value.length > range[1]) { - return this.format(defaultMessages.rangeLength, this.formatLabel(attr, model), range[0], range[1]); - } - }, - - // One of validator - // Validates that the value has to be equal to one of the elements in - // the specified array. Case sensitive matching - oneOf: function(value, attr, values, model) { - if(!_.include(values, value)){ - return this.format(defaultMessages.oneOf, this.formatLabel(attr, model), values.join(', ')); - } - }, - - // Equal to validator - // Validates that the value has to be equal to the value of the attribute - // with the name specified - equalTo: function(value, attr, equalTo, model, computed) { - if(value !== computed[equalTo]) { - return this.format(defaultMessages.equalTo, this.formatLabel(attr, model), this.formatLabel(equalTo, model)); - } - }, - - // Pattern validator - // Validates that the value has to match the pattern specified. - // Can be a regular expression or the name of one of the built in patterns - pattern: function(value, attr, pattern, model) { - if (!hasValue(value) || !value.toString().match(defaultPatterns[pattern] || pattern)) { - return this.format(defaultMessages[pattern] || defaultMessages.inlinePattern, this.formatLabel(attr, model), pattern); - } - } - }; - }()); - - // Set the correct context for all validators - // when used from within a method validator - _.each(defaultValidators, function(validator, key){ - defaultValidators[key] = _.bind(defaultValidators[key], _.extend({}, formatFunctions, defaultValidators)); - }); - - return Validation; - }(_)); - return Backbone.Validation; -})); \ No newline at end of file diff --git a/client/src/js/vendor/backbone/backbone-validation.js_.js b/client/src/js/vendor/backbone/backbone-validation.js_.js deleted file mode 100644 index 6b112dd12..000000000 --- a/client/src/js/vendor/backbone/backbone-validation.js_.js +++ /dev/null @@ -1,634 +0,0 @@ -// Backbone.Validation v0.9.1 -// -// Copyright (c) 2011-2014 Thomas Pedersen -// Distributed under MIT License -// -// Documentation and full license available at: -// http://thedersen.com/projects/backbone-validation -Backbone.Validation = (function(_){ - 'use strict'; - - // Default options - // --------------- - - var defaultOptions = { - forceUpdate: false, - selector: 'name', - labelFormatter: 'sentenceCase', - valid: Function.prototype, - invalid: Function.prototype - }; - - - // Helper functions - // ---------------- - - // Formatting functions used for formatting error messages - var formatFunctions = { - // Uses the configured label formatter to format the attribute name - // to make it more readable for the user - formatLabel: function(attrName, model) { - return defaultLabelFormatters[defaultOptions.labelFormatter](attrName, model); - }, - - // Replaces nummeric placeholders like {0} in a string with arguments - // passed to the function - format: function() { - var args = Array.prototype.slice.call(arguments), - text = args.shift(); - return text.replace(/\{(\d+)\}/g, function(match, number) { - return typeof args[number] !== 'undefined' ? args[number] : match; - }); - } - }; - - // Flattens an object - // eg: - // - // var o = { - // address: { - // street: 'Street', - // zip: 1234 - // } - // }; - // - // becomes: - // - // var o = { - // 'address.street': 'Street', - // 'address.zip': 1234 - // }; - var flatten = function (obj, into, prefix) { - into = into || {}; - prefix = prefix || ''; - - _.each(obj, function(val, key) { - if(obj.hasOwnProperty(key)) { - if (val && typeof val === 'object' && !( - val instanceof Array || - val instanceof Date || - val instanceof RegExp || - val instanceof Backbone.Model || - val instanceof Backbone.Collection) - ) { - flatten(val, into, prefix + key + '.'); - } - else { - into[prefix + key] = val; - } - } - }); - - return into; - }; - - // Validation - // ---------- - - var Validation = (function(){ - - // Returns an object with undefined properties for all - // attributes on the model that has defined one or more - // validation rules. - var getValidatedAttrs = function(model) { - return _.reduce(_.keys(_.result(model, 'validation') || {}), function(memo, key) { - memo[key] = void 0; - return memo; - }, {}); - }; - - // Looks on the model for validations for a specified - // attribute. Returns an array of any validators defined, - // or an empty array if none is defined. - var getValidators = function(model, attr) { - var attrValidationSet = model.validation ? _.result(model, 'validation')[attr] || {} : {}; - - // If the validator is a function or a string, wrap it in a function validator - if (_.isFunction(attrValidationSet) || _.isString(attrValidationSet)) { - attrValidationSet = { - fn: attrValidationSet - }; - } - - // Stick the validator object into an array - if(!_.isArray(attrValidationSet)) { - attrValidationSet = [attrValidationSet]; - } - - // Reduces the array of validators into a new array with objects - // with a validation method to call, the value to validate against - // and the specified error message, if any - return _.reduce(attrValidationSet, function(memo, attrValidation) { - _.each(_.without(_.keys(attrValidation), 'msg'), function(validator) { - memo.push({ - fn: defaultValidators[validator], - val: attrValidation[validator], - msg: attrValidation.msg - }); - }); - return memo; - }, []); - }; - - // Validates an attribute against all validators defined - // for that attribute. If one or more errors are found, - // the first error message is returned. - // If the attribute is valid, an empty string is returned. - var validateAttr = function(model, attr, value, computed) { - // Reduces the array of validators to an error message by - // applying all the validators and returning the first error - // message, if any. - return _.reduce(getValidators(model, attr), function(memo, validator){ - // Pass the format functions plus the default - // validators as the context to the validator - var ctx = _.extend({}, formatFunctions, defaultValidators), - result = validator.fn.call(ctx, value, attr, validator.val, model, computed); - - if(result === false || memo === false) { - return false; - } - if (result && !memo) { - return _.result(validator, 'msg') || result; - } - return memo; - }, ''); - }; - - // Loops through the model's attributes and validates them all. - // Returns and object containing names of invalid attributes - // as well as error messages. - var validateModel = function(model, attrs) { - var error, - invalidAttrs = {}, - isValid = true, - computed = _.clone(attrs), - flattened = flatten(attrs); - - _.each(flattened, function(val, attr) { - error = validateAttr(model, attr, val, computed); - if (error) { - invalidAttrs[attr] = error; - isValid = false; - } - }); - - return { - invalidAttrs: invalidAttrs, - isValid: isValid - }; - }; - - // Contains the methods that are mixed in on the model when binding - var mixin = function(view, options) { - return { - - // Check whether or not a value, or a hash of values - // passes validation without updating the model - preValidate: function(attr, value) { - var self = this, - result = {}, - error; - - if(_.isObject(attr)){ - _.each(attr, function(value, key) { - error = self.preValidate(key, value); - if(error){ - result[key] = error; - } - }); - - return _.isEmpty(result) ? undefined : result; - } - else { - return validateAttr(this, attr, value, _.extend({}, this.attributes)); - } - }, - - // Check to see if an attribute, an array of attributes or the - // entire model is valid. Passing true will force a validation - // of the model. - isValid: function(option) { - var flattened = flatten(this.attributes); - - if(_.isString(option)){ - return !validateAttr(this, option, flattened[option], _.extend({}, this.attributes)); - } - if(_.isArray(option)){ - return _.reduce(option, function(memo, attr) { - return memo && !validateAttr(this, attr, flattened[attr], _.extend({}, this.attributes)); - }, true, this); - } - if(option === true) { - this.validate(); - } - return this.validation ? this._isValid : true; - }, - - // This is called by Backbone when it needs to perform validation. - // You can call it manually without any parameters to validate the - // entire model. - validate: function(attrs, setOptions){ - var model = this, - validateAll = !attrs, - opt = _.extend({}, options, setOptions), - validatedAttrs = getValidatedAttrs(model), - allAttrs = _.extend({}, validatedAttrs, model.attributes, attrs), - changedAttrs = flatten(attrs || allAttrs), - - result = validateModel(model, allAttrs); - - model._isValid = result.isValid; - - // After validation is performed, loop through all validated attributes - // and call the valid callbacks so the view is updated. - _.each(validatedAttrs, function(val, attr){ - var invalid = result.invalidAttrs.hasOwnProperty(attr); - if(!invalid){ - opt.valid(view, attr, opt.selector); - } - }); - - // After validation is performed, loop through all validated and changed attributes - // and call the invalid callback so the view is updated. - _.each(validatedAttrs, function(val, attr){ - var invalid = result.invalidAttrs.hasOwnProperty(attr), - changed = changedAttrs.hasOwnProperty(attr); - - if(invalid && (changed || validateAll)){ - opt.invalid(view, attr, result.invalidAttrs[attr], opt.selector); - } - }); - - // Trigger validated events. - // Need to defer this so the model is actually updated before - // the event is triggered. - _.defer(function() { - model.trigger('validated', model._isValid, model, result.invalidAttrs); - model.trigger('validated:' + (model._isValid ? 'valid' : 'invalid'), model, result.invalidAttrs); - }); - - // Return any error messages to Backbone, unless the forceUpdate flag is set. - // Then we do not return anything and fools Backbone to believe the validation was - // a success. That way Backbone will update the model regardless. - if (!opt.forceUpdate && _.intersection(_.keys(result.invalidAttrs), _.keys(changedAttrs)).length > 0) { - return result.invalidAttrs; - } - } - }; - }; - - // Helper to mix in validation on a model - var bindModel = function(view, model, options) { - _.extend(model, mixin(view, options)); - }; - - // Removes the methods added to a model - var unbindModel = function(model) { - delete model.validate; - delete model.preValidate; - delete model.isValid; - }; - - // Mix in validation on a model whenever a model is - // added to a collection - var collectionAdd = function(model) { - bindModel(this.view, model, this.options); - }; - - // Remove validation from a model whenever a model is - // removed from a collection - var collectionRemove = function(model) { - unbindModel(model); - }; - - // Returns the public methods on Backbone.Validation - return { - - // Current version of the library - version: '0.9.1', - - // Called to configure the default options - configure: function(options) { - _.extend(defaultOptions, options); - }, - - // Hooks up validation on a view with a model - // or collection - bind: function(view, options) { - options = _.extend({}, defaultOptions, defaultCallbacks, options); - - var model = options.model || view.model, - collection = options.collection || view.collection; - - if(typeof model === 'undefined' && typeof collection === 'undefined'){ - throw 'Before you execute the binding your view must have a model or a collection.\n' + - 'See http://thedersen.com/projects/backbone-validation/#using-form-model-validation for more information.'; - } - - if(model) { - bindModel(view, model, options); - } - else if(collection) { - collection.each(function(model){ - bindModel(view, model, options); - }); - collection.bind('add', collectionAdd, {view: view, options: options}); - collection.bind('remove', collectionRemove); - } - }, - - // Removes validation from a view with a model - // or collection - unbind: function(view, options) { - options = _.extend({}, options); - var model = options.model || view.model, - collection = options.collection || view.collection; - - if(model) { - unbindModel(model); - } - else if(collection) { - collection.each(function(model){ - unbindModel(model); - }); - collection.unbind('add', collectionAdd); - collection.unbind('remove', collectionRemove); - } - }, - - // Used to extend the Backbone.Model.prototype - // with validation - mixin: mixin(null, defaultOptions) - }; - }()); - - - // Callbacks - // --------- - - var defaultCallbacks = Validation.callbacks = { - - // Gets called when a previously invalid field in the - // view becomes valid. Removes any error message. - // Should be overridden with custom functionality. - valid: function(view, attr, selector) { - view.$('[' + selector + '~="' + attr + '"]') - .removeClass('invalid') - .removeAttr('data-error'); - }, - - // Gets called when a field in the view becomes invalid. - // Adds a error message. - // Should be overridden with custom functionality. - invalid: function(view, attr, error, selector) { - view.$('[' + selector + '~="' + attr + '"]') - .addClass('invalid') - .attr('data-error', error); - } - }; - - - // Patterns - // -------- - - var defaultPatterns = Validation.patterns = { - // Matches any digit(s) (i.e. 0-9) - digits: /^\d+$/, - - // Matches any number (e.g. 100.000) - number: /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/, - - // Matches a valid email address (e.g. mail@example.com) - email: /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i, - - // Mathes any valid url (e.g. http://www.xample.com) - url: /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i - }; - - - // Error messages - // -------------- - - // Error message for the build in validators. - // {x} gets swapped out with arguments form the validator. - var defaultMessages = Validation.messages = { - required: '{0} is required', - acceptance: '{0} must be accepted', - min: '{0} must be greater than or equal to {1}', - max: '{0} must be less than or equal to {1}', - range: '{0} must be between {1} and {2}', - length: '{0} must be {1} characters', - minLength: '{0} must be at least {1} characters', - maxLength: '{0} must be at most {1} characters', - rangeLength: '{0} must be between {1} and {2} characters', - oneOf: '{0} must be one of: {1}', - equalTo: '{0} must be the same as {1}', - digits: '{0} must only contain digits', - number: '{0} must be a number', - email: '{0} must be a valid email', - url: '{0} must be a valid url', - inlinePattern: '{0} is invalid' - }; - - // Label formatters - // ---------------- - - // Label formatters are used to convert the attribute name - // to a more human friendly label when using the built in - // error messages. - // Configure which one to use with a call to - // - // Backbone.Validation.configure({ - // labelFormatter: 'label' - // }); - var defaultLabelFormatters = Validation.labelFormatters = { - - // Returns the attribute name with applying any formatting - none: function(attrName) { - return attrName; - }, - - // Converts attributeName or attribute_name to Attribute name - sentenceCase: function(attrName) { - return attrName.replace(/(?:^\w|[A-Z]|\b\w)/g, function(match, index) { - return index === 0 ? match.toUpperCase() : ' ' + match.toLowerCase(); - }).replace(/_/g, ' '); - }, - - // Looks for a label configured on the model and returns it - // - // var Model = Backbone.Model.extend({ - // validation: { - // someAttribute: { - // required: true - // } - // }, - // - // labels: { - // someAttribute: 'Custom label' - // } - // }); - label: function(attrName, model) { - return (model.labels && model.labels[attrName]) || defaultLabelFormatters.sentenceCase(attrName, model); - } - }; - - - // Built in validators - // ------------------- - - var defaultValidators = Validation.validators = (function(){ - // Use native trim when defined - var trim = String.prototype.trim ? - function(text) { - return text === null ? '' : String.prototype.trim.call(text); - } : - function(text) { - var trimLeft = /^\s+/, - trimRight = /\s+$/; - - return text === null ? '' : text.toString().replace(trimLeft, '').replace(trimRight, ''); - }; - - // Determines whether or not a value is a number - var isNumber = function(value){ - return _.isNumber(value) || (_.isString(value) && value.match(defaultPatterns.number)); - }; - - // Determines whether or not a value is empty - var hasValue = function(value) { - return !(_.isNull(value) || _.isUndefined(value) || (_.isString(value) && trim(value) === '') || (_.isArray(value) && _.isEmpty(value))); - }; - - return { - // Function validator - // Lets you implement a custom function used for validation - fn: function(value, attr, fn, model, computed) { - if(_.isString(fn)){ - fn = model[fn]; - } - return fn.call(model, value, attr, computed); - }, - - // Required validator - // Validates if the attribute is required or not - // This can be specified as either a boolean value or a function that returns a boolean value - required: function(value, attr, required, model, computed) { - var isRequired = _.isFunction(required) ? required.call(model, value, attr, computed) : required; - if(!isRequired && !hasValue(value)) { - return false; // overrides all other validators - } - if (isRequired && !hasValue(value)) { - return this.format(defaultMessages.required, this.formatLabel(attr, model)); - } - }, - - // Acceptance validator - // Validates that something has to be accepted, e.g. terms of use - // `true` or 'true' are valid - acceptance: function(value, attr, accept, model) { - if(value !== 'true' && (!_.isBoolean(value) || value === false)) { - return this.format(defaultMessages.acceptance, this.formatLabel(attr, model)); - } - }, - - // Min validator - // Validates that the value has to be a number and equal to or greater than - // the min value specified - min: function(value, attr, minValue, model) { - if (!isNumber(value) || value < minValue) { - return this.format(defaultMessages.min, this.formatLabel(attr, model), minValue); - } - }, - - // Max validator - // Validates that the value has to be a number and equal to or less than - // the max value specified - max: function(value, attr, maxValue, model) { - if (!isNumber(value) || value > maxValue) { - return this.format(defaultMessages.max, this.formatLabel(attr, model), maxValue); - } - }, - - // Range validator - // Validates that the value has to be a number and equal to or between - // the two numbers specified - range: function(value, attr, range, model) { - if(!isNumber(value) || value < range[0] || value > range[1]) { - return this.format(defaultMessages.range, this.formatLabel(attr, model), range[0], range[1]); - } - }, - - // Length validator - // Validates that the value has to be a string with length equal to - // the length value specified - length: function(value, attr, length, model) { - if (!_.isString(value) || value.length !== length) { - return this.format(defaultMessages.length, this.formatLabel(attr, model), length); - } - }, - - // Min length validator - // Validates that the value has to be a string with length equal to or greater than - // the min length value specified - minLength: function(value, attr, minLength, model) { - if (!_.isString(value) || value.length < minLength) { - return this.format(defaultMessages.minLength, this.formatLabel(attr, model), minLength); - } - }, - - // Max length validator - // Validates that the value has to be a string with length equal to or less than - // the max length value specified - maxLength: function(value, attr, maxLength, model) { - if (!_.isString(value) || value.length > maxLength) { - return this.format(defaultMessages.maxLength, this.formatLabel(attr, model), maxLength); - } - }, - - // Range length validator - // Validates that the value has to be a string and equal to or between - // the two numbers specified - rangeLength: function(value, attr, range, model) { - if (!_.isString(value) || value.length < range[0] || value.length > range[1]) { - return this.format(defaultMessages.rangeLength, this.formatLabel(attr, model), range[0], range[1]); - } - }, - - // One of validator - // Validates that the value has to be equal to one of the elements in - // the specified array. Case sensitive matching - oneOf: function(value, attr, values, model) { - if(!_.include(values, value)){ - return this.format(defaultMessages.oneOf, this.formatLabel(attr, model), values.join(', ')); - } - }, - - // Equal to validator - // Validates that the value has to be equal to the value of the attribute - // with the name specified - equalTo: function(value, attr, equalTo, model, computed) { - if(value !== computed[equalTo]) { - return this.format(defaultMessages.equalTo, this.formatLabel(attr, model), this.formatLabel(equalTo, model)); - } - }, - - // Pattern validator - // Validates that the value has to match the pattern specified. - // Can be a regular expression or the name of one of the built in patterns - pattern: function(value, attr, pattern, model) { - if (!hasValue(value) || !value.toString().match(defaultPatterns[pattern] || pattern)) { - return this.format(defaultMessages[pattern] || defaultMessages.inlinePattern, this.formatLabel(attr, model), pattern); - } - } - }; - }()); - - // Set the correct context for all validators - // when used from within a method validator - _.each(defaultValidators, function(validator, key){ - defaultValidators[key] = _.bind(defaultValidators[key], _.extend({}, formatFunctions, defaultValidators)); - }); - - return Validation; -}(_)); \ No newline at end of file diff --git a/client/src/js/vendor/backbone/backbone.babysitter.js b/client/src/js/vendor/backbone/backbone.babysitter.js deleted file mode 100644 index eeb92a2fd..000000000 --- a/client/src/js/vendor/backbone/backbone.babysitter.js +++ /dev/null @@ -1,190 +0,0 @@ -// Backbone.BabySitter -// ------------------- -// v0.1.4 -// -// Copyright (c)2014 Derick Bailey, Muted Solutions, LLC. -// Distributed under MIT license -// -// http://github.com/marionettejs/backbone.babysitter - -(function(root, factory) { - - if (typeof define === 'function' && define.amd) { - define(['backbone', 'underscore'], function(Backbone, _) { - return factory(Backbone, _); - }); - } else if (typeof exports !== 'undefined') { - var Backbone = require('backbone'); - var _ = require('underscore'); - module.exports = factory(Backbone, _); - } else { - factory(root.Backbone, root._); - } - -}(this, function(Backbone, _) { - 'use strict'; - - var previousChildViewContainer = Backbone.ChildViewContainer; - - // BabySitter.ChildViewContainer - // ----------------------------- - // - // Provide a container to store, retrieve and - // shut down child views. - - Backbone.ChildViewContainer = (function (Backbone, _) { - - // Container Constructor - // --------------------- - - var Container = function(views){ - this._views = {}; - this._indexByModel = {}; - this._indexByCustom = {}; - this._updateLength(); - - _.each(views, this.add, this); - }; - - // Container Methods - // ----------------- - - _.extend(Container.prototype, { - - // Add a view to this container. Stores the view - // by `cid` and makes it searchable by the model - // cid (and model itself). Optionally specify - // a custom key to store an retrieve the view. - add: function(view, customIndex){ - var viewCid = view.cid; - - // store the view - this._views[viewCid] = view; - - // index it by model - if (view.model){ - this._indexByModel[view.model.cid] = viewCid; - } - - // index by custom - if (customIndex){ - this._indexByCustom[customIndex] = viewCid; - } - - this._updateLength(); - return this; - }, - - // Find a view by the model that was attached to - // it. Uses the model's `cid` to find it. - findByModel: function(model){ - return this.findByModelCid(model.cid); - }, - - // Find a view by the `cid` of the model that was attached to - // it. Uses the model's `cid` to find the view `cid` and - // retrieve the view using it. - findByModelCid: function(modelCid){ - var viewCid = this._indexByModel[modelCid]; - return this.findByCid(viewCid); - }, - - // Find a view by a custom indexer. - findByCustom: function(index){ - var viewCid = this._indexByCustom[index]; - return this.findByCid(viewCid); - }, - - // Find by index. This is not guaranteed to be a - // stable index. - findByIndex: function(index){ - return _.values(this._views)[index]; - }, - - // retrieve a view by its `cid` directly - findByCid: function(cid){ - return this._views[cid]; - }, - - // Remove a view - remove: function(view){ - var viewCid = view.cid; - - // delete model index - if (view.model){ - delete this._indexByModel[view.model.cid]; - } - - // delete custom index - _.any(this._indexByCustom, function(cid, key) { - if (cid === viewCid) { - delete this._indexByCustom[key]; - return true; - } - }, this); - - // remove the view from the container - delete this._views[viewCid]; - - // update the length - this._updateLength(); - return this; - }, - - // Call a method on every view in the container, - // passing parameters to the call method one at a - // time, like `function.call`. - call: function(method){ - this.apply(method, _.tail(arguments)); - }, - - // Apply a method on every view in the container, - // passing parameters to the call method one at a - // time, like `function.apply`. - apply: function(method, args){ - _.each(this._views, function(view){ - if (_.isFunction(view[method])){ - view[method].apply(view, args || []); - } - }); - }, - - // Update the `.length` attribute on this container - _updateLength: function(){ - this.length = _.size(this._views); - } - }); - - // Borrowing this code from Backbone.Collection: - // http://backbonejs.org/docs/backbone.html#section-106 - // - // Mix in methods from Underscore, for iteration, and other - // collection related features. - var methods = ['forEach', 'each', 'map', 'find', 'detect', 'filter', - 'select', 'reject', 'every', 'all', 'some', 'any', 'include', - 'contains', 'invoke', 'toArray', 'first', 'initial', 'rest', - 'last', 'without', 'isEmpty', 'pluck']; - - _.each(methods, function(method) { - Container.prototype[method] = function() { - var views = _.values(this._views); - var args = [views].concat(_.toArray(arguments)); - return _[method].apply(_, args); - }; - }); - - // return the public API - return Container; - })(Backbone, _); - - - Backbone.ChildViewContainer.VERSION = '0.1.4'; - - Backbone.ChildViewContainer.noConflict = function () { - Backbone.ChildViewContainer = previousChildViewContainer; - return this; - }; - - return Backbone.ChildViewContainer; - -})); diff --git a/client/src/js/vendor/backbone/backbone.js b/client/src/js/vendor/backbone/backbone.js deleted file mode 100644 index 24a550a0a..000000000 --- a/client/src/js/vendor/backbone/backbone.js +++ /dev/null @@ -1,1608 +0,0 @@ -// Backbone.js 1.1.2 - -// (c) 2010-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors -// Backbone may be freely distributed under the MIT license. -// For all details and documentation: -// http://backbonejs.org - -(function(root, factory) { - - // Set up Backbone appropriately for the environment. Start with AMD. - if (typeof define === 'function' && define.amd) { - define(['underscore', 'jquery', 'exports'], function(_, $, exports) { - // Export global even in AMD case in case this script is loaded with - // others that may still expect a global Backbone. - root.Backbone = factory(root, exports, _, $); - }); - - // Next for Node.js or CommonJS. jQuery may not be needed as a module. - } else if (typeof exports !== 'undefined') { - var _ = require('underscore'); - factory(root, exports, _); - - // Finally, as a browser global. - } else { - root.Backbone = factory(root, {}, root._, (root.jQuery || root.Zepto || root.ender || root.$)); - } - -}(this, function(root, Backbone, _, $) { - - // Initial Setup - // ------------- - - // Save the previous value of the `Backbone` variable, so that it can be - // restored later on, if `noConflict` is used. - var previousBackbone = root.Backbone; - - // Create local references to array methods we'll want to use later. - var array = []; - var push = array.push; - var slice = array.slice; - var splice = array.splice; - - // Current version of the library. Keep in sync with `package.json`. - Backbone.VERSION = '1.1.2'; - - // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns - // the `$` variable. - Backbone.$ = $; - - // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable - // to its previous owner. Returns a reference to this Backbone object. - Backbone.noConflict = function() { - root.Backbone = previousBackbone; - return this; - }; - - // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option - // will fake `"PATCH"`, `"PUT"` and `"DELETE"` requests via the `_method` parameter and - // set a `X-Http-Method-Override` header. - Backbone.emulateHTTP = false; - - // Turn on `emulateJSON` to support legacy servers that can't deal with direct - // `application/json` requests ... will encode the body as - // `application/x-www-form-urlencoded` instead and will send the model in a - // form param named `model`. - Backbone.emulateJSON = false; - - // Backbone.Events - // --------------- - - // A module that can be mixed in to *any object* in order to provide it with - // custom events. You may bind with `on` or remove with `off` callback - // functions to an event; `trigger`-ing an event fires all callbacks in - // succession. - // - // var object = {}; - // _.extend(object, Backbone.Events); - // object.on('expand', function(){ alert('expanded'); }); - // object.trigger('expand'); - // - var Events = Backbone.Events = { - - // Bind an event to a `callback` function. Passing `"all"` will bind - // the callback to all events fired. - on: function(name, callback, context) { - if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this; - this._events || (this._events = {}); - var events = this._events[name] || (this._events[name] = []); - events.push({callback: callback, context: context, ctx: context || this}); - return this; - }, - - // Bind an event to only be triggered a single time. After the first time - // the callback is invoked, it will be removed. - once: function(name, callback, context) { - if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this; - var self = this; - var once = _.once(function() { - self.off(name, once); - callback.apply(this, arguments); - }); - once._callback = callback; - return this.on(name, once, context); - }, - - // Remove one or many callbacks. If `context` is null, removes all - // callbacks with that function. If `callback` is null, removes all - // callbacks for the event. If `name` is null, removes all bound - // callbacks for all events. - off: function(name, callback, context) { - var retain, ev, events, names, i, l, j, k; - if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this; - if (!name && !callback && !context) { - this._events = void 0; - return this; - } - names = name ? [name] : _.keys(this._events); - for (i = 0, l = names.length; i < l; i++) { - name = names[i]; - if (events = this._events[name]) { - this._events[name] = retain = []; - if (callback || context) { - for (j = 0, k = events.length; j < k; j++) { - ev = events[j]; - if ((callback && callback !== ev.callback && callback !== ev.callback._callback) || - (context && context !== ev.context)) { - retain.push(ev); - } - } - } - if (!retain.length) delete this._events[name]; - } - } - - return this; - }, - - // Trigger one or many events, firing all bound callbacks. Callbacks are - // passed the same arguments as `trigger` is, apart from the event name - // (unless you're listening on `"all"`, which will cause your callback to - // receive the true name of the event as the first argument). - trigger: function(name) { - if (!this._events) return this; - var args = slice.call(arguments, 1); - if (!eventsApi(this, 'trigger', name, args)) return this; - var events = this._events[name]; - var allEvents = this._events.all; - if (events) triggerEvents(events, args); - if (allEvents) triggerEvents(allEvents, arguments); - return this; - }, - - // Tell this object to stop listening to either specific events ... or - // to every object it's currently listening to. - stopListening: function(obj, name, callback) { - var listeningTo = this._listeningTo; - if (!listeningTo) return this; - var remove = !name && !callback; - if (!callback && typeof name === 'object') callback = this; - if (obj) (listeningTo = {})[obj._listenId] = obj; - for (var id in listeningTo) { - obj = listeningTo[id]; - obj.off(name, callback, this); - if (remove || _.isEmpty(obj._events)) delete this._listeningTo[id]; - } - return this; - } - - }; - - // Regular expression used to split event strings. - var eventSplitter = /\s+/; - - // Implement fancy features of the Events API such as multiple event - // names `"change blur"` and jQuery-style event maps `{change: action}` - // in terms of the existing API. - var eventsApi = function(obj, action, name, rest) { - if (!name) return true; - - // Handle event maps. - if (typeof name === 'object') { - for (var key in name) { - obj[action].apply(obj, [key, name[key]].concat(rest)); - } - return false; - } - - // Handle space separated event names. - if (eventSplitter.test(name)) { - var names = name.split(eventSplitter); - for (var i = 0, l = names.length; i < l; i++) { - obj[action].apply(obj, [names[i]].concat(rest)); - } - return false; - } - - return true; - }; - - // A difficult-to-believe, but optimized internal dispatch function for - // triggering events. Tries to keep the usual cases speedy (most internal - // Backbone events have 3 arguments). - var triggerEvents = function(events, args) { - var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2]; - switch (args.length) { - case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return; - case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return; - case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return; - case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return; - default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return; - } - }; - - var listenMethods = {listenTo: 'on', listenToOnce: 'once'}; - - // Inversion-of-control versions of `on` and `once`. Tell *this* object to - // listen to an event in another object ... keeping track of what it's - // listening to. - _.each(listenMethods, function(implementation, method) { - Events[method] = function(obj, name, callback) { - var listeningTo = this._listeningTo || (this._listeningTo = {}); - var id = obj._listenId || (obj._listenId = _.uniqueId('l')); - listeningTo[id] = obj; - if (!callback && typeof name === 'object') callback = this; - obj[implementation](name, callback, this); - return this; - }; - }); - - // Aliases for backwards compatibility. - Events.bind = Events.on; - Events.unbind = Events.off; - - // Allow the `Backbone` object to serve as a global event bus, for folks who - // want global "pubsub" in a convenient place. - _.extend(Backbone, Events); - - // Backbone.Model - // -------------- - - // Backbone **Models** are the basic data object in the framework -- - // frequently representing a row in a table in a database on your server. - // A discrete chunk of data and a bunch of useful, related methods for - // performing computations and transformations on that data. - - // Create a new model with the specified attributes. A client id (`cid`) - // is automatically generated and assigned for you. - var Model = Backbone.Model = function(attributes, options) { - var attrs = attributes || {}; - options || (options = {}); - this.cid = _.uniqueId('c'); - this.attributes = {}; - if (options.collection) this.collection = options.collection; - if (options.parse) attrs = this.parse(attrs, options) || {}; - attrs = _.defaults({}, attrs, _.result(this, 'defaults')); - this.set(attrs, options); - this.changed = {}; - this.initialize.apply(this, arguments); - }; - - // Attach all inheritable methods to the Model prototype. - _.extend(Model.prototype, Events, { - - // A hash of attributes whose current and previous value differ. - changed: null, - - // The value returned during the last failed validation. - validationError: null, - - // The default name for the JSON `id` attribute is `"id"`. MongoDB and - // CouchDB users may want to set this to `"_id"`. - idAttribute: 'id', - - // Initialize is an empty function by default. Override it with your own - // initialization logic. - initialize: function(){}, - - // Return a copy of the model's `attributes` object. - toJSON: function(options) { - return _.clone(this.attributes); - }, - - // Proxy `Backbone.sync` by default -- but override this if you need - // custom syncing semantics for *this* particular model. - sync: function() { - return Backbone.sync.apply(this, arguments); - }, - - // Get the value of an attribute. - get: function(attr) { - return this.attributes[attr]; - }, - - // Get the HTML-escaped value of an attribute. - escape: function(attr) { - return _.escape(this.get(attr)); - }, - - // Returns `true` if the attribute contains a value that is not null - // or undefined. - has: function(attr) { - return this.get(attr) != null; - }, - - // Set a hash of model attributes on the object, firing `"change"`. This is - // the core primitive operation of a model, updating the data and notifying - // anyone who needs to know about the change in state. The heart of the beast. - set: function(key, val, options) { - var attr, attrs, unset, changes, silent, changing, prev, current; - if (key == null) return this; - - // Handle both `"key", value` and `{key: value}` -style arguments. - if (typeof key === 'object') { - attrs = key; - options = val; - } else { - (attrs = {})[key] = val; - } - - options || (options = {}); - - // Run validation. - if (!this._validate(attrs, options)) return false; - - // Extract attributes and options. - unset = options.unset; - silent = options.silent; - changes = []; - changing = this._changing; - this._changing = true; - - if (!changing) { - this._previousAttributes = _.clone(this.attributes); - this.changed = {}; - } - current = this.attributes, prev = this._previousAttributes; - - // Check for changes of `id`. - if (this.idAttribute in attrs) this.id = attrs[this.idAttribute]; - - // For each `set` attribute, update or delete the current value. - for (attr in attrs) { - val = attrs[attr]; - if (!_.isEqual(current[attr], val)) changes.push(attr); - if (!_.isEqual(prev[attr], val)) { - this.changed[attr] = val; - } else { - delete this.changed[attr]; - } - unset ? delete current[attr] : current[attr] = val; - } - - // Trigger all relevant attribute changes. - if (!silent) { - if (changes.length) this._pending = options; - for (var i = 0, l = changes.length; i < l; i++) { - this.trigger('change:' + changes[i], this, current[changes[i]], options); - } - } - - // You might be wondering why there's a `while` loop here. Changes can - // be recursively nested within `"change"` events. - if (changing) return this; - if (!silent) { - while (this._pending) { - options = this._pending; - this._pending = false; - this.trigger('change', this, options); - } - } - this._pending = false; - this._changing = false; - return this; - }, - - // Remove an attribute from the model, firing `"change"`. `unset` is a noop - // if the attribute doesn't exist. - unset: function(attr, options) { - return this.set(attr, void 0, _.extend({}, options, {unset: true})); - }, - - // Clear all attributes on the model, firing `"change"`. - clear: function(options) { - var attrs = {}; - for (var key in this.attributes) attrs[key] = void 0; - return this.set(attrs, _.extend({}, options, {unset: true})); - }, - - // Determine if the model has changed since the last `"change"` event. - // If you specify an attribute name, determine if that attribute has changed. - hasChanged: function(attr) { - if (attr == null) return !_.isEmpty(this.changed); - return _.has(this.changed, attr); - }, - - // Return an object containing all the attributes that have changed, or - // false if there are no changed attributes. Useful for determining what - // parts of a view need to be updated and/or what attributes need to be - // persisted to the server. Unset attributes will be set to undefined. - // You can also pass an attributes object to diff against the model, - // determining if there *would be* a change. - changedAttributes: function(diff) { - if (!diff) return this.hasChanged() ? _.clone(this.changed) : false; - var val, changed = false; - var old = this._changing ? this._previousAttributes : this.attributes; - for (var attr in diff) { - if (_.isEqual(old[attr], (val = diff[attr]))) continue; - (changed || (changed = {}))[attr] = val; - } - return changed; - }, - - // Get the previous value of an attribute, recorded at the time the last - // `"change"` event was fired. - previous: function(attr) { - if (attr == null || !this._previousAttributes) return null; - return this._previousAttributes[attr]; - }, - - // Get all of the attributes of the model at the time of the previous - // `"change"` event. - previousAttributes: function() { - return _.clone(this._previousAttributes); - }, - - // Fetch the model from the server. If the server's representation of the - // model differs from its current attributes, they will be overridden, - // triggering a `"change"` event. - fetch: function(options) { - options = options ? _.clone(options) : {}; - if (options.parse === void 0) options.parse = true; - var model = this; - var success = options.success; - options.success = function(resp) { - if (!model.set(model.parse(resp, options), options)) return false; - if (success) success(model, resp, options); - model.trigger('sync', model, resp, options); - }; - wrapError(this, options); - return this.sync('read', this, options); - }, - - // Set a hash of model attributes, and sync the model to the server. - // If the server returns an attributes hash that differs, the model's - // state will be `set` again. - save: function(key, val, options) { - var attrs, method, xhr, attributes = this.attributes; - - // Handle both `"key", value` and `{key: value}` -style arguments. - if (key == null || typeof key === 'object') { - attrs = key; - options = val; - } else { - (attrs = {})[key] = val; - } - - options = _.extend({validate: true}, options); - - // If we're not waiting and attributes exist, save acts as - // `set(attr).save(null, opts)` with validation. Otherwise, check if - // the model will be valid when the attributes, if any, are set. - if (attrs && !options.wait) { - if (!this.set(attrs, options)) return false; - } else { - if (!this._validate(attrs, options)) return false; - } - - // Set temporary attributes if `{wait: true}`. - if (attrs && options.wait) { - this.attributes = _.extend({}, attributes, attrs); - } - - // After a successful server-side save, the client is (optionally) - // updated with the server-side state. - if (options.parse === void 0) options.parse = true; - var model = this; - var success = options.success; - options.success = function(resp) { - // Ensure attributes are restored during synchronous saves. - model.attributes = attributes; - var serverAttrs = model.parse(resp, options); - if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs); - if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) { - return false; - } - if (success) success(model, resp, options); - model.trigger('sync', model, resp, options); - }; - wrapError(this, options); - - method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update'); - if (method === 'patch') options.attrs = attrs; - xhr = this.sync(method, this, options); - - // Restore attributes. - if (attrs && options.wait) this.attributes = attributes; - - return xhr; - }, - - // Destroy this model on the server if it was already persisted. - // Optimistically removes the model from its collection, if it has one. - // If `wait: true` is passed, waits for the server to respond before removal. - destroy: function(options) { - options = options ? _.clone(options) : {}; - var model = this; - var success = options.success; - - var destroy = function() { - model.trigger('destroy', model, model.collection, options); - }; - - options.success = function(resp) { - if (options.wait || model.isNew()) destroy(); - if (success) success(model, resp, options); - if (!model.isNew()) model.trigger('sync', model, resp, options); - }; - - if (this.isNew()) { - options.success(); - return false; - } - wrapError(this, options); - - var xhr = this.sync('delete', this, options); - if (!options.wait) destroy(); - return xhr; - }, - - // Default URL for the model's representation on the server -- if you're - // using Backbone's restful methods, override this to change the endpoint - // that will be called. - url: function() { - var base = - _.result(this, 'urlRoot') || - _.result(this.collection, 'url') || - urlError(); - if (this.isNew()) return base; - return base.replace(/([^\/])$/, '$1/') + encodeURIComponent(this.id); - }, - - // **parse** converts a response into the hash of attributes to be `set` on - // the model. The default implementation is just to pass the response along. - parse: function(resp, options) { - return resp; - }, - - // Create a new model with identical attributes to this one. - clone: function() { - return new this.constructor(this.attributes); - }, - - // A model is new if it has never been saved to the server, and lacks an id. - isNew: function() { - return !this.has(this.idAttribute); - }, - - // Check if the model is currently in a valid state. - isValid: function(options) { - return this._validate({}, _.extend(options || {}, { validate: true })); - }, - - // Run validation against the next complete set of model attributes, - // returning `true` if all is well. Otherwise, fire an `"invalid"` event. - _validate: function(attrs, options) { - if (!options.validate || !this.validate) return true; - attrs = _.extend({}, this.attributes, attrs); - var error = this.validationError = this.validate(attrs, options) || null; - if (!error) return true; - this.trigger('invalid', this, error, _.extend(options, {validationError: error})); - return false; - } - - }); - - // Underscore methods that we want to implement on the Model. - var modelMethods = ['keys', 'values', 'pairs', 'invert', 'pick', 'omit']; - - // Mix in each Underscore method as a proxy to `Model#attributes`. - _.each(modelMethods, function(method) { - Model.prototype[method] = function() { - var args = slice.call(arguments); - args.unshift(this.attributes); - return _[method].apply(_, args); - }; - }); - - // Backbone.Collection - // ------------------- - - // If models tend to represent a single row of data, a Backbone Collection is - // more analagous to a table full of data ... or a small slice or page of that - // table, or a collection of rows that belong together for a particular reason - // -- all of the messages in this particular folder, all of the documents - // belonging to this particular author, and so on. Collections maintain - // indexes of their models, both in order, and for lookup by `id`. - - // Create a new **Collection**, perhaps to contain a specific type of `model`. - // If a `comparator` is specified, the Collection will maintain - // its models in sort order, as they're added and removed. - var Collection = Backbone.Collection = function(models, options) { - options || (options = {}); - if (options.model) this.model = options.model; - if (options.comparator !== void 0) this.comparator = options.comparator; - this._reset(); - this.initialize.apply(this, arguments); - if (models) this.reset(models, _.extend({silent: true}, options)); - }; - - // Default options for `Collection#set`. - var setOptions = {add: true, remove: true, merge: true}; - var addOptions = {add: true, remove: false}; - - // Define the Collection's inheritable methods. - _.extend(Collection.prototype, Events, { - - // The default model for a collection is just a **Backbone.Model**. - // This should be overridden in most cases. - model: Model, - - // Initialize is an empty function by default. Override it with your own - // initialization logic. - initialize: function(){}, - - // The JSON representation of a Collection is an array of the - // models' attributes. - toJSON: function(options) { - return this.map(function(model){ return model.toJSON(options); }); - }, - - // Proxy `Backbone.sync` by default. - sync: function() { - return Backbone.sync.apply(this, arguments); - }, - - // Add a model, or list of models to the set. - add: function(models, options) { - return this.set(models, _.extend({merge: false}, options, addOptions)); - }, - - // Remove a model, or a list of models from the set. - remove: function(models, options) { - var singular = !_.isArray(models); - models = singular ? [models] : _.clone(models); - options || (options = {}); - var i, l, index, model; - for (i = 0, l = models.length; i < l; i++) { - model = models[i] = this.get(models[i]); - if (!model) continue; - delete this._byId[model.id]; - delete this._byId[model.cid]; - index = this.indexOf(model); - this.models.splice(index, 1); - this.length--; - if (!options.silent) { - options.index = index; - model.trigger('remove', model, this, options); - } - this._removeReference(model, options); - } - return singular ? models[0] : models; - }, - - // Update a collection by `set`-ing a new list of models, adding new ones, - // removing models that are no longer present, and merging models that - // already exist in the collection, as necessary. Similar to **Model#set**, - // the core operation for updating the data contained by the collection. - set: function(models, options) { - options = _.defaults({}, options, setOptions); - if (options.parse) models = this.parse(models, options); - var singular = !_.isArray(models); - models = singular ? (models ? [models] : []) : _.clone(models); - var i, l, id, model, attrs, existing, sort; - var at = options.at; - var targetModel = this.model; - var sortable = this.comparator && (at == null) && options.sort !== false; - var sortAttr = _.isString(this.comparator) ? this.comparator : null; - var toAdd = [], toRemove = [], modelMap = {}; - var add = options.add, merge = options.merge, remove = options.remove; - var order = !sortable && add && remove ? [] : false; - - // Turn bare objects into model references, and prevent invalid models - // from being added. - for (i = 0, l = models.length; i < l; i++) { - attrs = models[i] || {}; - if (attrs instanceof Model) { - id = model = attrs; - } else { - id = attrs[targetModel.prototype.idAttribute || 'id']; - } - - // If a duplicate is found, prevent it from being added and - // optionally merge it into the existing model. - if (existing = this.get(id)) { - if (remove) modelMap[existing.cid] = true; - if (merge) { - attrs = attrs === model ? model.attributes : attrs; - if (options.parse) attrs = existing.parse(attrs, options); - existing.set(attrs, options); - if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true; - } - models[i] = existing; - - // If this is a new, valid model, push it to the `toAdd` list. - } else if (add) { - model = models[i] = this._prepareModel(attrs, options); - if (!model) continue; - toAdd.push(model); - this._addReference(model, options); - } - - // Do not add multiple models with the same `id`. - model = existing || model; - if (order && (model.isNew() || !modelMap[model.id])) order.push(model); - modelMap[model.id] = true; - } - - // Remove nonexistent models if appropriate. - if (remove) { - for (i = 0, l = this.length; i < l; ++i) { - if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model); - } - if (toRemove.length) this.remove(toRemove, options); - } - - // See if sorting is needed, update `length` and splice in new models. - if (toAdd.length || (order && order.length)) { - if (sortable) sort = true; - this.length += toAdd.length; - if (at != null) { - for (i = 0, l = toAdd.length; i < l; i++) { - this.models.splice(at + i, 0, toAdd[i]); - } - } else { - if (order) this.models.length = 0; - var orderedModels = order || toAdd; - for (i = 0, l = orderedModels.length; i < l; i++) { - this.models.push(orderedModels[i]); - } - } - } - - // Silently sort the collection if appropriate. - if (sort) this.sort({silent: true}); - - // Unless silenced, it's time to fire all appropriate add/sort events. - if (!options.silent) { - for (i = 0, l = toAdd.length; i < l; i++) { - (model = toAdd[i]).trigger('add', model, this, options); - } - if (sort || (order && order.length)) this.trigger('sort', this, options); - } - - // Return the added (or merged) model (or models). - return singular ? models[0] : models; - }, - - // When you have more items than you want to add or remove individually, - // you can reset the entire set with a new list of models, without firing - // any granular `add` or `remove` events. Fires `reset` when finished. - // Useful for bulk operations and optimizations. - reset: function(models, options) { - options || (options = {}); - for (var i = 0, l = this.models.length; i < l; i++) { - this._removeReference(this.models[i], options); - } - options.previousModels = this.models; - this._reset(); - models = this.add(models, _.extend({silent: true}, options)); - if (!options.silent) this.trigger('reset', this, options); - return models; - }, - - // Add a model to the end of the collection. - push: function(model, options) { - return this.add(model, _.extend({at: this.length}, options)); - }, - - // Remove a model from the end of the collection. - pop: function(options) { - var model = this.at(this.length - 1); - this.remove(model, options); - return model; - }, - - // Add a model to the beginning of the collection. - unshift: function(model, options) { - return this.add(model, _.extend({at: 0}, options)); - }, - - // Remove a model from the beginning of the collection. - shift: function(options) { - var model = this.at(0); - this.remove(model, options); - return model; - }, - - // Slice out a sub-array of models from the collection. - slice: function() { - return slice.apply(this.models, arguments); - }, - - // Get a model from the set by id. - get: function(obj) { - if (obj == null) return void 0; - return this._byId[obj] || this._byId[obj.id] || this._byId[obj.cid]; - }, - - // Get the model at the given index. - at: function(index) { - return this.models[index]; - }, - - // Return models with matching attributes. Useful for simple cases of - // `filter`. - where: function(attrs, first) { - if (_.isEmpty(attrs)) return first ? void 0 : []; - return this[first ? 'find' : 'filter'](function(model) { - for (var key in attrs) { - if (attrs[key] !== model.get(key)) return false; - } - return true; - }); - }, - - // Return the first model with matching attributes. Useful for simple cases - // of `find`. - findWhere: function(attrs) { - return this.where(attrs, true); - }, - - // Force the collection to re-sort itself. You don't need to call this under - // normal circumstances, as the set will maintain sort order as each item - // is added. - sort: function(options) { - if (!this.comparator) throw new Error('Cannot sort a set without a comparator'); - options || (options = {}); - - // Run sort based on type of `comparator`. - if (_.isString(this.comparator) || this.comparator.length === 1) { - this.models = this.sortBy(this.comparator, this); - } else { - this.models.sort(_.bind(this.comparator, this)); - } - - if (!options.silent) this.trigger('sort', this, options); - return this; - }, - - // Pluck an attribute from each model in the collection. - pluck: function(attr) { - return _.invoke(this.models, 'get', attr); - }, - - // Fetch the default set of models for this collection, resetting the - // collection when they arrive. If `reset: true` is passed, the response - // data will be passed through the `reset` method instead of `set`. - fetch: function(options) { - options = options ? _.clone(options) : {}; - if (options.parse === void 0) options.parse = true; - var success = options.success; - var collection = this; - options.success = function(resp) { - var method = options.reset ? 'reset' : 'set'; - collection[method](resp, options); - if (success) success(collection, resp, options); - collection.trigger('sync', collection, resp, options); - }; - wrapError(this, options); - return this.sync('read', this, options); - }, - - // Create a new instance of a model in this collection. Add the model to the - // collection immediately, unless `wait: true` is passed, in which case we - // wait for the server to agree. - create: function(model, options) { - options = options ? _.clone(options) : {}; - if (!(model = this._prepareModel(model, options))) return false; - if (!options.wait) this.add(model, options); - var collection = this; - var success = options.success; - options.success = function(model, resp) { - if (options.wait) collection.add(model, options); - if (success) success(model, resp, options); - }; - model.save(null, options); - return model; - }, - - // **parse** converts a response into a list of models to be added to the - // collection. The default implementation is just to pass it through. - parse: function(resp, options) { - return resp; - }, - - // Create a new collection with an identical list of models as this one. - clone: function() { - return new this.constructor(this.models); - }, - - // Private method to reset all internal state. Called when the collection - // is first initialized or reset. - _reset: function() { - this.length = 0; - this.models = []; - this._byId = {}; - }, - - // Prepare a hash of attributes (or other model) to be added to this - // collection. - _prepareModel: function(attrs, options) { - if (attrs instanceof Model) return attrs; - options = options ? _.clone(options) : {}; - options.collection = this; - var model = new this.model(attrs, options); - if (!model.validationError) return model; - this.trigger('invalid', this, model.validationError, options); - return false; - }, - - // Internal method to create a model's ties to a collection. - _addReference: function(model, options) { - this._byId[model.cid] = model; - if (model.id != null) this._byId[model.id] = model; - if (!model.collection) model.collection = this; - model.on('all', this._onModelEvent, this); - }, - - // Internal method to sever a model's ties to a collection. - _removeReference: function(model, options) { - if (this === model.collection) delete model.collection; - model.off('all', this._onModelEvent, this); - }, - - // Internal method called every time a model in the set fires an event. - // Sets need to update their indexes when models change ids. All other - // events simply proxy through. "add" and "remove" events that originate - // in other collections are ignored. - _onModelEvent: function(event, model, collection, options) { - if ((event === 'add' || event === 'remove') && collection !== this) return; - if (event === 'destroy') this.remove(model, options); - if (model && event === 'change:' + model.idAttribute) { - delete this._byId[model.previous(model.idAttribute)]; - if (model.id != null) this._byId[model.id] = model; - } - this.trigger.apply(this, arguments); - } - - }); - - // Underscore methods that we want to implement on the Collection. - // 90% of the core usefulness of Backbone Collections is actually implemented - // right here: - var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl', - 'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select', - 'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke', - 'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest', - 'tail', 'drop', 'last', 'without', 'difference', 'indexOf', 'shuffle', - 'lastIndexOf', 'isEmpty', 'chain', 'sample']; - - // Mix in each Underscore method as a proxy to `Collection#models`. - _.each(methods, function(method) { - Collection.prototype[method] = function() { - var args = slice.call(arguments); - args.unshift(this.models); - return _[method].apply(_, args); - }; - }); - - // Underscore methods that take a property name as an argument. - var attributeMethods = ['groupBy', 'countBy', 'sortBy', 'indexBy']; - - // Use attributes instead of properties. - _.each(attributeMethods, function(method) { - Collection.prototype[method] = function(value, context) { - var iterator = _.isFunction(value) ? value : function(model) { - return model.get(value); - }; - return _[method](this.models, iterator, context); - }; - }); - - // Backbone.View - // ------------- - - // Backbone Views are almost more convention than they are actual code. A View - // is simply a JavaScript object that represents a logical chunk of UI in the - // DOM. This might be a single item, an entire list, a sidebar or panel, or - // even the surrounding frame which wraps your whole app. Defining a chunk of - // UI as a **View** allows you to define your DOM events declaratively, without - // having to worry about render order ... and makes it easy for the view to - // react to specific changes in the state of your models. - - // Creating a Backbone.View creates its initial element outside of the DOM, - // if an existing element is not provided... - var View = Backbone.View = function(options) { - this.cid = _.uniqueId('view'); - options || (options = {}); - _.extend(this, _.pick(options, viewOptions)); - this._ensureElement(); - this.initialize.apply(this, arguments); - this.delegateEvents(); - }; - - // Cached regex to split keys for `delegate`. - var delegateEventSplitter = /^(\S+)\s*(.*)$/; - - // List of view options to be merged as properties. - var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events']; - - // Set up all inheritable **Backbone.View** properties and methods. - _.extend(View.prototype, Events, { - - // The default `tagName` of a View's element is `"div"`. - tagName: 'div', - - // jQuery delegate for element lookup, scoped to DOM elements within the - // current view. This should be preferred to global lookups where possible. - $: function(selector) { - return this.$el.find(selector); - }, - - // Initialize is an empty function by default. Override it with your own - // initialization logic. - initialize: function(){}, - - // **render** is the core function that your view should override, in order - // to populate its element (`this.el`), with the appropriate HTML. The - // convention is for **render** to always return `this`. - render: function() { - return this; - }, - - // Remove this view by taking the element out of the DOM, and removing any - // applicable Backbone.Events listeners. - remove: function() { - this.$el.remove(); - this.stopListening(); - return this; - }, - - // Change the view's element (`this.el` property), including event - // re-delegation. - setElement: function(element, delegate) { - if (this.$el) this.undelegateEvents(); - this.$el = element instanceof Backbone.$ ? element : Backbone.$(element); - this.el = this.$el[0]; - if (delegate !== false) this.delegateEvents(); - return this; - }, - - // Set callbacks, where `this.events` is a hash of - // - // *{"event selector": "callback"}* - // - // { - // 'mousedown .title': 'edit', - // 'click .button': 'save', - // 'click .open': function(e) { ... } - // } - // - // pairs. Callbacks will be bound to the view, with `this` set properly. - // Uses event delegation for efficiency. - // Omitting the selector binds the event to `this.el`. - // This only works for delegate-able events: not `focus`, `blur`, and - // not `change`, `submit`, and `reset` in Internet Explorer. - delegateEvents: function(events) { - if (!(events || (events = _.result(this, 'events')))) return this; - this.undelegateEvents(); - for (var key in events) { - var method = events[key]; - if (!_.isFunction(method)) method = this[events[key]]; - if (!method) continue; - - var match = key.match(delegateEventSplitter); - var eventName = match[1], selector = match[2]; - method = _.bind(method, this); - eventName += '.delegateEvents' + this.cid; - if (selector === '') { - this.$el.on(eventName, method); - } else { - this.$el.on(eventName, selector, method); - } - } - return this; - }, - - // Clears all callbacks previously bound to the view with `delegateEvents`. - // You usually don't need to use this, but may wish to if you have multiple - // Backbone views attached to the same DOM element. - undelegateEvents: function() { - this.$el.off('.delegateEvents' + this.cid); - return this; - }, - - // Ensure that the View has a DOM element to render into. - // If `this.el` is a string, pass it through `$()`, take the first - // matching element, and re-assign it to `el`. Otherwise, create - // an element from the `id`, `className` and `tagName` properties. - _ensureElement: function() { - if (!this.el) { - var attrs = _.extend({}, _.result(this, 'attributes')); - if (this.id) attrs.id = _.result(this, 'id'); - if (this.className) attrs['class'] = _.result(this, 'className'); - var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs); - this.setElement($el, false); - } else { - this.setElement(_.result(this, 'el'), false); - } - } - - }); - - // Backbone.sync - // ------------- - - // Override this function to change the manner in which Backbone persists - // models to the server. You will be passed the type of request, and the - // model in question. By default, makes a RESTful Ajax request - // to the model's `url()`. Some possible customizations could be: - // - // * Use `setTimeout` to batch rapid-fire updates into a single request. - // * Send up the models as XML instead of JSON. - // * Persist models via WebSockets instead of Ajax. - // - // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests - // as `POST`, with a `_method` parameter containing the true HTTP method, - // as well as all requests with the body as `application/x-www-form-urlencoded` - // instead of `application/json` with the model in a param named `model`. - // Useful when interfacing with server-side languages like **PHP** that make - // it difficult to read the body of `PUT` requests. - Backbone.sync = function(method, model, options) { - var type = methodMap[method]; - - // Default options, unless specified. - _.defaults(options || (options = {}), { - emulateHTTP: Backbone.emulateHTTP, - emulateJSON: Backbone.emulateJSON - }); - - // Default JSON-request options. - var params = {type: type, dataType: 'json'}; - - // Ensure that we have a URL. - if (!options.url) { - params.url = _.result(model, 'url') || urlError(); - } - - // Ensure that we have the appropriate request data. - if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) { - params.contentType = 'application/json'; - params.data = JSON.stringify(options.attrs || model.toJSON(options)); - } - - // For older servers, emulate JSON by encoding the request into an HTML-form. - if (options.emulateJSON) { - params.contentType = 'application/x-www-form-urlencoded'; - params.data = params.data ? {model: params.data} : {}; - } - - // For older servers, emulate HTTP by mimicking the HTTP method with `_method` - // And an `X-HTTP-Method-Override` header. - if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) { - params.type = 'POST'; - if (options.emulateJSON) params.data._method = type; - var beforeSend = options.beforeSend; - options.beforeSend = function(xhr) { - xhr.setRequestHeader('X-HTTP-Method-Override', type); - if (beforeSend) return beforeSend.apply(this, arguments); - }; - } - - // Don't process data on a non-GET request. - if (params.type !== 'GET' && !options.emulateJSON) { - params.processData = false; - } - - // If we're sending a `PATCH` request, and we're in an old Internet Explorer - // that still has ActiveX enabled by default, override jQuery to use that - // for XHR instead. Remove this line when jQuery supports `PATCH` on IE8. - if (params.type === 'PATCH' && noXhrPatch) { - params.xhr = function() { - return new ActiveXObject("Microsoft.XMLHTTP"); - }; - } - - // Make the request, allowing the user to override any Ajax options. - var xhr = options.xhr = Backbone.ajax(_.extend(params, options)); - model.trigger('request', model, xhr, options); - return xhr; - }; - - var noXhrPatch = - typeof window !== 'undefined' && !!window.ActiveXObject && - !(window.XMLHttpRequest && (new XMLHttpRequest).dispatchEvent); - - // Map from CRUD to HTTP for our default `Backbone.sync` implementation. - var methodMap = { - 'create': 'POST', - 'update': 'PUT', - 'patch': 'PATCH', - 'delete': 'DELETE', - 'read': 'GET' - }; - - // Set the default implementation of `Backbone.ajax` to proxy through to `$`. - // Override this if you'd like to use a different library. - Backbone.ajax = function() { - return Backbone.$.ajax.apply(Backbone.$, arguments); - }; - - // Backbone.Router - // --------------- - - // Routers map faux-URLs to actions, and fire events when routes are - // matched. Creating a new one sets its `routes` hash, if not set statically. - var Router = Backbone.Router = function(options) { - options || (options = {}); - if (options.routes) this.routes = options.routes; - this._bindRoutes(); - this.initialize.apply(this, arguments); - }; - - // Cached regular expressions for matching named param parts and splatted - // parts of route strings. - var optionalParam = /\((.*?)\)/g; - var namedParam = /(\(\?)?:\w+/g; - var splatParam = /\*\w+/g; - var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g; - - // Set up all inheritable **Backbone.Router** properties and methods. - _.extend(Router.prototype, Events, { - - // Initialize is an empty function by default. Override it with your own - // initialization logic. - initialize: function(){}, - - // Manually bind a single named route to a callback. For example: - // - // this.route('search/:query/p:num', 'search', function(query, num) { - // ... - // }); - // - route: function(route, name, callback) { - if (!_.isRegExp(route)) route = this._routeToRegExp(route); - if (_.isFunction(name)) { - callback = name; - name = ''; - } - if (!callback) callback = this[name]; - var router = this; - Backbone.history.route(route, function(fragment) { - var args = router._extractParameters(route, fragment); - router.execute(callback, args); - router.trigger.apply(router, ['route:' + name].concat(args)); - router.trigger('route', name, args); - Backbone.history.trigger('route', router, name, args); - }); - return this; - }, - - // Execute a route handler with the provided parameters. This is an - // excellent place to do pre-route setup or post-route cleanup. - execute: function(callback, args) { - if (callback) callback.apply(this, args); - }, - - // Simple proxy to `Backbone.history` to save a fragment into the history. - navigate: function(fragment, options) { - Backbone.history.navigate(fragment, options); - return this; - }, - - // Bind all defined routes to `Backbone.history`. We have to reverse the - // order of the routes here to support behavior where the most general - // routes can be defined at the bottom of the route map. - _bindRoutes: function() { - if (!this.routes) return; - this.routes = _.result(this, 'routes'); - var route, routes = _.keys(this.routes); - while ((route = routes.pop()) != null) { - this.route(route, this.routes[route]); - } - }, - - // Convert a route string into a regular expression, suitable for matching - // against the current location hash. - _routeToRegExp: function(route) { - route = route.replace(escapeRegExp, '\\$&') - .replace(optionalParam, '(?:$1)?') - .replace(namedParam, function(match, optional) { - return optional ? match : '([^/?]+)'; - }) - .replace(splatParam, '([^?]*?)'); - return new RegExp('^' + route + '(?:\\?([\\s\\S]*))?$'); - }, - - // Given a route, and a URL fragment that it matches, return the array of - // extracted decoded parameters. Empty or unmatched parameters will be - // treated as `null` to normalize cross-browser behavior. - _extractParameters: function(route, fragment) { - var params = route.exec(fragment).slice(1); - return _.map(params, function(param, i) { - // Don't decode the search params. - if (i === params.length - 1) return param || null; - return param ? decodeURIComponent(param) : null; - }); - } - - }); - - // Backbone.History - // ---------------- - - // Handles cross-browser history management, based on either - // [pushState](http://diveintohtml5.info/history.html) and real URLs, or - // [onhashchange](https://developer.mozilla.org/en-US/docs/DOM/window.onhashchange) - // and URL fragments. If the browser supports neither (old IE, natch), - // falls back to polling. - var History = Backbone.History = function() { - this.handlers = []; - _.bindAll(this, 'checkUrl'); - - // Ensure that `History` can be used outside of the browser. - if (typeof window !== 'undefined') { - this.location = window.location; - this.history = window.history; - } - }; - - // Cached regex for stripping a leading hash/slash and trailing space. - var routeStripper = /^[#\/]|\s+$/g; - - // Cached regex for stripping leading and trailing slashes. - var rootStripper = /^\/+|\/+$/g; - - // Cached regex for detecting MSIE. - var isExplorer = /msie [\w.]+/; - - // Cached regex for removing a trailing slash. - var trailingSlash = /\/$/; - - // Cached regex for stripping urls of hash. - var pathStripper = /#.*$/; - - // Has the history handling already been started? - History.started = false; - - // Set up all inheritable **Backbone.History** properties and methods. - _.extend(History.prototype, Events, { - - // The default interval to poll for hash changes, if necessary, is - // twenty times a second. - interval: 50, - - // Are we at the app root? - atRoot: function() { - return this.location.pathname.replace(/[^\/]$/, '$&/') === this.root; - }, - - // Gets the true hash value. Cannot use location.hash directly due to bug - // in Firefox where location.hash will always be decoded. - getHash: function(window) { - var match = (window || this).location.href.match(/#(.*)$/); - return match ? match[1] : ''; - }, - - // Get the cross-browser normalized URL fragment, either from the URL, - // the hash, or the override. - getFragment: function(fragment, forcePushState) { - if (fragment == null) { - if (this._hasPushState || !this._wantsHashChange || forcePushState) { - fragment = decodeURI(this.location.pathname + this.location.search); - var root = this.root.replace(trailingSlash, ''); - if (!fragment.indexOf(root)) fragment = fragment.slice(root.length); - } else { - fragment = this.getHash(); - } - } - return fragment.replace(routeStripper, ''); - }, - - // Start the hash change handling, returning `true` if the current URL matches - // an existing route, and `false` otherwise. - start: function(options) { - if (History.started) throw new Error("Backbone.history has already been started"); - History.started = true; - - // Figure out the initial configuration. Do we need an iframe? - // Is pushState desired ... is it available? - this.options = _.extend({root: '/'}, this.options, options); - this.root = this.options.root; - this._wantsHashChange = this.options.hashChange !== false; - this._wantsPushState = !!this.options.pushState; - this._hasPushState = !!(this.options.pushState && this.history && this.history.pushState); - var fragment = this.getFragment(); - var docMode = document.documentMode; - var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7)); - - // Normalize root to always include a leading and trailing slash. - this.root = ('/' + this.root + '/').replace(rootStripper, '/'); - - if (oldIE && this._wantsHashChange) { - var frame = Backbone.$('