/* Built for whs v2.2.0-beta.0 */
function createCommonjsModule(fn, module) {
return module = { exports: {} }, fn(module, module.exports), module.exports;
}
var dat_gui = createCommonjsModule(function (module) {
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
/** @namespace */
var dat = module.exports = dat || {};
/** @namespace */
dat.gui = dat.gui || {};
/** @namespace */
dat.utils = dat.utils || {};
/** @namespace */
dat.controllers = dat.controllers || {};
/** @namespace */
dat.dom = dat.dom || {};
/** @namespace */
dat.color = dat.color || {};
dat.utils.css = (function () {
return {
load: function (url, doc) {
doc = doc || document;
var link = doc.createElement('link');
link.type = 'text/css';
link.rel = 'stylesheet';
link.href = url;
doc.getElementsByTagName('head')[0].appendChild(link);
},
inject: function(css, doc) {
doc = doc || document;
var injected = document.createElement('style');
injected.type = 'text/css';
injected.innerHTML = css;
doc.getElementsByTagName('head')[0].appendChild(injected);
}
}
})();
dat.utils.common = (function () {
var ARR_EACH = Array.prototype.forEach;
var ARR_SLICE = Array.prototype.slice;
/**
* Band-aid methods for things that should be a lot easier in JavaScript.
* Implementation and structure inspired by underscore.js
* http://documentcloud.github.com/underscore/
*/
return {
BREAK: {},
extend: function(target) {
this.each(ARR_SLICE.call(arguments, 1), function(obj) {
for (var key in obj)
if (!this.isUndefined(obj[key]))
target[key] = obj[key];
}, this);
return target;
},
defaults: function(target) {
this.each(ARR_SLICE.call(arguments, 1), function(obj) {
for (var key in obj)
if (this.isUndefined(target[key]))
target[key] = obj[key];
}, this);
return target;
},
compose: function() {
var toCall = ARR_SLICE.call(arguments);
return function() {
var args = ARR_SLICE.call(arguments);
for (var i = toCall.length -1; i >= 0; i--) {
args = [toCall[i].apply(this, args)];
}
return args[0];
}
},
each: function(obj, itr, scope) {
if (ARR_EACH && obj.forEach === ARR_EACH) {
obj.forEach(itr, scope);
} else if (obj.length === obj.length + 0) { // Is number but not NaN
for (var key = 0, l = obj.length; key < l; key++)
if (key in obj && itr.call(scope, obj[key], key) === this.BREAK)
return;
} else {
for (var key in obj)
if (itr.call(scope, obj[key], key) === this.BREAK)
return;
}
},
defer: function(fnc) {
setTimeout(fnc, 0);
},
toArray: function(obj) {
if (obj.toArray) return obj.toArray();
return ARR_SLICE.call(obj);
},
isUndefined: function(obj) {
return obj === undefined;
},
isNull: function(obj) {
return obj === null;
},
isNaN: function(obj) {
return obj !== obj;
},
isArray: Array.isArray || function(obj) {
return obj.constructor === Array;
},
isObject: function(obj) {
return obj === Object(obj);
},
isNumber: function(obj) {
return obj === obj+0;
},
isString: function(obj) {
return obj === obj+'';
},
isBoolean: function(obj) {
return obj === false || obj === true;
},
isFunction: function(obj) {
return Object.prototype.toString.call(obj) === '[object Function]';
}
};
})();
dat.controllers.Controller = (function (common) {
/**
* @class An "abstract" class that represents a given property of an object.
*
* @param {Object} object The object to be manipulated
* @param {string} property The name of the property to be manipulated
*
* @member dat.controllers
*/
var Controller = function(object, property) {
this.initialValue = object[property];
/**
* Those who extend this class will put their DOM elements in here.
* @type {DOMElement}
*/
this.domElement = document.createElement('div');
/**
* The object to manipulate
* @type {Object}
*/
this.object = object;
/**
* The name of the property to manipulate
* @type {String}
*/
this.property = property;
/**
* The function to be called on change.
* @type {Function}
* @ignore
*/
this.__onChange = undefined;
/**
* The function to be called on finishing change.
* @type {Function}
* @ignore
*/
this.__onFinishChange = undefined;
};
common.extend(
Controller.prototype,
/** @lends dat.controllers.Controller.prototype */
{
/**
* Specify that a function fire every time someone changes the value with
* this Controller.
*
* @param {Function} fnc This function will be called whenever the value
* is modified via this Controller.
* @returns {dat.controllers.Controller} this
*/
onChange: function(fnc) {
this.__onChange = fnc;
return this;
},
/**
* Specify that a function fire every time someone "finishes" changing
* the value wih this Controller. Useful for values that change
* incrementally like numbers or strings.
*
* @param {Function} fnc This function will be called whenever
* someone "finishes" changing the value via this Controller.
* @returns {dat.controllers.Controller} this
*/
onFinishChange: function(fnc) {
this.__onFinishChange = fnc;
return this;
},
/**
* Change the value of object[property]
*
* @param {Object} newValue The new value of object[property]
*/
setValue: function(newValue) {
this.object[this.property] = newValue;
if (this.__onChange) {
this.__onChange.call(this, newValue);
}
this.updateDisplay();
return this;
},
/**
* Gets the value of object[property]
*
* @returns {Object} The current value of object[property]
*/
getValue: function() {
return this.object[this.property];
},
/**
* Refreshes the visual display of a Controller in order to keep sync
* with the object's current value.
* @returns {dat.controllers.Controller} this
*/
updateDisplay: function() {
return this;
},
/**
* @returns {Boolean} true if the value has deviated from initialValue
*/
isModified: function() {
return this.initialValue !== this.getValue()
}
}
);
return Controller;
})(dat.utils.common);
dat.dom.dom = (function (common) {
var EVENT_MAP = {
'HTMLEvents': ['change'],
'MouseEvents': ['click','mousemove','mousedown','mouseup', 'mouseover'],
'KeyboardEvents': ['keydown']
};
var EVENT_MAP_INV = {};
common.each(EVENT_MAP, function(v, k) {
common.each(v, function(e) {
EVENT_MAP_INV[e] = k;
});
});
var CSS_VALUE_PIXELS = /(\d+(\.\d+)?)px/;
function cssValueToPixels(val) {
if (val === '0' || common.isUndefined(val)) return 0;
var match = val.match(CSS_VALUE_PIXELS);
if (!common.isNull(match)) {
return parseFloat(match[1]);
}
// TODO ...ems? %?
return 0;
}
/**
* @namespace
* @member dat.dom
*/
var dom = {
/**
*
* @param elem
* @param selectable
*/
makeSelectable: function(elem, selectable) {
if (elem === undefined || elem.style === undefined) return;
elem.onselectstart = selectable ? function() {
return false;
} : function() {
};
elem.style.MozUserSelect = selectable ? 'auto' : 'none';
elem.style.KhtmlUserSelect = selectable ? 'auto' : 'none';
elem.unselectable = selectable ? 'on' : 'off';
},
/**
*
* @param elem
* @param horizontal
* @param vertical
*/
makeFullscreen: function(elem, horizontal, vertical) {
if (common.isUndefined(horizontal)) horizontal = true;
if (common.isUndefined(vertical)) vertical = true;
elem.style.position = 'absolute';
if (horizontal) {
elem.style.left = 0;
elem.style.right = 0;
}
if (vertical) {
elem.style.top = 0;
elem.style.bottom = 0;
}
},
/**
*
* @param elem
* @param eventType
* @param params
*/
fakeEvent: function(elem, eventType, params, aux) {
params = params || {};
var className = EVENT_MAP_INV[eventType];
if (!className) {
throw new Error('Event type ' + eventType + ' not supported.');
}
var evt = document.createEvent(className);
switch (className) {
case 'MouseEvents':
var clientX = params.x || params.clientX || 0;
var clientY = params.y || params.clientY || 0;
evt.initMouseEvent(eventType, params.bubbles || false,
params.cancelable || true, window, params.clickCount || 1,
0, //screen X
0, //screen Y
clientX, //client X
clientY, //client Y
false, false, false, false, 0, null);
break;
case 'KeyboardEvents':
var init = evt.initKeyboardEvent || evt.initKeyEvent; // webkit || moz
common.defaults(params, {
cancelable: true,
ctrlKey: false,
altKey: false,
shiftKey: false,
metaKey: false,
keyCode: undefined,
charCode: undefined
});
init(eventType, params.bubbles || false,
params.cancelable, window,
params.ctrlKey, params.altKey,
params.shiftKey, params.metaKey,
params.keyCode, params.charCode);
break;
default:
evt.initEvent(eventType, params.bubbles || false,
params.cancelable || true);
break;
}
common.defaults(evt, aux);
elem.dispatchEvent(evt);
},
/**
*
* @param elem
* @param event
* @param func
* @param bool
*/
bind: function(elem, event, func, bool) {
bool = bool || false;
if (elem.addEventListener)
elem.addEventListener(event, func, bool);
else if (elem.attachEvent)
elem.attachEvent('on' + event, func);
return dom;
},
/**
*
* @param elem
* @param event
* @param func
* @param bool
*/
unbind: function(elem, event, func, bool) {
bool = bool || false;
if (elem.removeEventListener)
elem.removeEventListener(event, func, bool);
else if (elem.detachEvent)
elem.detachEvent('on' + event, func);
return dom;
},
/**
*
* @param elem
* @param className
*/
addClass: function(elem, className) {
if (elem.className === undefined) {
elem.className = className;
} else if (elem.className !== className) {
var classes = elem.className.split(/ +/);
if (classes.indexOf(className) == -1) {
classes.push(className);
elem.className = classes.join(' ').replace(/^\s+/, '').replace(/\s+$/, '');
}
}
return dom;
},
/**
*
* @param elem
* @param className
*/
removeClass: function(elem, className) {
if (className) {
if (elem.className === undefined) ; else if (elem.className === className) {
elem.removeAttribute('class');
} else {
var classes = elem.className.split(/ +/);
var index = classes.indexOf(className);
if (index != -1) {
classes.splice(index, 1);
elem.className = classes.join(' ');
}
}
} else {
elem.className = undefined;
}
return dom;
},
hasClass: function(elem, className) {
return new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)').test(elem.className) || false;
},
/**
*
* @param elem
*/
getWidth: function(elem) {
var style = getComputedStyle(elem);
return cssValueToPixels(style['border-left-width']) +
cssValueToPixels(style['border-right-width']) +
cssValueToPixels(style['padding-left']) +
cssValueToPixels(style['padding-right']) +
cssValueToPixels(style['width']);
},
/**
*
* @param elem
*/
getHeight: function(elem) {
var style = getComputedStyle(elem);
return cssValueToPixels(style['border-top-width']) +
cssValueToPixels(style['border-bottom-width']) +
cssValueToPixels(style['padding-top']) +
cssValueToPixels(style['padding-bottom']) +
cssValueToPixels(style['height']);
},
/**
*
* @param elem
*/
getOffset: function(elem) {
var offset = {left: 0, top:0};
if (elem.offsetParent) {
do {
offset.left += elem.offsetLeft;
offset.top += elem.offsetTop;
} while (elem = elem.offsetParent);
}
return offset;
},
// http://stackoverflow.com/posts/2684561/revisions
/**
*
* @param elem
*/
isActive: function(elem) {
return elem === document.activeElement && ( elem.type || elem.href );
}
};
return dom;
})(dat.utils.common);
dat.controllers.OptionController = (function (Controller, dom, common) {
/**
* @class Provides a select input to alter the property of an object, using a
* list of accepted values.
*
* @extends dat.controllers.Controller
*
* @param {Object} object The object to be manipulated
* @param {string} property The name of the property to be manipulated
* @param {Object|string[]} options A map of labels to acceptable values, or
* a list of acceptable string values.
*
* @member dat.controllers
*/
var OptionController = function(object, property, options) {
OptionController.superclass.call(this, object, property);
var _this = this;
/**
* The drop down menu
* @ignore
*/
this.__select = document.createElement('select');
if (common.isArray(options)) {
var map = {};
common.each(options, function(element) {
map[element] = element;
});
options = map;
}
common.each(options, function(value, key) {
var opt = document.createElement('option');
opt.innerHTML = key;
opt.setAttribute('value', value);
_this.__select.appendChild(opt);
});
// Acknowledge original value
this.updateDisplay();
dom.bind(this.__select, 'change', function() {
var desiredValue = this.options[this.selectedIndex].value;
_this.setValue(desiredValue);
});
this.domElement.appendChild(this.__select);
};
OptionController.superclass = Controller;
common.extend(
OptionController.prototype,
Controller.prototype,
{
setValue: function(v) {
var toReturn = OptionController.superclass.prototype.setValue.call(this, v);
if (this.__onFinishChange) {
this.__onFinishChange.call(this, this.getValue());
}
return toReturn;
},
updateDisplay: function() {
this.__select.value = this.getValue();
return OptionController.superclass.prototype.updateDisplay.call(this);
}
}
);
return OptionController;
})(dat.controllers.Controller,
dat.dom.dom,
dat.utils.common);
dat.controllers.NumberController = (function (Controller, common) {
/**
* @class Represents a given property of an object that is a number.
*
* @extends dat.controllers.Controller
*
* @param {Object} object The object to be manipulated
* @param {string} property The name of the property to be manipulated
* @param {Object} [params] Optional parameters
* @param {Number} [params.min] Minimum allowed value
* @param {Number} [params.max] Maximum allowed value
* @param {Number} [params.step] Increment by which to change value
*
* @member dat.controllers
*/
var NumberController = function(object, property, params) {
NumberController.superclass.call(this, object, property);
params = params || {};
this.__min = params.min;
this.__max = params.max;
this.__step = params.step;
if (common.isUndefined(this.__step)) {
if (this.initialValue == 0) {
this.__impliedStep = 1; // What are we, psychics?
} else {
// Hey Doug, check this out.
this.__impliedStep = Math.pow(10, Math.floor(Math.log(this.initialValue)/Math.LN10))/10;
}
} else {
this.__impliedStep = this.__step;
}
this.__precision = numDecimals(this.__impliedStep);
};
NumberController.superclass = Controller;
common.extend(
NumberController.prototype,
Controller.prototype,
/** @lends dat.controllers.NumberController.prototype */
{
setValue: function(v) {
if (this.__min !== undefined && v < this.__min) {
v = this.__min;
} else if (this.__max !== undefined && v > this.__max) {
v = this.__max;
}
if (this.__step !== undefined && v % this.__step != 0) {
v = Math.round(v / this.__step) * this.__step;
}
return NumberController.superclass.prototype.setValue.call(this, v);
},
/**
* Specify a minimum value for object[property].
*
* @param {Number} minValue The minimum value for
* object[property]
* @returns {dat.controllers.NumberController} this
*/
min: function(v) {
this.__min = v;
return this;
},
/**
* Specify a maximum value for object[property].
*
* @param {Number} maxValue The maximum value for
* object[property]
* @returns {dat.controllers.NumberController} this
*/
max: function(v) {
this.__max = v;
return this;
},
/**
* Specify a step value that dat.controllers.NumberController
* increments by.
*
* @param {Number} stepValue The step value for
* dat.controllers.NumberController
* @default if minimum and maximum specified increment is 1% of the
* difference otherwise stepValue is 1
* @returns {dat.controllers.NumberController} this
*/
step: function(v) {
this.__step = v;
return this;
}
}
);
function numDecimals(x) {
x = x.toString();
if (x.indexOf('.') > -1) {
return x.length - x.indexOf('.') - 1;
} else {
return 0;
}
}
return NumberController;
})(dat.controllers.Controller,
dat.utils.common);
dat.controllers.NumberControllerBox = (function (NumberController, dom, common) {
/**
* @class Represents a given property of an object that is a number and
* provides an input element with which to manipulate it.
*
* @extends dat.controllers.Controller
* @extends dat.controllers.NumberController
*
* @param {Object} object The object to be manipulated
* @param {string} property The name of the property to be manipulated
* @param {Object} [params] Optional parameters
* @param {Number} [params.min] Minimum allowed value
* @param {Number} [params.max] Maximum allowed value
* @param {Number} [params.step] Increment by which to change value
*
* @member dat.controllers
*/
var NumberControllerBox = function(object, property, params) {
this.__truncationSuspended = false;
NumberControllerBox.superclass.call(this, object, property, params);
var _this = this;
/**
* {Number} Previous mouse y position
* @ignore
*/
var prev_y;
this.__input = document.createElement('input');
this.__input.setAttribute('type', 'text');
// Makes it so manually specified values are not truncated.
dom.bind(this.__input, 'change', onChange);
dom.bind(this.__input, 'blur', onBlur);
dom.bind(this.__input, 'mousedown', onMouseDown);
dom.bind(this.__input, 'keydown', function(e) {
// When pressing entire, you can be as precise as you want.
if (e.keyCode === 13) {
_this.__truncationSuspended = true;
this.blur();
_this.__truncationSuspended = false;
}
});
function onChange() {
var attempted = parseFloat(_this.__input.value);
if (!common.isNaN(attempted)) _this.setValue(attempted);
}
function onBlur() {
onChange();
if (_this.__onFinishChange) {
_this.__onFinishChange.call(_this, _this.getValue());
}
}
function onMouseDown(e) {
dom.bind(window, 'mousemove', onMouseDrag);
dom.bind(window, 'mouseup', onMouseUp);
prev_y = e.clientY;
}
function onMouseDrag(e) {
var diff = prev_y - e.clientY;
_this.setValue(_this.getValue() + diff * _this.__impliedStep);
prev_y = e.clientY;
}
function onMouseUp() {
dom.unbind(window, 'mousemove', onMouseDrag);
dom.unbind(window, 'mouseup', onMouseUp);
}
this.updateDisplay();
this.domElement.appendChild(this.__input);
};
NumberControllerBox.superclass = NumberController;
common.extend(
NumberControllerBox.prototype,
NumberController.prototype,
{
updateDisplay: function() {
this.__input.value = this.__truncationSuspended ? this.getValue() : roundToDecimal(this.getValue(), this.__precision);
return NumberControllerBox.superclass.prototype.updateDisplay.call(this);
}
}
);
function roundToDecimal(value, decimals) {
var tenTo = Math.pow(10, decimals);
return Math.round(value * tenTo) / tenTo;
}
return NumberControllerBox;
})(dat.controllers.NumberController,
dat.dom.dom,
dat.utils.common);
dat.controllers.NumberControllerSlider = (function (NumberController, dom, css, common, styleSheet) {
/**
* @class Represents a given property of an object that is a number, contains
* a minimum and maximum, and provides a slider element with which to
* manipulate it. It should be noted that the slider element is made up of
* <div> tags, not the html5
* <slider> element.
*
* @extends dat.controllers.Controller
* @extends dat.controllers.NumberController
*
* @param {Object} object The object to be manipulated
* @param {string} property The name of the property to be manipulated
* @param {Number} minValue Minimum allowed value
* @param {Number} maxValue Maximum allowed value
* @param {Number} stepValue Increment by which to change value
*
* @member dat.controllers
*/
var NumberControllerSlider = function(object, property, min, max, step) {
NumberControllerSlider.superclass.call(this, object, property, { min: min, max: max, step: step });
var _this = this;
this.__background = document.createElement('div');
this.__foreground = document.createElement('div');
dom.bind(this.__background, 'mousedown', onMouseDown);
dom.addClass(this.__background, 'slider');
dom.addClass(this.__foreground, 'slider-fg');
function onMouseDown(e) {
dom.bind(window, 'mousemove', onMouseDrag);
dom.bind(window, 'mouseup', onMouseUp);
onMouseDrag(e);
}
function onMouseDrag(e) {
e.preventDefault();
var offset = dom.getOffset(_this.__background);
var width = dom.getWidth(_this.__background);
_this.setValue(
map(e.clientX, offset.left, offset.left + width, _this.__min, _this.__max)
);
return false;
}
function onMouseUp() {
dom.unbind(window, 'mousemove', onMouseDrag);
dom.unbind(window, 'mouseup', onMouseUp);
if (_this.__onFinishChange) {
_this.__onFinishChange.call(_this, _this.getValue());
}
}
this.updateDisplay();
this.__background.appendChild(this.__foreground);
this.domElement.appendChild(this.__background);
};
NumberControllerSlider.superclass = NumberController;
/**
* Injects default stylesheet for slider elements.
*/
NumberControllerSlider.useDefaultStyles = function() {
css.inject(styleSheet);
};
common.extend(
NumberControllerSlider.prototype,
NumberController.prototype,
{
updateDisplay: function() {
var pct = (this.getValue() - this.__min)/(this.__max - this.__min);
this.__foreground.style.width = pct*100+'%';
return NumberControllerSlider.superclass.prototype.updateDisplay.call(this);
}
}
);
function map(v, i1, i2, o1, o2) {
return o1 + (o2 - o1) * ((v - i1) / (i2 - i1));
}
return NumberControllerSlider;
})(dat.controllers.NumberController,
dat.dom.dom,
dat.utils.css,
dat.utils.common,
".slider {\n box-shadow: inset 0 2px 4px rgba(0,0,0,0.15);\n height: 1em;\n border-radius: 1em;\n background-color: #eee;\n padding: 0 0.5em;\n overflow: hidden;\n}\n\n.slider-fg {\n padding: 1px 0 2px 0;\n background-color: #aaa;\n height: 1em;\n margin-left: -0.5em;\n padding-right: 0.5em;\n border-radius: 1em 0 0 1em;\n}\n\n.slider-fg:after {\n display: inline-block;\n border-radius: 1em;\n background-color: #fff;\n border: 1px solid #aaa;\n content: '';\n float: right;\n margin-right: -1em;\n margin-top: -1px;\n height: 0.9em;\n width: 0.9em;\n}");
dat.controllers.FunctionController = (function (Controller, dom, common) {
/**
* @class Provides a GUI interface to fire a specified method, a property of an object.
*
* @extends dat.controllers.Controller
*
* @param {Object} object The object to be manipulated
* @param {string} property The name of the property to be manipulated
*
* @member dat.controllers
*/
var FunctionController = function(object, property, text) {
FunctionController.superclass.call(this, object, property);
var _this = this;
this.__button = document.createElement('div');
this.__button.innerHTML = text === undefined ? 'Fire' : text;
dom.bind(this.__button, 'click', function(e) {
e.preventDefault();
_this.fire();
return false;
});
dom.addClass(this.__button, 'button');
this.domElement.appendChild(this.__button);
};
FunctionController.superclass = Controller;
common.extend(
FunctionController.prototype,
Controller.prototype,
{
fire: function() {
if (this.__onChange) {
this.__onChange.call(this);
}
if (this.__onFinishChange) {
this.__onFinishChange.call(this, this.getValue());
}
this.getValue().call(this.object);
}
}
);
return FunctionController;
})(dat.controllers.Controller,
dat.dom.dom,
dat.utils.common);
dat.controllers.BooleanController = (function (Controller, dom, common) {
/**
* @class Provides a checkbox input to alter the boolean property of an object.
* @extends dat.controllers.Controller
*
* @param {Object} object The object to be manipulated
* @param {string} property The name of the property to be manipulated
*
* @member dat.controllers
*/
var BooleanController = function(object, property) {
BooleanController.superclass.call(this, object, property);
var _this = this;
this.__prev = this.getValue();
this.__checkbox = document.createElement('input');
this.__checkbox.setAttribute('type', 'checkbox');
dom.bind(this.__checkbox, 'change', onChange, false);
this.domElement.appendChild(this.__checkbox);
// Match original value
this.updateDisplay();
function onChange() {
_this.setValue(!_this.__prev);
}
};
BooleanController.superclass = Controller;
common.extend(
BooleanController.prototype,
Controller.prototype,
{
setValue: function(v) {
var toReturn = BooleanController.superclass.prototype.setValue.call(this, v);
if (this.__onFinishChange) {
this.__onFinishChange.call(this, this.getValue());
}
this.__prev = this.getValue();
return toReturn;
},
updateDisplay: function() {
if (this.getValue() === true) {
this.__checkbox.setAttribute('checked', 'checked');
this.__checkbox.checked = true;
} else {
this.__checkbox.checked = false;
}
return BooleanController.superclass.prototype.updateDisplay.call(this);
}
}
);
return BooleanController;
})(dat.controllers.Controller,
dat.dom.dom,
dat.utils.common);
dat.color.toString = (function (common) {
return function(color) {
if (color.a == 1 || common.isUndefined(color.a)) {
var s = color.hex.toString(16);
while (s.length < 6) {
s = '0' + s;
}
return '#' + s;
} else {
return 'rgba(' + Math.round(color.r) + ',' + Math.round(color.g) + ',' + Math.round(color.b) + ',' + color.a + ')';
}
}
})(dat.utils.common);
dat.color.interpret = (function (toString, common) {
var result, toReturn;
var interpret = function() {
toReturn = false;
var original = arguments.length > 1 ? common.toArray(arguments) : arguments[0];
common.each(INTERPRETATIONS, function(family) {
if (family.litmus(original)) {
common.each(family.conversions, function(conversion, conversionName) {
result = conversion.read(original);
if (toReturn === false && result !== false) {
toReturn = result;
result.conversionName = conversionName;
result.conversion = conversion;
return common.BREAK;
}
});
return common.BREAK;
}
});
return toReturn;
};
var INTERPRETATIONS = [
// Strings
{
litmus: common.isString,
conversions: {
THREE_CHAR_HEX: {
read: function(original) {
var test = original.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i);
if (test === null) return false;
return {
space: 'HEX',
hex: parseInt(
'0x' +
test[1].toString() + test[1].toString() +
test[2].toString() + test[2].toString() +
test[3].toString() + test[3].toString())
};
},
write: toString
},
SIX_CHAR_HEX: {
read: function(original) {
var test = original.match(/^#([A-F0-9]{6})$/i);
if (test === null) return false;
return {
space: 'HEX',
hex: parseInt('0x' + test[1].toString())
};
},
write: toString
},
CSS_RGB: {
read: function(original) {
var test = original.match(/^rgb\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/);
if (test === null) return false;
return {
space: 'RGB',
r: parseFloat(test[1]),
g: parseFloat(test[2]),
b: parseFloat(test[3])
};
},
write: toString
},
CSS_RGBA: {
read: function(original) {
var test = original.match(/^rgba\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\,\s*(.+)\s*\)/);
if (test === null) return false;
return {
space: 'RGB',
r: parseFloat(test[1]),
g: parseFloat(test[2]),
b: parseFloat(test[3]),
a: parseFloat(test[4])
};
},
write: toString
}
}
},
// Numbers
{
litmus: common.isNumber,
conversions: {
HEX: {
read: function(original) {
return {
space: 'HEX',
hex: original,
conversionName: 'HEX'
}
},
write: function(color) {
return color.hex;
}
}
}
},
// Arrays
{
litmus: common.isArray,
conversions: {
RGB_ARRAY: {
read: function(original) {
if (original.length != 3) return false;
return {
space: 'RGB',
r: original[0],
g: original[1],
b: original[2]
};
},
write: function(color) {
return [color.r, color.g, color.b];
}
},
RGBA_ARRAY: {
read: function(original) {
if (original.length != 4) return false;
return {
space: 'RGB',
r: original[0],
g: original[1],
b: original[2],
a: original[3]
};
},
write: function(color) {
return [color.r, color.g, color.b, color.a];
}
}
}
},
// Objects
{
litmus: common.isObject,
conversions: {
RGBA_OBJ: {
read: function(original) {
if (common.isNumber(original.r) &&
common.isNumber(original.g) &&
common.isNumber(original.b) &&
common.isNumber(original.a)) {
return {
space: 'RGB',
r: original.r,
g: original.g,
b: original.b,
a: original.a
}
}
return false;
},
write: function(color) {
return {
r: color.r,
g: color.g,
b: color.b,
a: color.a
}
}
},
RGB_OBJ: {
read: function(original) {
if (common.isNumber(original.r) &&
common.isNumber(original.g) &&
common.isNumber(original.b)) {
return {
space: 'RGB',
r: original.r,
g: original.g,
b: original.b
}
}
return false;
},
write: function(color) {
return {
r: color.r,
g: color.g,
b: color.b
}
}
},
HSVA_OBJ: {
read: function(original) {
if (common.isNumber(original.h) &&
common.isNumber(original.s) &&
common.isNumber(original.v) &&
common.isNumber(original.a)) {
return {
space: 'HSV',
h: original.h,
s: original.s,
v: original.v,
a: original.a
}
}
return false;
},
write: function(color) {
return {
h: color.h,
s: color.s,
v: color.v,
a: color.a
}
}
},
HSV_OBJ: {
read: function(original) {
if (common.isNumber(original.h) &&
common.isNumber(original.s) &&
common.isNumber(original.v)) {
return {
space: 'HSV',
h: original.h,
s: original.s,
v: original.v
}
}
return false;
},
write: function(color) {
return {
h: color.h,
s: color.s,
v: color.v
}
}
}
}
}
];
return interpret;
})(dat.color.toString,
dat.utils.common);
dat.GUI = dat.gui.GUI = (function (css, saveDialogueContents, styleSheet, controllerFactory, Controller, BooleanController, FunctionController, NumberControllerBox, NumberControllerSlider, OptionController, ColorController, requestAnimationFrame, CenteredDiv, dom, common) {
css.inject(styleSheet);
/** Outer-most className for GUI's */
var CSS_NAMESPACE = 'dg';
var HIDE_KEY_CODE = 72;
/** The only value shared between the JS and SCSS. Use caution. */
var CLOSE_BUTTON_HEIGHT = 20;
var DEFAULT_DEFAULT_PRESET_NAME = 'Default';
var SUPPORTS_LOCAL_STORAGE = (function() {
try {
return 'localStorage' in window && window['localStorage'] !== null;
} catch (e) {
return false;
}
})();
var SAVE_DIALOGUE;
/** Have we yet to create an autoPlace GUI? */
var auto_place_virgin = true;
/** Fixed position div that auto place GUI's go inside */
var auto_place_container;
/** Are we hiding the GUI's ? */
var hide = false;
/** GUI's which should be hidden */
var hideable_guis = [];
/**
* A lightweight controller library for JavaScript. It allows you to easily
* manipulate variables and fire functions on the fly.
* @class
*
* @member dat.gui
*
* @param {Object} [params]
* @param {String} [params.name] The name of this GUI.
* @param {Object} [params.load] JSON object representing the saved state of
* this GUI.
* @param {Boolean} [params.auto=true]
* @param {dat.gui.GUI} [params.parent] The GUI I'm nested in.
* @param {Boolean} [params.closed] If true, starts closed
*/
var GUI = function(params) {
var _this = this;
/**
* Outermost DOM Element
* @type DOMElement
*/
this.domElement = document.createElement('div');
this.__ul = document.createElement('ul');
this.domElement.appendChild(this.__ul);
dom.addClass(this.domElement, CSS_NAMESPACE);
/**
* Nested GUI's by name
* @ignore
*/
this.__folders = {};
this.__controllers = [];
/**
* List of objects I'm remembering for save, only used in top level GUI
* @ignore
*/
this.__rememberedObjects = [];
/**
* Maps the index of remembered objects to a map of controllers, only used
* in top level GUI.
*
* @private
* @ignore
*
* @example
* [
* {
* propertyName: Controller,
* anotherPropertyName: Controller
* },
* {
* propertyName: Controller
* }
* ]
*/
this.__rememberedObjectIndecesToControllers = [];
this.__listening = [];
params = params || {};
// Default parameters
params = common.defaults(params, {
autoPlace: true,
width: GUI.DEFAULT_WIDTH
});
params = common.defaults(params, {
resizable: params.autoPlace,
hideable: params.autoPlace
});
if (!common.isUndefined(params.load)) {
// Explicit preset
if (params.preset) params.load.preset = params.preset;
} else {
params.load = { preset: DEFAULT_DEFAULT_PRESET_NAME };
}
if (common.isUndefined(params.parent) && params.hideable) {
hideable_guis.push(this);
}
// Only root level GUI's are resizable.
params.resizable = common.isUndefined(params.parent) && params.resizable;
if (params.autoPlace && common.isUndefined(params.scrollable)) {
params.scrollable = true;
}
// params.scrollable = common.isUndefined(params.parent) && params.scrollable === true;
// Not part of params because I don't want people passing this in via
// constructor. Should be a 'remembered' value.
var use_local_storage =
SUPPORTS_LOCAL_STORAGE &&
localStorage.getItem(getLocalStorageHash(this, 'isLocal')) === 'true';
Object.defineProperties(this,
/** @lends dat.gui.GUI.prototype */
{
/**
* The parent GUI
* @type dat.gui.GUI
*/
parent: {
get: function() {
return params.parent;
}
},
scrollable: {
get: function() {
return params.scrollable;
}
},
/**
* Handles GUI's element placement for you
* @type Boolean
*/
autoPlace: {
get: function() {
return params.autoPlace;
}
},
/**
* The identifier for a set of saved values
* @type String
*/
preset: {
get: function() {
if (_this.parent) {
return _this.getRoot().preset;
} else {
return params.load.preset;
}
},
set: function(v) {
if (_this.parent) {
_this.getRoot().preset = v;
} else {
params.load.preset = v;
}
setPresetSelectIndex(this);
_this.revert();
}
},
/**
* The width of GUI element
* @type Number
*/
width: {
get: function() {
return params.width;
},
set: function(v) {
params.width = v;
setWidth(_this, v);
}
},
/**
* The name of GUI. Used for folders. i.e
* a folder's name
* @type String
*/
name: {
get: function() {
return params.name;
},
set: function(v) {
// TODO Check for collisions among sibling folders
params.name = v;
if (title_row_name) {
title_row_name.innerHTML = params.name;
}
}
},
/**
* Whether the GUI is collapsed or not
* @type Boolean
*/
closed: {
get: function() {
return params.closed;
},
set: function(v) {
params.closed = v;
if (params.closed) {
dom.addClass(_this.__ul, GUI.CLASS_CLOSED);
} else {
dom.removeClass(_this.__ul, GUI.CLASS_CLOSED);
}
// For browsers that aren't going to respect the CSS transition,
// Lets just check our height against the window height right off
// the bat.
this.onResize();
if (_this.__closeButton) {
_this.__closeButton.innerHTML = v ? GUI.TEXT_OPEN : GUI.TEXT_CLOSED;
}
}
},
/**
* Contains all presets
* @type Object
*/
load: {
get: function() {
return params.load;
}
},
/**
* Determines whether or not to use localStorage as the means for
* remembering
* @type Boolean
*/
useLocalStorage: {
get: function() {
return use_local_storage;
},
set: function(bool) {
if (SUPPORTS_LOCAL_STORAGE) {
use_local_storage = bool;
if (bool) {
dom.bind(window, 'unload', saveToLocalStorage);
} else {
dom.unbind(window, 'unload', saveToLocalStorage);
}
localStorage.setItem(getLocalStorageHash(_this, 'isLocal'), bool);
}
}
}
});
// Are we a root level GUI?
if (common.isUndefined(params.parent)) {
params.closed = false;
dom.addClass(this.domElement, GUI.CLASS_MAIN);
dom.makeSelectable(this.domElement, false);
// Are we supposed to be loading locally?
if (SUPPORTS_LOCAL_STORAGE) {
if (use_local_storage) {
_this.useLocalStorage = true;
var saved_gui = localStorage.getItem(getLocalStorageHash(this, 'gui'));
if (saved_gui) {
params.load = JSON.parse(saved_gui);
}
}
}
this.__closeButton = document.createElement('div');
this.__closeButton.innerHTML = GUI.TEXT_CLOSED;
dom.addClass(this.__closeButton, GUI.CLASS_CLOSE_BUTTON);
this.domElement.appendChild(this.__closeButton);
dom.bind(this.__closeButton, 'click', function() {
_this.closed = !_this.closed;
});
// Oh, you're a nested GUI!
} else {
if (params.closed === undefined) {
params.closed = true;
}
var title_row_name = document.createTextNode(params.name);
dom.addClass(title_row_name, 'controller-name');
var title_row = addRow(_this, title_row_name);
var on_click_title = function(e) {
e.preventDefault();
_this.closed = !_this.closed;
return false;
};
dom.addClass(this.__ul, GUI.CLASS_CLOSED);
dom.addClass(title_row, 'title');
dom.bind(title_row, 'click', on_click_title);
if (!params.closed) {
this.closed = false;
}
}
if (params.autoPlace) {
if (common.isUndefined(params.parent)) {
if (auto_place_virgin) {
auto_place_container = document.createElement('div');
dom.addClass(auto_place_container, CSS_NAMESPACE);
dom.addClass(auto_place_container, GUI.CLASS_AUTO_PLACE_CONTAINER);
document.body.appendChild(auto_place_container);
auto_place_virgin = false;
}
// Put it in the dom for you.
auto_place_container.appendChild(this.domElement);
// Apply the auto styles
dom.addClass(this.domElement, GUI.CLASS_AUTO_PLACE);
}
// Make it not elastic.
if (!this.parent) setWidth(_this, params.width);
}
dom.bind(window, 'resize', function() { _this.onResize(); });
dom.bind(this.__ul, 'webkitTransitionEnd', function() { _this.onResize(); });
dom.bind(this.__ul, 'transitionend', function() { _this.onResize(); });
dom.bind(this.__ul, 'oTransitionEnd', function() { _this.onResize(); });
this.onResize();
if (params.resizable) {
addResizeHandle(this);
}
function saveToLocalStorage() {
localStorage.setItem(getLocalStorageHash(_this, 'gui'), JSON.stringify(_this.getSaveObject()));
}
var root = _this.getRoot();
function resetWidth() {
var root = _this.getRoot();
root.width += 1;
common.defer(function() {
root.width -= 1;
});
}
if (!params.parent) {
resetWidth();
}
};
GUI.toggleHide = function() {
hide = !hide;
common.each(hideable_guis, function(gui) {
gui.domElement.style.zIndex = hide ? -999 : 999;
gui.domElement.style.opacity = hide ? 0 : 1;
});
};
GUI.CLASS_AUTO_PLACE = 'a';
GUI.CLASS_AUTO_PLACE_CONTAINER = 'ac';
GUI.CLASS_MAIN = 'main';
GUI.CLASS_CONTROLLER_ROW = 'cr';
GUI.CLASS_TOO_TALL = 'taller-than-window';
GUI.CLASS_CLOSED = 'closed';
GUI.CLASS_CLOSE_BUTTON = 'close-button';
GUI.CLASS_DRAG = 'drag';
GUI.DEFAULT_WIDTH = 245;
GUI.TEXT_CLOSED = 'Close Controls';
GUI.TEXT_OPEN = 'Open Controls';
dom.bind(window, 'keydown', function(e) {
if (document.activeElement.type !== 'text' &&
(e.which === HIDE_KEY_CODE || e.keyCode == HIDE_KEY_CODE)) {
GUI.toggleHide();
}
}, false);
common.extend(
GUI.prototype,
/** @lends dat.gui.GUI */
{
/**
* @param object
* @param property
* @returns {dat.controllers.Controller} The new controller that was added.
* @instance
*/
add: function(object, property) {
return add(
this,
object,
property,
{
factoryArgs: Array.prototype.slice.call(arguments, 2)
}
);
},
/**
* @param object
* @param property
* @returns {dat.controllers.ColorController} The new controller that was added.
* @instance
*/
addColor: function(object, property) {
return add(
this,
object,
property,
{
color: true
}
);
},
/**
* @param controller
* @instance
*/
remove: function(controller) {
// TODO listening?
this.__ul.removeChild(controller.__li);
this.__controllers.slice(this.__controllers.indexOf(controller), 1);
var _this = this;
common.defer(function() {
_this.onResize();
});
},
destroy: function() {
if (this.autoPlace) {
auto_place_container.removeChild(this.domElement);
}
},
/**
* @param name
* @returns {dat.gui.GUI} The new folder.
* @throws {Error} if this GUI already has a folder by the specified
* name
* @instance
*/
addFolder: function(name) {
// We have to prevent collisions on names in order to have a key
// by which to remember saved values
if (this.__folders[name] !== undefined) {
throw new Error('You already have a folder in this GUI by the' +
' name "' + name + '"');
}
var new_gui_params = { name: name, parent: this };
// We need to pass down the autoPlace trait so that we can
// attach event listeners to open/close folder actions to
// ensure that a scrollbar appears if the window is too short.
new_gui_params.autoPlace = this.autoPlace;
// Do we have saved appearance data for this folder?
if (this.load && // Anything loaded?
this.load.folders && // Was my parent a dead-end?
this.load.folders[name]) { // Did daddy remember me?
// Start me closed if I was closed
new_gui_params.closed = this.load.folders[name].closed;
// Pass down the loaded data
new_gui_params.load = this.load.folders[name];
}
var gui = new GUI(new_gui_params);
this.__folders[name] = gui;
var li = addRow(this, gui.domElement);
dom.addClass(li, 'folder');
return gui;
},
open: function() {
this.closed = false;
},
close: function() {
this.closed = true;
},
onResize: function() {
var root = this.getRoot();
if (root.scrollable) {
var top = dom.getOffset(root.__ul).top;
var h = 0;
common.each(root.__ul.childNodes, function(node) {
if (! (root.autoPlace && node === root.__save_row))
h += dom.getHeight(node);
});
if (window.innerHeight - top - CLOSE_BUTTON_HEIGHT < h) {
dom.addClass(root.domElement, GUI.CLASS_TOO_TALL);
root.__ul.style.height = window.innerHeight - top - CLOSE_BUTTON_HEIGHT + 'px';
} else {
dom.removeClass(root.domElement, GUI.CLASS_TOO_TALL);
root.__ul.style.height = 'auto';
}
}
if (root.__resize_handle) {
common.defer(function() {
root.__resize_handle.style.height = root.__ul.offsetHeight + 'px';
});
}
if (root.__closeButton) {
root.__closeButton.style.width = root.width + 'px';
}
},
/**
* Mark objects for saving. The order of these objects cannot change as
* the GUI grows. When remembering new objects, append them to the end
* of the list.
*
* @param {Object...} objects
* @throws {Error} if not called on a top level GUI.
* @instance
*/
remember: function() {
if (common.isUndefined(SAVE_DIALOGUE)) {
SAVE_DIALOGUE = new CenteredDiv();
SAVE_DIALOGUE.domElement.innerHTML = saveDialogueContents;
}
if (this.parent) {
throw new Error("You can only call remember on a top level GUI.");
}
var _this = this;
common.each(Array.prototype.slice.call(arguments), function(object) {
if (_this.__rememberedObjects.length == 0) {
addSaveMenu(_this);
}
if (_this.__rememberedObjects.indexOf(object) == -1) {
_this.__rememberedObjects.push(object);
}
});
if (this.autoPlace) {
// Set save row width
setWidth(this, this.width);
}
},
/**
* @returns {dat.gui.GUI} the topmost parent GUI of a nested GUI.
* @instance
*/
getRoot: function() {
var gui = this;
while (gui.parent) {
gui = gui.parent;
}
return gui;
},
/**
* @returns {Object} a JSON object representing the current state of
* this GUI as well as its remembered properties.
* @instance
*/
getSaveObject: function() {
var toReturn = this.load;
toReturn.closed = this.closed;
// Am I remembering any values?
if (this.__rememberedObjects.length > 0) {
toReturn.preset = this.preset;
if (!toReturn.remembered) {
toReturn.remembered = {};
}
toReturn.remembered[this.preset] = getCurrentPreset(this);
}
toReturn.folders = {};
common.each(this.__folders, function(element, key) {
toReturn.folders[key] = element.getSaveObject();
});
return toReturn;
},
save: function() {
if (!this.load.remembered) {
this.load.remembered = {};
}
this.load.remembered[this.preset] = getCurrentPreset(this);
markPresetModified(this, false);
},
saveAs: function(presetName) {
if (!this.load.remembered) {
// Retain default values upon first save
this.load.remembered = {};
this.load.remembered[DEFAULT_DEFAULT_PRESET_NAME] = getCurrentPreset(this, true);
}
this.load.remembered[presetName] = getCurrentPreset(this);
this.preset = presetName;
addPresetOption(this, presetName, true);
},
revert: function(gui) {
common.each(this.__controllers, function(controller) {
// Make revert work on Default.
if (!this.getRoot().load.remembered) {
controller.setValue(controller.initialValue);
} else {
recallSavedValue(gui || this.getRoot(), controller);
}
}, this);
common.each(this.__folders, function(folder) {
folder.revert(folder);
});
if (!gui) {
markPresetModified(this.getRoot(), false);
}
},
listen: function(controller) {
var init = this.__listening.length == 0;
this.__listening.push(controller);
if (init) updateDisplays(this.__listening);
}
}
);
function add(gui, object, property, params) {
if (object[property] === undefined) {
throw new Error("Object " + object + " has no property \"" + property + "\"");
}
var controller;
if (params.color) {
controller = new ColorController(object, property);
} else {
var factoryArgs = [object,property].concat(params.factoryArgs);
controller = controllerFactory.apply(gui, factoryArgs);
}
if (params.before instanceof Controller) {
params.before = params.before.__li;
}
recallSavedValue(gui, controller);
dom.addClass(controller.domElement, 'c');
var name = document.createElement('span');
dom.addClass(name, 'property-name');
name.innerHTML = controller.property;
var container = document.createElement('div');
container.appendChild(name);
container.appendChild(controller.domElement);
var li = addRow(gui, container, params.before);
dom.addClass(li, GUI.CLASS_CONTROLLER_ROW);
dom.addClass(li, typeof controller.getValue());
augmentController(gui, li, controller);
gui.__controllers.push(controller);
return controller;
}
/**
* Add a row to the end of the GUI or before another row.
*
* @param gui
* @param [dom] If specified, inserts the dom content in the new row
* @param [liBefore] If specified, places the new row before another row
*/
function addRow(gui, dom, liBefore) {
var li = document.createElement('li');
if (dom) li.appendChild(dom);
if (liBefore) {
gui.__ul.insertBefore(li, params.before);
} else {
gui.__ul.appendChild(li);
}
gui.onResize();
return li;
}
function augmentController(gui, li, controller) {
controller.__li = li;
controller.__gui = gui;
common.extend(controller, {
options: function(options) {
if (arguments.length > 1) {
controller.remove();
return add(
gui,
controller.object,
controller.property,
{
before: controller.__li.nextElementSibling,
factoryArgs: [common.toArray(arguments)]
}
);
}
if (common.isArray(options) || common.isObject(options)) {
controller.remove();
return add(
gui,
controller.object,
controller.property,
{
before: controller.__li.nextElementSibling,
factoryArgs: [options]
}
);
}
},
name: function(v) {
controller.__li.firstElementChild.firstElementChild.innerHTML = v;
return controller;
},
listen: function() {
controller.__gui.listen(controller);
return controller;
},
remove: function() {
controller.__gui.remove(controller);
return controller;
}
});
// All sliders should be accompanied by a box.
if (controller instanceof NumberControllerSlider) {
var box = new NumberControllerBox(controller.object, controller.property,
{ min: controller.__min, max: controller.__max, step: controller.__step });
common.each(['updateDisplay', 'onChange', 'onFinishChange'], function(method) {
var pc = controller[method];
var pb = box[method];
controller[method] = box[method] = function() {
var args = Array.prototype.slice.call(arguments);
pc.apply(controller, args);
return pb.apply(box, args);
};
});
dom.addClass(li, 'has-slider');
controller.domElement.insertBefore(box.domElement, controller.domElement.firstElementChild);
}
else if (controller instanceof NumberControllerBox) {
var r = function(returned) {
// Have we defined both boundaries?
if (common.isNumber(controller.__min) && common.isNumber(controller.__max)) {
// Well, then lets just replace this with a slider.
controller.remove();
return add(
gui,
controller.object,
controller.property,
{
before: controller.__li.nextElementSibling,
factoryArgs: [controller.__min, controller.__max, controller.__step]
});
}
return returned;
};
controller.min = common.compose(r, controller.min);
controller.max = common.compose(r, controller.max);
}
else if (controller instanceof BooleanController) {
dom.bind(li, 'click', function() {
dom.fakeEvent(controller.__checkbox, 'click');
});
dom.bind(controller.__checkbox, 'click', function(e) {
e.stopPropagation(); // Prevents double-toggle
});
}
else if (controller instanceof FunctionController) {
dom.bind(li, 'click', function() {
dom.fakeEvent(controller.__button, 'click');
});
dom.bind(li, 'mouseover', function() {
dom.addClass(controller.__button, 'hover');
});
dom.bind(li, 'mouseout', function() {
dom.removeClass(controller.__button, 'hover');
});
}
else if (controller instanceof ColorController) {
dom.addClass(li, 'color');
controller.updateDisplay = common.compose(function(r) {
li.style.borderLeftColor = controller.__color.toString();
return r;
}, controller.updateDisplay);
controller.updateDisplay();
}
controller.setValue = common.compose(function(r) {
if (gui.getRoot().__preset_select && controller.isModified()) {
markPresetModified(gui.getRoot(), true);
}
return r;
}, controller.setValue);
}
function recallSavedValue(gui, controller) {
// Find the topmost GUI, that's where remembered objects live.
var root = gui.getRoot();
// Does the object we're controlling match anything we've been told to
// remember?
var matched_index = root.__rememberedObjects.indexOf(controller.object);
// Why yes, it does!
if (matched_index != -1) {
// Let me fetch a map of controllers for thcommon.isObject.
var controller_map =
root.__rememberedObjectIndecesToControllers[matched_index];
// Ohp, I believe this is the first controller we've created for this
// object. Lets make the map fresh.
if (controller_map === undefined) {
controller_map = {};
root.__rememberedObjectIndecesToControllers[matched_index] =
controller_map;
}
// Keep track of this controller
controller_map[controller.property] = controller;
// Okay, now have we saved any values for this controller?
if (root.load && root.load.remembered) {
var preset_map = root.load.remembered;
// Which preset are we trying to load?
var preset;
if (preset_map[gui.preset]) {
preset = preset_map[gui.preset];
} else if (preset_map[DEFAULT_DEFAULT_PRESET_NAME]) {
// Uhh, you can have the default instead?
preset = preset_map[DEFAULT_DEFAULT_PRESET_NAME];
} else {
// Nada.
return;
}
// Did the loaded object remember thcommon.isObject?
if (preset[matched_index] &&
// Did we remember this particular property?
preset[matched_index][controller.property] !== undefined) {
// We did remember something for this guy ...
var value = preset[matched_index][controller.property];
// And that's what it is.
controller.initialValue = value;
controller.setValue(value);
}
}
}
}
function getLocalStorageHash(gui, key) {
// TODO how does this deal with multiple GUI's?
return document.location.href + '.' + key;
}
function addSaveMenu(gui) {
var div = gui.__save_row = document.createElement('li');
dom.addClass(gui.domElement, 'has-save');
gui.__ul.insertBefore(div, gui.__ul.firstChild);
dom.addClass(div, 'save-row');
var gears = document.createElement('span');
gears.innerHTML = ' ';
dom.addClass(gears, 'button gears');
// TODO replace with FunctionController
var button = document.createElement('span');
button.innerHTML = 'Save';
dom.addClass(button, 'button');
dom.addClass(button, 'save');
var button2 = document.createElement('span');
button2.innerHTML = 'New';
dom.addClass(button2, 'button');
dom.addClass(button2, 'save-as');
var button3 = document.createElement('span');
button3.innerHTML = 'Revert';
dom.addClass(button3, 'button');
dom.addClass(button3, 'revert');
var select = gui.__preset_select = document.createElement('select');
if (gui.load && gui.load.remembered) {
common.each(gui.load.remembered, function(value, key) {
addPresetOption(gui, key, key == gui.preset);
});
} else {
addPresetOption(gui, DEFAULT_DEFAULT_PRESET_NAME, false);
}
dom.bind(select, 'change', function() {
for (var index = 0; index < gui.__preset_select.length; index++) {
gui.__preset_select[index].innerHTML = gui.__preset_select[index].value;
}
gui.preset = this.value;
});
div.appendChild(select);
div.appendChild(gears);
div.appendChild(button);
div.appendChild(button2);
div.appendChild(button3);
if (SUPPORTS_LOCAL_STORAGE) {
var saveLocally = document.getElementById('dg-save-locally');
var explain = document.getElementById('dg-local-explain');
saveLocally.style.display = 'block';
var localStorageCheckBox = document.getElementById('dg-local-storage');
if (localStorage.getItem(getLocalStorageHash(gui, 'isLocal')) === 'true') {
localStorageCheckBox.setAttribute('checked', 'checked');
}
function showHideExplain() {
explain.style.display = gui.useLocalStorage ? 'block' : 'none';
}
showHideExplain();
// TODO: Use a boolean controller, fool!
dom.bind(localStorageCheckBox, 'change', function() {
gui.useLocalStorage = !gui.useLocalStorage;
showHideExplain();
});
}
var newConstructorTextArea = document.getElementById('dg-new-constructor');
dom.bind(newConstructorTextArea, 'keydown', function(e) {
if (e.metaKey && (e.which === 67 || e.keyCode == 67)) {
SAVE_DIALOGUE.hide();
}
});
dom.bind(gears, 'click', function() {
newConstructorTextArea.innerHTML = JSON.stringify(gui.getSaveObject(), undefined, 2);
SAVE_DIALOGUE.show();
newConstructorTextArea.focus();
newConstructorTextArea.select();
});
dom.bind(button, 'click', function() {
gui.save();
});
dom.bind(button2, 'click', function() {
var presetName = prompt('Enter a new preset name.');
if (presetName) gui.saveAs(presetName);
});
dom.bind(button3, 'click', function() {
gui.revert();
});
// div.appendChild(button2);
}
function addResizeHandle(gui) {
gui.__resize_handle = document.createElement('div');
common.extend(gui.__resize_handle.style, {
width: '6px',
marginLeft: '-3px',
height: '200px',
cursor: 'ew-resize',
position: 'absolute'
// border: '1px solid blue'
});
var pmouseX;
dom.bind(gui.__resize_handle, 'mousedown', dragStart);
dom.bind(gui.__closeButton, 'mousedown', dragStart);
gui.domElement.insertBefore(gui.__resize_handle, gui.domElement.firstElementChild);
function dragStart(e) {
e.preventDefault();
pmouseX = e.clientX;
dom.addClass(gui.__closeButton, GUI.CLASS_DRAG);
dom.bind(window, 'mousemove', drag);
dom.bind(window, 'mouseup', dragStop);
return false;
}
function drag(e) {
e.preventDefault();
gui.width += pmouseX - e.clientX;
gui.onResize();
pmouseX = e.clientX;
return false;
}
function dragStop() {
dom.removeClass(gui.__closeButton, GUI.CLASS_DRAG);
dom.unbind(window, 'mousemove', drag);
dom.unbind(window, 'mouseup', dragStop);
}
}
function setWidth(gui, w) {
gui.domElement.style.width = w + 'px';
// Auto placed save-rows are position fixed, so we have to
// set the width manually if we want it to bleed to the edge
if (gui.__save_row && gui.autoPlace) {
gui.__save_row.style.width = w + 'px';
}if (gui.__closeButton) {
gui.__closeButton.style.width = w + 'px';
}
}
function getCurrentPreset(gui, useInitialValues) {
var toReturn = {};
// For each object I'm remembering
common.each(gui.__rememberedObjects, function(val, index) {
var saved_values = {};
// The controllers I've made for thcommon.isObject by property
var controller_map =
gui.__rememberedObjectIndecesToControllers[index];
// Remember each value for each property
common.each(controller_map, function(controller, property) {
saved_values[property] = useInitialValues ? controller.initialValue : controller.getValue();
});
// Save the values for thcommon.isObject
toReturn[index] = saved_values;
});
return toReturn;
}
function addPresetOption(gui, name, setSelected) {
var opt = document.createElement('option');
opt.innerHTML = name;
opt.value = name;
gui.__preset_select.appendChild(opt);
if (setSelected) {
gui.__preset_select.selectedIndex = gui.__preset_select.length - 1;
}
}
function setPresetSelectIndex(gui) {
for (var index = 0; index < gui.__preset_select.length; index++) {
if (gui.__preset_select[index].value == gui.preset) {
gui.__preset_select.selectedIndex = index;
}
}
}
function markPresetModified(gui, modified) {
var opt = gui.__preset_select[gui.__preset_select.selectedIndex];
// console.log('mark', modified, opt);
if (modified) {
opt.innerHTML = opt.value + "*";
} else {
opt.innerHTML = opt.value;
}
}
function updateDisplays(controllerArray) {
if (controllerArray.length != 0) {
requestAnimationFrame(function() {
updateDisplays(controllerArray);
});
}
common.each(controllerArray, function(c) {
c.updateDisplay();
});
}
return GUI;
})(dat.utils.css,
"
\n\n Here's the new load parameter for your GUI's constructor:\n\n \n\n
\n\n Automatically save\n values to localStorage on exit.\n\n
The values saved to localStorage will\n override those passed to dat.GUI's constructor. This makes it\n easier to work incrementally, but localStorage is fragile,\n and your friends may not see the same values you do.\n \n
\n \n
\n\n
",
".dg ul{list-style:none;margin:0;padding:0;width:100%;clear:both}.dg.ac{position:fixed;top:0;left:0;right:0;height:0;z-index:0}.dg:not(.ac) .main{overflow:hidden}.dg.main{-webkit-transition:opacity 0.1s linear;-o-transition:opacity 0.1s linear;-moz-transition:opacity 0.1s linear;transition:opacity 0.1s linear}.dg.main.taller-than-window{overflow-y:auto}.dg.main.taller-than-window .close-button{opacity:1;margin-top:-1px;border-top:1px solid #2c2c2c}.dg.main ul.closed .close-button{opacity:1 !important}.dg.main:hover .close-button,.dg.main .close-button.drag{opacity:1}.dg.main .close-button{-webkit-transition:opacity 0.1s linear;-o-transition:opacity 0.1s linear;-moz-transition:opacity 0.1s linear;transition:opacity 0.1s linear;border:0;position:absolute;line-height:19px;height:20px;cursor:pointer;text-align:center;background-color:#000}.dg.main .close-button:hover{background-color:#111}.dg.a{float:right;margin-right:15px;overflow-x:hidden}.dg.a.has-save ul{margin-top:27px}.dg.a.has-save ul.closed{margin-top:0}.dg.a .save-row{position:fixed;top:0;z-index:1002}.dg li{-webkit-transition:height 0.1s ease-out;-o-transition:height 0.1s ease-out;-moz-transition:height 0.1s ease-out;transition:height 0.1s ease-out}.dg li:not(.folder){cursor:auto;height:27px;line-height:27px;overflow:hidden;padding:0 4px 0 5px}.dg li.folder{padding:0;border-left:4px solid rgba(0,0,0,0)}.dg li.title{cursor:pointer;margin-left:-4px}.dg .closed li:not(.title),.dg .closed ul li,.dg .closed ul li > *{height:0;overflow:hidden;border:0}.dg .cr{clear:both;padding-left:3px;height:27px}.dg .property-name{cursor:default;float:left;clear:left;width:40%;overflow:hidden;text-overflow:ellipsis}.dg .c{float:left;width:60%}.dg .c input[type=text]{border:0;margin-top:4px;padding:3px;width:100%;float:right}.dg .has-slider input[type=text]{width:30%;margin-left:0}.dg .slider{float:left;width:66%;margin-left:-5px;margin-right:0;height:19px;margin-top:4px}.dg .slider-fg{height:100%}.dg .c input[type=checkbox]{margin-top:9px}.dg .c select{margin-top:5px}.dg .cr.function,.dg .cr.function .property-name,.dg .cr.function *,.dg .cr.boolean,.dg .cr.boolean *{cursor:pointer}.dg .selector{display:none;position:absolute;margin-left:-9px;margin-top:23px;z-index:10}.dg .c:hover .selector,.dg .selector.drag{display:block}.dg li.save-row{padding:0}.dg li.save-row .button{display:inline-block;padding:0px 6px}.dg.dialogue{background-color:#222;width:460px;padding:15px;font-size:13px;line-height:15px}#dg-new-constructor{padding:10px;color:#222;font-family:Monaco, monospace;font-size:10px;border:0;resize:none;box-shadow:inset 1px 1px 1px #888;word-wrap:break-word;margin:12px 0;display:block;width:440px;overflow-y:scroll;height:100px;position:relative}#dg-local-explain{display:none;font-size:11px;line-height:17px;border-radius:3px;background-color:#333;padding:8px;margin-top:10px}#dg-local-explain code{font-size:10px}#dat-gui-save-locally{display:none}.dg{color:#eee;font:11px 'Lucida Grande', sans-serif;text-shadow:0 -1px 0 #111}.dg.main::-webkit-scrollbar{width:5px;background:#1a1a1a}.dg.main::-webkit-scrollbar-corner{height:0;display:none}.dg.main::-webkit-scrollbar-thumb{border-radius:5px;background:#676767}.dg li:not(.folder){background:#1a1a1a;border-bottom:1px solid #2c2c2c}.dg li.save-row{line-height:25px;background:#dad5cb;border:0}.dg li.save-row select{margin-left:5px;width:108px}.dg li.save-row .button{margin-left:5px;margin-top:1px;border-radius:2px;font-size:9px;line-height:7px;padding:4px 4px 5px 4px;background:#c5bdad;color:#fff;text-shadow:0 1px 0 #b0a58f;box-shadow:0 -1px 0 #b0a58f;cursor:pointer}.dg li.save-row .button.gears{background:#c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;height:7px;width:8px}.dg li.save-row .button:hover{background-color:#bab19e;box-shadow:0 -1px 0 #b0a58f}.dg li.folder{border-bottom:0}.dg li.title{padding-left:16px;background:#000 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;cursor:pointer;border-bottom:1px solid rgba(255,255,255,0.2)}.dg .closed li.title{background-image:url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==)}.dg .cr.boolean{border-left:3px solid #806787}.dg .cr.function{border-left:3px solid #e61d5f}.dg .cr.number{border-left:3px solid #2fa1d6}.dg .cr.number input[type=text]{color:#2fa1d6}.dg .cr.string{border-left:3px solid #1ed36f}.dg .cr.string input[type=text]{color:#1ed36f}.dg .cr.function:hover,.dg .cr.boolean:hover{background:#111}.dg .c input[type=text]{background:#303030;outline:none}.dg .c input[type=text]:hover{background:#3c3c3c}.dg .c input[type=text]:focus{background:#494949;color:#fff}.dg .c .slider{background:#303030;cursor:ew-resize}.dg .c .slider-fg{background:#2fa1d6}.dg .c .slider:hover{background:#3c3c3c}.dg .c .slider:hover .slider-fg{background:#44abda}\n",
dat.controllers.factory = (function (OptionController, NumberControllerBox, NumberControllerSlider, StringController, FunctionController, BooleanController, common) {
return function(object, property) {
var initialValue = object[property];
// Providing options?
if (common.isArray(arguments[2]) || common.isObject(arguments[2])) {
return new OptionController(object, property, arguments[2]);
}
// Providing a map?
if (common.isNumber(initialValue)) {
if (common.isNumber(arguments[2]) && common.isNumber(arguments[3])) {
// Has min and max.
return new NumberControllerSlider(object, property, arguments[2], arguments[3]);
} else {
return new NumberControllerBox(object, property, { min: arguments[2], max: arguments[3] });
}
}
if (common.isString(initialValue)) {
return new StringController(object, property);
}
if (common.isFunction(initialValue)) {
return new FunctionController(object, property, '');
}
if (common.isBoolean(initialValue)) {
return new BooleanController(object, property);
}
}
})(dat.controllers.OptionController,
dat.controllers.NumberControllerBox,
dat.controllers.NumberControllerSlider,
dat.controllers.StringController = (function (Controller, dom, common) {
/**
* @class Provides a text input to alter the string property of an object.
*
* @extends dat.controllers.Controller
*
* @param {Object} object The object to be manipulated
* @param {string} property The name of the property to be manipulated
*
* @member dat.controllers
*/
var StringController = function(object, property) {
StringController.superclass.call(this, object, property);
var _this = this;
this.__input = document.createElement('input');
this.__input.setAttribute('type', 'text');
dom.bind(this.__input, 'keyup', onChange);
dom.bind(this.__input, 'change', onChange);
dom.bind(this.__input, 'blur', onBlur);
dom.bind(this.__input, 'keydown', function(e) {
if (e.keyCode === 13) {
this.blur();
}
});
function onChange() {
_this.setValue(_this.__input.value);
}
function onBlur() {
if (_this.__onFinishChange) {
_this.__onFinishChange.call(_this, _this.getValue());
}
}
this.updateDisplay();
this.domElement.appendChild(this.__input);
};
StringController.superclass = Controller;
common.extend(
StringController.prototype,
Controller.prototype,
{
updateDisplay: function() {
// Stops the caret from moving on account of:
// keyup -> setValue -> updateDisplay
if (!dom.isActive(this.__input)) {
this.__input.value = this.getValue();
}
return StringController.superclass.prototype.updateDisplay.call(this);
}
}
);
return StringController;
})(dat.controllers.Controller,
dat.dom.dom,
dat.utils.common),
dat.controllers.FunctionController,
dat.controllers.BooleanController,
dat.utils.common),
dat.controllers.Controller,
dat.controllers.BooleanController,
dat.controllers.FunctionController,
dat.controllers.NumberControllerBox,
dat.controllers.NumberControllerSlider,
dat.controllers.OptionController,
dat.controllers.ColorController = (function (Controller, dom, Color, interpret, common) {
var ColorController = function(object, property) {
ColorController.superclass.call(this, object, property);
this.__color = new Color(this.getValue());
this.__temp = new Color(0);
var _this = this;
this.domElement = document.createElement('div');
dom.makeSelectable(this.domElement, false);
this.__selector = document.createElement('div');
this.__selector.className = 'selector';
this.__saturation_field = document.createElement('div');
this.__saturation_field.className = 'saturation-field';
this.__field_knob = document.createElement('div');
this.__field_knob.className = 'field-knob';
this.__field_knob_border = '2px solid ';
this.__hue_knob = document.createElement('div');
this.__hue_knob.className = 'hue-knob';
this.__hue_field = document.createElement('div');
this.__hue_field.className = 'hue-field';
this.__input = document.createElement('input');
this.__input.type = 'text';
this.__input_textShadow = '0 1px 1px ';
dom.bind(this.__input, 'keydown', function(e) {
if (e.keyCode === 13) { // on enter
onBlur.call(this);
}
});
dom.bind(this.__input, 'blur', onBlur);
dom.bind(this.__selector, 'mousedown', function(e) {
dom
.addClass(this, 'drag')
.bind(window, 'mouseup', function(e) {
dom.removeClass(_this.__selector, 'drag');
});
});
var value_field = document.createElement('div');
common.extend(this.__selector.style, {
width: '122px',
height: '102px',
padding: '3px',
backgroundColor: '#222',
boxShadow: '0px 1px 3px rgba(0,0,0,0.3)'
});
common.extend(this.__field_knob.style, {
position: 'absolute',
width: '12px',
height: '12px',
border: this.__field_knob_border + (this.__color.v < .5 ? '#fff' : '#000'),
boxShadow: '0px 1px 3px rgba(0,0,0,0.5)',
borderRadius: '12px',
zIndex: 1
});
common.extend(this.__hue_knob.style, {
position: 'absolute',
width: '15px',
height: '2px',
borderRight: '4px solid #fff',
zIndex: 1
});
common.extend(this.__saturation_field.style, {
width: '100px',
height: '100px',
border: '1px solid #555',
marginRight: '3px',
display: 'inline-block',
cursor: 'pointer'
});
common.extend(value_field.style, {
width: '100%',
height: '100%',
background: 'none'
});
linearGradient(value_field, 'top', 'rgba(0,0,0,0)', '#000');
common.extend(this.__hue_field.style, {
width: '15px',
height: '100px',
display: 'inline-block',
border: '1px solid #555',
cursor: 'ns-resize'
});
hueGradient(this.__hue_field);
common.extend(this.__input.style, {
outline: 'none',
// width: '120px',
textAlign: 'center',
// padding: '4px',
// marginBottom: '6px',
color: '#fff',
border: 0,
fontWeight: 'bold',
textShadow: this.__input_textShadow + 'rgba(0,0,0,0.7)'
});
dom.bind(this.__saturation_field, 'mousedown', fieldDown);
dom.bind(this.__field_knob, 'mousedown', fieldDown);
dom.bind(this.__hue_field, 'mousedown', function(e) {
setH(e);
dom.bind(window, 'mousemove', setH);
dom.bind(window, 'mouseup', unbindH);
});
function fieldDown(e) {
setSV(e);
// document.body.style.cursor = 'none';
dom.bind(window, 'mousemove', setSV);
dom.bind(window, 'mouseup', unbindSV);
}
function unbindSV() {
dom.unbind(window, 'mousemove', setSV);
dom.unbind(window, 'mouseup', unbindSV);
// document.body.style.cursor = 'default';
}
function onBlur() {
var i = interpret(this.value);
if (i !== false) {
_this.__color.__state = i;
_this.setValue(_this.__color.toOriginal());
} else {
this.value = _this.__color.toString();
}
}
function unbindH() {
dom.unbind(window, 'mousemove', setH);
dom.unbind(window, 'mouseup', unbindH);
}
this.__saturation_field.appendChild(value_field);
this.__selector.appendChild(this.__field_knob);
this.__selector.appendChild(this.__saturation_field);
this.__selector.appendChild(this.__hue_field);
this.__hue_field.appendChild(this.__hue_knob);
this.domElement.appendChild(this.__input);
this.domElement.appendChild(this.__selector);
this.updateDisplay();
function setSV(e) {
e.preventDefault();
var w = dom.getWidth(_this.__saturation_field);
var o = dom.getOffset(_this.__saturation_field);
var s = (e.clientX - o.left + document.body.scrollLeft) / w;
var v = 1 - (e.clientY - o.top + document.body.scrollTop) / w;
if (v > 1) v = 1;
else if (v < 0) v = 0;
if (s > 1) s = 1;
else if (s < 0) s = 0;
_this.__color.v = v;
_this.__color.s = s;
_this.setValue(_this.__color.toOriginal());
return false;
}
function setH(e) {
e.preventDefault();
var s = dom.getHeight(_this.__hue_field);
var o = dom.getOffset(_this.__hue_field);
var h = 1 - (e.clientY - o.top + document.body.scrollTop) / s;
if (h > 1) h = 1;
else if (h < 0) h = 0;
_this.__color.h = h * 360;
_this.setValue(_this.__color.toOriginal());
return false;
}
};
ColorController.superclass = Controller;
common.extend(
ColorController.prototype,
Controller.prototype,
{
updateDisplay: function() {
var i = interpret(this.getValue());
if (i !== false) {
var mismatch = false;
// Check for mismatch on the interpreted value.
common.each(Color.COMPONENTS, function(component) {
if (!common.isUndefined(i[component]) &&
!common.isUndefined(this.__color.__state[component]) &&
i[component] !== this.__color.__state[component]) {
mismatch = true;
return {}; // break
}
}, this);
// If nothing diverges, we keep our previous values
// for statefulness, otherwise we recalculate fresh
if (mismatch) {
common.extend(this.__color.__state, i);
}
}
common.extend(this.__temp.__state, this.__color.__state);
this.__temp.a = 1;
var flip = (this.__color.v < .5 || this.__color.s > .5) ? 255 : 0;
var _flip = 255 - flip;
common.extend(this.__field_knob.style, {
marginLeft: 100 * this.__color.s - 7 + 'px',
marginTop: 100 * (1 - this.__color.v) - 7 + 'px',
backgroundColor: this.__temp.toString(),
border: this.__field_knob_border + 'rgb(' + flip + ',' + flip + ',' + flip +')'
});
this.__hue_knob.style.marginTop = (1 - this.__color.h / 360) * 100 + 'px';
this.__temp.s = 1;
this.__temp.v = 1;
linearGradient(this.__saturation_field, 'left', '#fff', this.__temp.toString());
common.extend(this.__input.style, {
backgroundColor: this.__input.value = this.__color.toString(),
color: 'rgb(' + flip + ',' + flip + ',' + flip +')',
textShadow: this.__input_textShadow + 'rgba(' + _flip + ',' + _flip + ',' + _flip +',.7)'
});
}
}
);
var vendors = ['-moz-','-o-','-webkit-','-ms-',''];
function linearGradient(elem, x, a, b) {
elem.style.background = '';
common.each(vendors, function(vendor) {
elem.style.cssText += 'background: ' + vendor + 'linear-gradient('+x+', '+a+' 0%, ' + b + ' 100%); ';
});
}
function hueGradient(elem) {
elem.style.background = '';
elem.style.cssText += 'background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);';
elem.style.cssText += 'background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);';
elem.style.cssText += 'background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);';
elem.style.cssText += 'background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);';
elem.style.cssText += 'background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);';
}
return ColorController;
})(dat.controllers.Controller,
dat.dom.dom,
dat.color.Color = (function (interpret, math, toString, common) {
var Color = function() {
this.__state = interpret.apply(this, arguments);
if (this.__state === false) {
throw 'Failed to interpret color arguments';
}
this.__state.a = this.__state.a || 1;
};
Color.COMPONENTS = ['r','g','b','h','s','v','hex','a'];
common.extend(Color.prototype, {
toString: function() {
return toString(this);
},
toOriginal: function() {
return this.__state.conversion.write(this);
}
});
defineRGBComponent(Color.prototype, 'r', 2);
defineRGBComponent(Color.prototype, 'g', 1);
defineRGBComponent(Color.prototype, 'b', 0);
defineHSVComponent(Color.prototype, 'h');
defineHSVComponent(Color.prototype, 's');
defineHSVComponent(Color.prototype, 'v');
Object.defineProperty(Color.prototype, 'a', {
get: function() {
return this.__state.a;
},
set: function(v) {
this.__state.a = v;
}
});
Object.defineProperty(Color.prototype, 'hex', {
get: function() {
if (!this.__state.space !== 'HEX') {
this.__state.hex = math.rgb_to_hex(this.r, this.g, this.b);
}
return this.__state.hex;
},
set: function(v) {
this.__state.space = 'HEX';
this.__state.hex = v;
}
});
function defineRGBComponent(target, component, componentHexIndex) {
Object.defineProperty(target, component, {
get: function() {
if (this.__state.space === 'RGB') {
return this.__state[component];
}
recalculateRGB(this, component, componentHexIndex);
return this.__state[component];
},
set: function(v) {
if (this.__state.space !== 'RGB') {
recalculateRGB(this, component, componentHexIndex);
this.__state.space = 'RGB';
}
this.__state[component] = v;
}
});
}
function defineHSVComponent(target, component) {
Object.defineProperty(target, component, {
get: function() {
if (this.__state.space === 'HSV')
return this.__state[component];
recalculateHSV(this);
return this.__state[component];
},
set: function(v) {
if (this.__state.space !== 'HSV') {
recalculateHSV(this);
this.__state.space = 'HSV';
}
this.__state[component] = v;
}
});
}
function recalculateRGB(color, component, componentHexIndex) {
if (color.__state.space === 'HEX') {
color.__state[component] = math.component_from_hex(color.__state.hex, componentHexIndex);
} else if (color.__state.space === 'HSV') {
common.extend(color.__state, math.hsv_to_rgb(color.__state.h, color.__state.s, color.__state.v));
} else {
throw 'Corrupted color state';
}
}
function recalculateHSV(color) {
var result = math.rgb_to_hsv(color.r, color.g, color.b);
common.extend(color.__state,
{
s: result.s,
v: result.v
}
);
if (!common.isNaN(result.h)) {
color.__state.h = result.h;
} else if (common.isUndefined(color.__state.h)) {
color.__state.h = 0;
}
}
return Color;
})(dat.color.interpret,
dat.color.math = (function () {
var tmpComponent;
return {
hsv_to_rgb: function(h, s, v) {
var hi = Math.floor(h / 60) % 6;
var f = h / 60 - Math.floor(h / 60);
var p = v * (1.0 - s);
var q = v * (1.0 - (f * s));
var t = v * (1.0 - ((1.0 - f) * s));
var c = [
[v, t, p],
[q, v, p],
[p, v, t],
[p, q, v],
[t, p, v],
[v, p, q]
][hi];
return {
r: c[0] * 255,
g: c[1] * 255,
b: c[2] * 255
};
},
rgb_to_hsv: function(r, g, b) {
var min = Math.min(r, g, b),
max = Math.max(r, g, b),
delta = max - min,
h, s;
if (max != 0) {
s = delta / max;
} else {
return {
h: NaN,
s: 0,
v: 0
};
}
if (r == max) {
h = (g - b) / delta;
} else if (g == max) {
h = 2 + (b - r) / delta;
} else {
h = 4 + (r - g) / delta;
}
h /= 6;
if (h < 0) {
h += 1;
}
return {
h: h * 360,
s: s,
v: max / 255
};
},
rgb_to_hex: function(r, g, b) {
var hex = this.hex_with_component(0, 2, r);
hex = this.hex_with_component(hex, 1, g);
hex = this.hex_with_component(hex, 0, b);
return hex;
},
component_from_hex: function(hex, componentIndex) {
return (hex >> (componentIndex * 8)) & 0xFF;
},
hex_with_component: function(hex, componentIndex, value) {
return value << (tmpComponent = componentIndex * 8) | (hex & ~ (0xFF << tmpComponent));
}
}
})(),
dat.color.toString,
dat.utils.common),
dat.color.interpret,
dat.utils.common),
dat.utils.requestAnimationFrame = (function () {
/**
* requirejs version of Paul Irish's RequestAnimationFrame
* http://paulirish.com/2011/requestanimationframe-for-smart-animating/
*/
return window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback, element) {
window.setTimeout(callback, 1000 / 60);
};
})(),
dat.dom.CenteredDiv = (function (dom, common) {
var CenteredDiv = function() {
this.backgroundElement = document.createElement('div');
common.extend(this.backgroundElement.style, {
backgroundColor: 'rgba(0,0,0,0.8)',
top: 0,
left: 0,
display: 'none',
zIndex: '1000',
opacity: 0,
WebkitTransition: 'opacity 0.2s linear'
});
dom.makeFullscreen(this.backgroundElement);
this.backgroundElement.style.position = 'fixed';
this.domElement = document.createElement('div');
common.extend(this.domElement.style, {
position: 'fixed',
display: 'none',
zIndex: '1001',
opacity: 0,
WebkitTransition: '-webkit-transform 0.2s ease-out, opacity 0.2s linear'
});
document.body.appendChild(this.backgroundElement);
document.body.appendChild(this.domElement);
var _this = this;
dom.bind(this.backgroundElement, 'click', function() {
_this.hide();
});
};
CenteredDiv.prototype.show = function() {
var _this = this;
this.backgroundElement.style.display = 'block';
this.domElement.style.display = 'block';
this.domElement.style.opacity = 0;
// this.domElement.style.top = '52%';
this.domElement.style.webkitTransform = 'scale(1.1)';
this.layout();
common.defer(function() {
_this.backgroundElement.style.opacity = 1;
_this.domElement.style.opacity = 1;
_this.domElement.style.webkitTransform = 'scale(1)';
});
};
CenteredDiv.prototype.hide = function() {
var _this = this;
var hide = function() {
_this.domElement.style.display = 'none';
_this.backgroundElement.style.display = 'none';
dom.unbind(_this.domElement, 'webkitTransitionEnd', hide);
dom.unbind(_this.domElement, 'transitionend', hide);
dom.unbind(_this.domElement, 'oTransitionEnd', hide);
};
dom.bind(this.domElement, 'webkitTransitionEnd', hide);
dom.bind(this.domElement, 'transitionend', hide);
dom.bind(this.domElement, 'oTransitionEnd', hide);
this.backgroundElement.style.opacity = 0;
// this.domElement.style.top = '48%';
this.domElement.style.opacity = 0;
this.domElement.style.webkitTransform = 'scale(1.1)';
};
CenteredDiv.prototype.layout = function() {
this.domElement.style.left = window.innerWidth/2 - dom.getWidth(this.domElement) / 2 + 'px';
this.domElement.style.top = window.innerHeight/2 - dom.getHeight(this.domElement) / 2 + 'px';
};
return CenteredDiv;
})(dat.dom.dom,
dat.utils.common),
dat.dom.dom,
dat.utils.common);
});
var dat_color = createCommonjsModule(function (module) {
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
/** @namespace */
var dat = module.exports = dat || {};
/** @namespace */
dat.color = dat.color || {};
/** @namespace */
dat.utils = dat.utils || {};
dat.utils.common = (function () {
var ARR_EACH = Array.prototype.forEach;
var ARR_SLICE = Array.prototype.slice;
/**
* Band-aid methods for things that should be a lot easier in JavaScript.
* Implementation and structure inspired by underscore.js
* http://documentcloud.github.com/underscore/
*/
return {
BREAK: {},
extend: function(target) {
this.each(ARR_SLICE.call(arguments, 1), function(obj) {
for (var key in obj)
if (!this.isUndefined(obj[key]))
target[key] = obj[key];
}, this);
return target;
},
defaults: function(target) {
this.each(ARR_SLICE.call(arguments, 1), function(obj) {
for (var key in obj)
if (this.isUndefined(target[key]))
target[key] = obj[key];
}, this);
return target;
},
compose: function() {
var toCall = ARR_SLICE.call(arguments);
return function() {
var args = ARR_SLICE.call(arguments);
for (var i = toCall.length -1; i >= 0; i--) {
args = [toCall[i].apply(this, args)];
}
return args[0];
}
},
each: function(obj, itr, scope) {
if (ARR_EACH && obj.forEach === ARR_EACH) {
obj.forEach(itr, scope);
} else if (obj.length === obj.length + 0) { // Is number but not NaN
for (var key = 0, l = obj.length; key < l; key++)
if (key in obj && itr.call(scope, obj[key], key) === this.BREAK)
return;
} else {
for (var key in obj)
if (itr.call(scope, obj[key], key) === this.BREAK)
return;
}
},
defer: function(fnc) {
setTimeout(fnc, 0);
},
toArray: function(obj) {
if (obj.toArray) return obj.toArray();
return ARR_SLICE.call(obj);
},
isUndefined: function(obj) {
return obj === undefined;
},
isNull: function(obj) {
return obj === null;
},
isNaN: function(obj) {
return obj !== obj;
},
isArray: Array.isArray || function(obj) {
return obj.constructor === Array;
},
isObject: function(obj) {
return obj === Object(obj);
},
isNumber: function(obj) {
return obj === obj+0;
},
isString: function(obj) {
return obj === obj+'';
},
isBoolean: function(obj) {
return obj === false || obj === true;
},
isFunction: function(obj) {
return Object.prototype.toString.call(obj) === '[object Function]';
}
};
})();
dat.color.toString = (function (common) {
return function(color) {
if (color.a == 1 || common.isUndefined(color.a)) {
var s = color.hex.toString(16);
while (s.length < 6) {
s = '0' + s;
}
return '#' + s;
} else {
return 'rgba(' + Math.round(color.r) + ',' + Math.round(color.g) + ',' + Math.round(color.b) + ',' + color.a + ')';
}
}
})(dat.utils.common);
dat.Color = dat.color.Color = (function (interpret, math, toString, common) {
var Color = function() {
this.__state = interpret.apply(this, arguments);
if (this.__state === false) {
throw 'Failed to interpret color arguments';
}
this.__state.a = this.__state.a || 1;
};
Color.COMPONENTS = ['r','g','b','h','s','v','hex','a'];
common.extend(Color.prototype, {
toString: function() {
return toString(this);
},
toOriginal: function() {
return this.__state.conversion.write(this);
}
});
defineRGBComponent(Color.prototype, 'r', 2);
defineRGBComponent(Color.prototype, 'g', 1);
defineRGBComponent(Color.prototype, 'b', 0);
defineHSVComponent(Color.prototype, 'h');
defineHSVComponent(Color.prototype, 's');
defineHSVComponent(Color.prototype, 'v');
Object.defineProperty(Color.prototype, 'a', {
get: function() {
return this.__state.a;
},
set: function(v) {
this.__state.a = v;
}
});
Object.defineProperty(Color.prototype, 'hex', {
get: function() {
if (!this.__state.space !== 'HEX') {
this.__state.hex = math.rgb_to_hex(this.r, this.g, this.b);
}
return this.__state.hex;
},
set: function(v) {
this.__state.space = 'HEX';
this.__state.hex = v;
}
});
function defineRGBComponent(target, component, componentHexIndex) {
Object.defineProperty(target, component, {
get: function() {
if (this.__state.space === 'RGB') {
return this.__state[component];
}
recalculateRGB(this, component, componentHexIndex);
return this.__state[component];
},
set: function(v) {
if (this.__state.space !== 'RGB') {
recalculateRGB(this, component, componentHexIndex);
this.__state.space = 'RGB';
}
this.__state[component] = v;
}
});
}
function defineHSVComponent(target, component) {
Object.defineProperty(target, component, {
get: function() {
if (this.__state.space === 'HSV')
return this.__state[component];
recalculateHSV(this);
return this.__state[component];
},
set: function(v) {
if (this.__state.space !== 'HSV') {
recalculateHSV(this);
this.__state.space = 'HSV';
}
this.__state[component] = v;
}
});
}
function recalculateRGB(color, component, componentHexIndex) {
if (color.__state.space === 'HEX') {
color.__state[component] = math.component_from_hex(color.__state.hex, componentHexIndex);
} else if (color.__state.space === 'HSV') {
common.extend(color.__state, math.hsv_to_rgb(color.__state.h, color.__state.s, color.__state.v));
} else {
throw 'Corrupted color state';
}
}
function recalculateHSV(color) {
var result = math.rgb_to_hsv(color.r, color.g, color.b);
common.extend(color.__state,
{
s: result.s,
v: result.v
}
);
if (!common.isNaN(result.h)) {
color.__state.h = result.h;
} else if (common.isUndefined(color.__state.h)) {
color.__state.h = 0;
}
}
return Color;
})(dat.color.interpret = (function (toString, common) {
var result, toReturn;
var interpret = function() {
toReturn = false;
var original = arguments.length > 1 ? common.toArray(arguments) : arguments[0];
common.each(INTERPRETATIONS, function(family) {
if (family.litmus(original)) {
common.each(family.conversions, function(conversion, conversionName) {
result = conversion.read(original);
if (toReturn === false && result !== false) {
toReturn = result;
result.conversionName = conversionName;
result.conversion = conversion;
return common.BREAK;
}
});
return common.BREAK;
}
});
return toReturn;
};
var INTERPRETATIONS = [
// Strings
{
litmus: common.isString,
conversions: {
THREE_CHAR_HEX: {
read: function(original) {
var test = original.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i);
if (test === null) return false;
return {
space: 'HEX',
hex: parseInt(
'0x' +
test[1].toString() + test[1].toString() +
test[2].toString() + test[2].toString() +
test[3].toString() + test[3].toString())
};
},
write: toString
},
SIX_CHAR_HEX: {
read: function(original) {
var test = original.match(/^#([A-F0-9]{6})$/i);
if (test === null) return false;
return {
space: 'HEX',
hex: parseInt('0x' + test[1].toString())
};
},
write: toString
},
CSS_RGB: {
read: function(original) {
var test = original.match(/^rgb\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/);
if (test === null) return false;
return {
space: 'RGB',
r: parseFloat(test[1]),
g: parseFloat(test[2]),
b: parseFloat(test[3])
};
},
write: toString
},
CSS_RGBA: {
read: function(original) {
var test = original.match(/^rgba\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\,\s*(.+)\s*\)/);
if (test === null) return false;
return {
space: 'RGB',
r: parseFloat(test[1]),
g: parseFloat(test[2]),
b: parseFloat(test[3]),
a: parseFloat(test[4])
};
},
write: toString
}
}
},
// Numbers
{
litmus: common.isNumber,
conversions: {
HEX: {
read: function(original) {
return {
space: 'HEX',
hex: original,
conversionName: 'HEX'
}
},
write: function(color) {
return color.hex;
}
}
}
},
// Arrays
{
litmus: common.isArray,
conversions: {
RGB_ARRAY: {
read: function(original) {
if (original.length != 3) return false;
return {
space: 'RGB',
r: original[0],
g: original[1],
b: original[2]
};
},
write: function(color) {
return [color.r, color.g, color.b];
}
},
RGBA_ARRAY: {
read: function(original) {
if (original.length != 4) return false;
return {
space: 'RGB',
r: original[0],
g: original[1],
b: original[2],
a: original[3]
};
},
write: function(color) {
return [color.r, color.g, color.b, color.a];
}
}
}
},
// Objects
{
litmus: common.isObject,
conversions: {
RGBA_OBJ: {
read: function(original) {
if (common.isNumber(original.r) &&
common.isNumber(original.g) &&
common.isNumber(original.b) &&
common.isNumber(original.a)) {
return {
space: 'RGB',
r: original.r,
g: original.g,
b: original.b,
a: original.a
}
}
return false;
},
write: function(color) {
return {
r: color.r,
g: color.g,
b: color.b,
a: color.a
}
}
},
RGB_OBJ: {
read: function(original) {
if (common.isNumber(original.r) &&
common.isNumber(original.g) &&
common.isNumber(original.b)) {
return {
space: 'RGB',
r: original.r,
g: original.g,
b: original.b
}
}
return false;
},
write: function(color) {
return {
r: color.r,
g: color.g,
b: color.b
}
}
},
HSVA_OBJ: {
read: function(original) {
if (common.isNumber(original.h) &&
common.isNumber(original.s) &&
common.isNumber(original.v) &&
common.isNumber(original.a)) {
return {
space: 'HSV',
h: original.h,
s: original.s,
v: original.v,
a: original.a
}
}
return false;
},
write: function(color) {
return {
h: color.h,
s: color.s,
v: color.v,
a: color.a
}
}
},
HSV_OBJ: {
read: function(original) {
if (common.isNumber(original.h) &&
common.isNumber(original.s) &&
common.isNumber(original.v)) {
return {
space: 'HSV',
h: original.h,
s: original.s,
v: original.v
}
}
return false;
},
write: function(color) {
return {
h: color.h,
s: color.s,
v: color.v
}
}
}
}
}
];
return interpret;
})(dat.color.toString,
dat.utils.common),
dat.color.math = (function () {
var tmpComponent;
return {
hsv_to_rgb: function(h, s, v) {
var hi = Math.floor(h / 60) % 6;
var f = h / 60 - Math.floor(h / 60);
var p = v * (1.0 - s);
var q = v * (1.0 - (f * s));
var t = v * (1.0 - ((1.0 - f) * s));
var c = [
[v, t, p],
[q, v, p],
[p, v, t],
[p, q, v],
[t, p, v],
[v, p, q]
][hi];
return {
r: c[0] * 255,
g: c[1] * 255,
b: c[2] * 255
};
},
rgb_to_hsv: function(r, g, b) {
var min = Math.min(r, g, b),
max = Math.max(r, g, b),
delta = max - min,
h, s;
if (max != 0) {
s = delta / max;
} else {
return {
h: NaN,
s: 0,
v: 0
};
}
if (r == max) {
h = (g - b) / delta;
} else if (g == max) {
h = 2 + (b - r) / delta;
} else {
h = 4 + (r - g) / delta;
}
h /= 6;
if (h < 0) {
h += 1;
}
return {
h: h * 360,
s: s,
v: max / 255
};
},
rgb_to_hex: function(r, g, b) {
var hex = this.hex_with_component(0, 2, r);
hex = this.hex_with_component(hex, 1, g);
hex = this.hex_with_component(hex, 0, b);
return hex;
},
component_from_hex: function(hex, componentIndex) {
return (hex >> (componentIndex * 8)) & 0xFF;
},
hex_with_component: function(hex, componentIndex, value) {
return value << (tmpComponent = componentIndex * 8) | (hex & ~ (0xFF << tmpComponent));
}
}
})(),
dat.color.toString,
dat.utils.common);
});
var index = dat_gui;
var color = dat_color;
index.color = color;
// Polyfills
if ( Number.EPSILON === undefined ) {
Number.EPSILON = Math.pow( 2, - 52 );
}
if ( Number.isInteger === undefined ) {
// Missing in IE
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger
Number.isInteger = function ( value ) {
return typeof value === 'number' && isFinite( value ) && Math.floor( value ) === value;
};
}
//
if ( Math.sign === undefined ) {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign
Math.sign = function ( x ) {
return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : + x;
};
}
if ( Function.prototype.name === undefined ) {
// Missing in IE
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name
Object.defineProperty( Function.prototype, 'name', {
get: function () {
return this.toString().match( /^\s*function\s*([^\(\s]*)/ )[ 1 ];
}
} );
}
if ( Object.assign === undefined ) {
// Missing in IE
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
( function () {
Object.assign = function ( target ) {
if ( target === undefined || target === null ) {
throw new TypeError( 'Cannot convert undefined or null to object' );
}
var output = Object( target );
for ( var index = 1; index < arguments.length; index ++ ) {
var source = arguments[ index ];
if ( source !== undefined && source !== null ) {
for ( var nextKey in source ) {
if ( Object.prototype.hasOwnProperty.call( source, nextKey ) ) {
output[ nextKey ] = source[ nextKey ];
}
}
}
}
return output;
};
} )();
}
/**
* https://github.com/mrdoob/eventdispatcher.js/
*/
function EventDispatcher() {}
Object.assign( EventDispatcher.prototype, {
addEventListener: function ( type, listener ) {
if ( this._listeners === undefined ) this._listeners = {};
var listeners = this._listeners;
if ( listeners[ type ] === undefined ) {
listeners[ type ] = [];
}
if ( listeners[ type ].indexOf( listener ) === - 1 ) {
listeners[ type ].push( listener );
}
},
hasEventListener: function ( type, listener ) {
if ( this._listeners === undefined ) return false;
var listeners = this._listeners;
return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1;
},
removeEventListener: function ( type, listener ) {
if ( this._listeners === undefined ) return;
var listeners = this._listeners;
var listenerArray = listeners[ type ];
if ( listenerArray !== undefined ) {
var index = listenerArray.indexOf( listener );
if ( index !== - 1 ) {
listenerArray.splice( index, 1 );
}
}
},
dispatchEvent: function ( event ) {
if ( this._listeners === undefined ) return;
var listeners = this._listeners;
var listenerArray = listeners[ event.type ];
if ( listenerArray !== undefined ) {
event.target = this;
var array = [], i = 0;
var length = listenerArray.length;
for ( i = 0; i < length; i ++ ) {
array[ i ] = listenerArray[ i ];
}
for ( i = 0; i < length; i ++ ) {
array[ i ].call( this, event );
}
}
}
} );
var REVISION = '85';
var CullFaceNone = 0;
var CullFaceBack = 1;
var CullFaceFront = 2;
var FrontFaceDirectionCW = 0;
var PCFShadowMap = 1;
var PCFSoftShadowMap = 2;
var FrontSide = 0;
var BackSide = 1;
var DoubleSide = 2;
var FlatShading = 1;
var SmoothShading = 2;
var NoColors = 0;
var FaceColors = 1;
var VertexColors = 2;
var NoBlending = 0;
var NormalBlending = 1;
var AdditiveBlending = 2;
var SubtractiveBlending = 3;
var MultiplyBlending = 4;
var CustomBlending = 5;
var AddEquation = 100;
var SubtractEquation = 101;
var ReverseSubtractEquation = 102;
var MinEquation = 103;
var MaxEquation = 104;
var ZeroFactor = 200;
var OneFactor = 201;
var SrcColorFactor = 202;
var OneMinusSrcColorFactor = 203;
var SrcAlphaFactor = 204;
var OneMinusSrcAlphaFactor = 205;
var DstAlphaFactor = 206;
var OneMinusDstAlphaFactor = 207;
var DstColorFactor = 208;
var OneMinusDstColorFactor = 209;
var SrcAlphaSaturateFactor = 210;
var NeverDepth = 0;
var AlwaysDepth = 1;
var LessDepth = 2;
var LessEqualDepth = 3;
var EqualDepth = 4;
var GreaterEqualDepth = 5;
var GreaterDepth = 6;
var NotEqualDepth = 7;
var MultiplyOperation = 0;
var MixOperation = 1;
var AddOperation = 2;
var NoToneMapping = 0;
var LinearToneMapping = 1;
var ReinhardToneMapping = 2;
var Uncharted2ToneMapping = 3;
var CineonToneMapping = 4;
var UVMapping = 300;
var CubeReflectionMapping = 301;
var CubeRefractionMapping = 302;
var EquirectangularReflectionMapping = 303;
var EquirectangularRefractionMapping = 304;
var SphericalReflectionMapping = 305;
var CubeUVReflectionMapping = 306;
var CubeUVRefractionMapping = 307;
var RepeatWrapping = 1000;
var ClampToEdgeWrapping = 1001;
var MirroredRepeatWrapping = 1002;
var NearestFilter = 1003;
var NearestMipMapNearestFilter = 1004;
var NearestMipMapLinearFilter = 1005;
var LinearFilter = 1006;
var LinearMipMapNearestFilter = 1007;
var LinearMipMapLinearFilter = 1008;
var UnsignedByteType = 1009;
var ByteType = 1010;
var ShortType = 1011;
var UnsignedShortType = 1012;
var IntType = 1013;
var UnsignedIntType = 1014;
var FloatType = 1015;
var HalfFloatType = 1016;
var UnsignedShort4444Type = 1017;
var UnsignedShort5551Type = 1018;
var UnsignedShort565Type = 1019;
var UnsignedInt248Type = 1020;
var AlphaFormat = 1021;
var RGBFormat = 1022;
var RGBAFormat = 1023;
var LuminanceFormat = 1024;
var LuminanceAlphaFormat = 1025;
var DepthFormat = 1026;
var DepthStencilFormat = 1027;
var RGB_S3TC_DXT1_Format = 2001;
var RGBA_S3TC_DXT1_Format = 2002;
var RGBA_S3TC_DXT3_Format = 2003;
var RGBA_S3TC_DXT5_Format = 2004;
var RGB_PVRTC_4BPPV1_Format = 2100;
var RGB_PVRTC_2BPPV1_Format = 2101;
var RGBA_PVRTC_4BPPV1_Format = 2102;
var RGBA_PVRTC_2BPPV1_Format = 2103;
var RGB_ETC1_Format = 2151;
var LoopOnce = 2200;
var LoopRepeat = 2201;
var LoopPingPong = 2202;
var InterpolateDiscrete = 2300;
var InterpolateLinear = 2301;
var InterpolateSmooth = 2302;
var ZeroCurvatureEnding = 2400;
var ZeroSlopeEnding = 2401;
var WrapAroundEnding = 2402;
var TrianglesDrawMode = 0;
var TriangleStripDrawMode = 1;
var TriangleFanDrawMode = 2;
var LinearEncoding = 3000;
var sRGBEncoding = 3001;
var GammaEncoding = 3007;
var RGBEEncoding = 3002;
var RGBM7Encoding = 3004;
var RGBM16Encoding = 3005;
var RGBDEncoding = 3006;
var BasicDepthPacking = 3200;
var RGBADepthPacking = 3201;
/**
* @author alteredq / http://alteredqualia.com/
* @author mrdoob / http://mrdoob.com/
*/
var _Math = {
DEG2RAD: Math.PI / 180,
RAD2DEG: 180 / Math.PI,
generateUUID: function () {
// http://www.broofa.com/Tools/Math.uuid.htm
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split( '' );
var uuid = new Array( 36 );
var rnd = 0, r;
return function generateUUID() {
for ( var i = 0; i < 36; i ++ ) {
if ( i === 8 || i === 13 || i === 18 || i === 23 ) {
uuid[ i ] = '-';
} else if ( i === 14 ) {
uuid[ i ] = '4';
} else {
if ( rnd <= 0x02 ) rnd = 0x2000000 + ( Math.random() * 0x1000000 ) | 0;
r = rnd & 0xf;
rnd = rnd >> 4;
uuid[ i ] = chars[ ( i === 19 ) ? ( r & 0x3 ) | 0x8 : r ];
}
}
return uuid.join( '' );
};
}(),
clamp: function ( value, min, max ) {
return Math.max( min, Math.min( max, value ) );
},
// compute euclidian modulo of m % n
// https://en.wikipedia.org/wiki/Modulo_operation
euclideanModulo: function ( n, m ) {
return ( ( n % m ) + m ) % m;
},
// Linear mapping from range to range
mapLinear: function ( x, a1, a2, b1, b2 ) {
return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
},
// https://en.wikipedia.org/wiki/Linear_interpolation
lerp: function ( x, y, t ) {
return ( 1 - t ) * x + t * y;
},
// http://en.wikipedia.org/wiki/Smoothstep
smoothstep: function ( x, min, max ) {
if ( x <= min ) return 0;
if ( x >= max ) return 1;
x = ( x - min ) / ( max - min );
return x * x * ( 3 - 2 * x );
},
smootherstep: function ( x, min, max ) {
if ( x <= min ) return 0;
if ( x >= max ) return 1;
x = ( x - min ) / ( max - min );
return x * x * x * ( x * ( x * 6 - 15 ) + 10 );
},
// Random integer from interval
randInt: function ( low, high ) {
return low + Math.floor( Math.random() * ( high - low + 1 ) );
},
// Random float from interval
randFloat: function ( low, high ) {
return low + Math.random() * ( high - low );
},
// Random float from <-range/2, range/2> interval
randFloatSpread: function ( range ) {
return range * ( 0.5 - Math.random() );
},
degToRad: function ( degrees ) {
return degrees * _Math.DEG2RAD;
},
radToDeg: function ( radians ) {
return radians * _Math.RAD2DEG;
},
isPowerOfTwo: function ( value ) {
return ( value & ( value - 1 ) ) === 0 && value !== 0;
},
nearestPowerOfTwo: function ( value ) {
return Math.pow( 2, Math.round( Math.log( value ) / Math.LN2 ) );
},
nextPowerOfTwo: function ( value ) {
value --;
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
value ++;
return value;
}
};
/**
* @author mrdoob / http://mrdoob.com/
* @author philogb / http://blog.thejit.org/
* @author egraether / http://egraether.com/
* @author zz85 / http://www.lab4games.net/zz85/blog
*/
function Vector2( x, y ) {
this.x = x || 0;
this.y = y || 0;
}
Object.defineProperties( Vector2.prototype, {
"width" : {
get: function () {
return this.x;
},
set: function ( value ) {
this.x = value;
}
},
"height" : {
get: function () {
return this.y;
},
set: function ( value ) {
this.y = value;
}
}
} );
Object.assign( Vector2.prototype, {
isVector2: true,
set: function ( x, y ) {
this.x = x;
this.y = y;
return this;
},
setScalar: function ( scalar ) {
this.x = scalar;
this.y = scalar;
return this;
},
setX: function ( x ) {
this.x = x;
return this;
},
setY: function ( y ) {
this.y = y;
return this;
},
setComponent: function ( index, value ) {
switch ( index ) {
case 0: this.x = value; break;
case 1: this.y = value; break;
default: throw new Error( 'index is out of range: ' + index );
}
return this;
},
getComponent: function ( index ) {
switch ( index ) {
case 0: return this.x;
case 1: return this.y;
default: throw new Error( 'index is out of range: ' + index );
}
},
clone: function () {
return new this.constructor( this.x, this.y );
},
copy: function ( v ) {
this.x = v.x;
this.y = v.y;
return this;
},
add: function ( v, w ) {
if ( w !== undefined ) {
console.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
return this.addVectors( v, w );
}
this.x += v.x;
this.y += v.y;
return this;
},
addScalar: function ( s ) {
this.x += s;
this.y += s;
return this;
},
addVectors: function ( a, b ) {
this.x = a.x + b.x;
this.y = a.y + b.y;
return this;
},
addScaledVector: function ( v, s ) {
this.x += v.x * s;
this.y += v.y * s;
return this;
},
sub: function ( v, w ) {
if ( w !== undefined ) {
console.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
return this.subVectors( v, w );
}
this.x -= v.x;
this.y -= v.y;
return this;
},
subScalar: function ( s ) {
this.x -= s;
this.y -= s;
return this;
},
subVectors: function ( a, b ) {
this.x = a.x - b.x;
this.y = a.y - b.y;
return this;
},
multiply: function ( v ) {
this.x *= v.x;
this.y *= v.y;
return this;
},
multiplyScalar: function ( scalar ) {
this.x *= scalar;
this.y *= scalar;
return this;
},
divide: function ( v ) {
this.x /= v.x;
this.y /= v.y;
return this;
},
divideScalar: function ( scalar ) {
return this.multiplyScalar( 1 / scalar );
},
min: function ( v ) {
this.x = Math.min( this.x, v.x );
this.y = Math.min( this.y, v.y );
return this;
},
max: function ( v ) {
this.x = Math.max( this.x, v.x );
this.y = Math.max( this.y, v.y );
return this;
},
clamp: function ( min, max ) {
// This function assumes min < max, if this assumption isn't true it will not operate correctly
this.x = Math.max( min.x, Math.min( max.x, this.x ) );
this.y = Math.max( min.y, Math.min( max.y, this.y ) );
return this;
},
clampScalar: function () {
var min = new Vector2();
var max = new Vector2();
return function clampScalar( minVal, maxVal ) {
min.set( minVal, minVal );
max.set( maxVal, maxVal );
return this.clamp( min, max );
};
}(),
clampLength: function ( min, max ) {
var length = this.length();
return this.multiplyScalar( Math.max( min, Math.min( max, length ) ) / length );
},
floor: function () {
this.x = Math.floor( this.x );
this.y = Math.floor( this.y );
return this;
},
ceil: function () {
this.x = Math.ceil( this.x );
this.y = Math.ceil( this.y );
return this;
},
round: function () {
this.x = Math.round( this.x );
this.y = Math.round( this.y );
return this;
},
roundToZero: function () {
this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
return this;
},
negate: function () {
this.x = - this.x;
this.y = - this.y;
return this;
},
dot: function ( v ) {
return this.x * v.x + this.y * v.y;
},
lengthSq: function () {
return this.x * this.x + this.y * this.y;
},
length: function () {
return Math.sqrt( this.x * this.x + this.y * this.y );
},
lengthManhattan: function() {
return Math.abs( this.x ) + Math.abs( this.y );
},
normalize: function () {
return this.divideScalar( this.length() );
},
angle: function () {
// computes the angle in radians with respect to the positive x-axis
var angle = Math.atan2( this.y, this.x );
if ( angle < 0 ) angle += 2 * Math.PI;
return angle;
},
distanceTo: function ( v ) {
return Math.sqrt( this.distanceToSquared( v ) );
},
distanceToSquared: function ( v ) {
var dx = this.x - v.x, dy = this.y - v.y;
return dx * dx + dy * dy;
},
distanceToManhattan: function ( v ) {
return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y );
},
setLength: function ( length ) {
return this.multiplyScalar( length / this.length() );
},
lerp: function ( v, alpha ) {
this.x += ( v.x - this.x ) * alpha;
this.y += ( v.y - this.y ) * alpha;
return this;
},
lerpVectors: function ( v1, v2, alpha ) {
return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
},
equals: function ( v ) {
return ( ( v.x === this.x ) && ( v.y === this.y ) );
},
fromArray: function ( array, offset ) {
if ( offset === undefined ) offset = 0;
this.x = array[ offset ];
this.y = array[ offset + 1 ];
return this;
},
toArray: function ( array, offset ) {
if ( array === undefined ) array = [];
if ( offset === undefined ) offset = 0;
array[ offset ] = this.x;
array[ offset + 1 ] = this.y;
return array;
},
fromBufferAttribute: function ( attribute, index, offset ) {
if ( offset !== undefined ) {
console.warn( 'THREE.Vector2: offset has been removed from .fromBufferAttribute().' );
}
this.x = attribute.getX( index );
this.y = attribute.getY( index );
return this;
},
rotateAround: function ( center, angle ) {
var c = Math.cos( angle ), s = Math.sin( angle );
var x = this.x - center.x;
var y = this.y - center.y;
this.x = x * c - y * s + center.x;
this.y = x * s + y * c + center.y;
return this;
}
} );
/**
* @author mrdoob / http://mrdoob.com/
* @author alteredq / http://alteredqualia.com/
* @author szimek / https://github.com/szimek/
*/
var textureId = 0;
function Texture( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) {
Object.defineProperty( this, 'id', { value: textureId ++ } );
this.uuid = _Math.generateUUID();
this.name = '';
this.image = image !== undefined ? image : Texture.DEFAULT_IMAGE;
this.mipmaps = [];
this.mapping = mapping !== undefined ? mapping : Texture.DEFAULT_MAPPING;
this.wrapS = wrapS !== undefined ? wrapS : ClampToEdgeWrapping;
this.wrapT = wrapT !== undefined ? wrapT : ClampToEdgeWrapping;
this.magFilter = magFilter !== undefined ? magFilter : LinearFilter;
this.minFilter = minFilter !== undefined ? minFilter : LinearMipMapLinearFilter;
this.anisotropy = anisotropy !== undefined ? anisotropy : 1;
this.format = format !== undefined ? format : RGBAFormat;
this.type = type !== undefined ? type : UnsignedByteType;
this.offset = new Vector2( 0, 0 );
this.repeat = new Vector2( 1, 1 );
this.generateMipmaps = true;
this.premultiplyAlpha = false;
this.flipY = true;
this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
// Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap.
//
// Also changing the encoding after already used by a Material will not automatically make the Material
// update. You need to explicitly call Material.needsUpdate to trigger it to recompile.
this.encoding = encoding !== undefined ? encoding : LinearEncoding;
this.version = 0;
this.onUpdate = null;
}
Texture.DEFAULT_IMAGE = undefined;
Texture.DEFAULT_MAPPING = UVMapping;
Object.defineProperty( Texture.prototype, "needsUpdate", {
set: function ( value ) {
if ( value === true ) this.version ++;
}
} );
Object.assign( Texture.prototype, EventDispatcher.prototype, {
constructor: Texture,
isTexture: true,
clone: function () {
return new this.constructor().copy( this );
},
copy: function ( source ) {
this.name = source.name;
this.image = source.image;
this.mipmaps = source.mipmaps.slice( 0 );
this.mapping = source.mapping;
this.wrapS = source.wrapS;
this.wrapT = source.wrapT;
this.magFilter = source.magFilter;
this.minFilter = source.minFilter;
this.anisotropy = source.anisotropy;
this.format = source.format;
this.type = source.type;
this.offset.copy( source.offset );
this.repeat.copy( source.repeat );
this.generateMipmaps = source.generateMipmaps;
this.premultiplyAlpha = source.premultiplyAlpha;
this.flipY = source.flipY;
this.unpackAlignment = source.unpackAlignment;
this.encoding = source.encoding;
return this;
},
toJSON: function ( meta ) {
if ( meta.textures[ this.uuid ] !== undefined ) {
return meta.textures[ this.uuid ];
}
function getDataURL( image ) {
var canvas;
if ( image.toDataURL !== undefined ) {
canvas = image;
} else {
canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
canvas.width = image.width;
canvas.height = image.height;
canvas.getContext( '2d' ).drawImage( image, 0, 0, image.width, image.height );
}
if ( canvas.width > 2048 || canvas.height > 2048 ) {
return canvas.toDataURL( 'image/jpeg', 0.6 );
} else {
return canvas.toDataURL( 'image/png' );
}
}
var output = {
metadata: {
version: 4.5,
type: 'Texture',
generator: 'Texture.toJSON'
},
uuid: this.uuid,
name: this.name,
mapping: this.mapping,
repeat: [ this.repeat.x, this.repeat.y ],
offset: [ this.offset.x, this.offset.y ],
wrap: [ this.wrapS, this.wrapT ],
minFilter: this.minFilter,
magFilter: this.magFilter,
anisotropy: this.anisotropy,
flipY: this.flipY
};
if ( this.image !== undefined ) {
// TODO: Move to THREE.Image
var image = this.image;
if ( image.uuid === undefined ) {
image.uuid = _Math.generateUUID(); // UGH
}
if ( meta.images[ image.uuid ] === undefined ) {
meta.images[ image.uuid ] = {
uuid: image.uuid,
url: getDataURL( image )
};
}
output.image = image.uuid;
}
meta.textures[ this.uuid ] = output;
return output;
},
dispose: function () {
this.dispatchEvent( { type: 'dispose' } );
},
transformUv: function ( uv ) {
if ( this.mapping !== UVMapping ) return;
uv.multiply( this.repeat );
uv.add( this.offset );
if ( uv.x < 0 || uv.x > 1 ) {
switch ( this.wrapS ) {
case RepeatWrapping:
uv.x = uv.x - Math.floor( uv.x );
break;
case ClampToEdgeWrapping:
uv.x = uv.x < 0 ? 0 : 1;
break;
case MirroredRepeatWrapping:
if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) {
uv.x = Math.ceil( uv.x ) - uv.x;
} else {
uv.x = uv.x - Math.floor( uv.x );
}
break;
}
}
if ( uv.y < 0 || uv.y > 1 ) {
switch ( this.wrapT ) {
case RepeatWrapping:
uv.y = uv.y - Math.floor( uv.y );
break;
case ClampToEdgeWrapping:
uv.y = uv.y < 0 ? 0 : 1;
break;
case MirroredRepeatWrapping:
if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) {
uv.y = Math.ceil( uv.y ) - uv.y;
} else {
uv.y = uv.y - Math.floor( uv.y );
}
break;
}
}
if ( this.flipY ) {
uv.y = 1 - uv.y;
}
}
} );
/**
* @author supereggbert / http://www.paulbrunt.co.uk/
* @author philogb / http://blog.thejit.org/
* @author mikael emtinger / http://gomo.se/
* @author egraether / http://egraether.com/
* @author WestLangley / http://github.com/WestLangley
*/
function Vector4( x, y, z, w ) {
this.x = x || 0;
this.y = y || 0;
this.z = z || 0;
this.w = ( w !== undefined ) ? w : 1;
}
Object.assign( Vector4.prototype, {
isVector4: true,
set: function ( x, y, z, w ) {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
return this;
},
setScalar: function ( scalar ) {
this.x = scalar;
this.y = scalar;
this.z = scalar;
this.w = scalar;
return this;
},
setX: function ( x ) {
this.x = x;
return this;
},
setY: function ( y ) {
this.y = y;
return this;
},
setZ: function ( z ) {
this.z = z;
return this;
},
setW: function ( w ) {
this.w = w;
return this;
},
setComponent: function ( index, value ) {
switch ( index ) {
case 0: this.x = value; break;
case 1: this.y = value; break;
case 2: this.z = value; break;
case 3: this.w = value; break;
default: throw new Error( 'index is out of range: ' + index );
}
return this;
},
getComponent: function ( index ) {
switch ( index ) {
case 0: return this.x;
case 1: return this.y;
case 2: return this.z;
case 3: return this.w;
default: throw new Error( 'index is out of range: ' + index );
}
},
clone: function () {
return new this.constructor( this.x, this.y, this.z, this.w );
},
copy: function ( v ) {
this.x = v.x;
this.y = v.y;
this.z = v.z;
this.w = ( v.w !== undefined ) ? v.w : 1;
return this;
},
add: function ( v, w ) {
if ( w !== undefined ) {
console.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
return this.addVectors( v, w );
}
this.x += v.x;
this.y += v.y;
this.z += v.z;
this.w += v.w;
return this;
},
addScalar: function ( s ) {
this.x += s;
this.y += s;
this.z += s;
this.w += s;
return this;
},
addVectors: 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;
},
addScaledVector: function ( v, s ) {
this.x += v.x * s;
this.y += v.y * s;
this.z += v.z * s;
this.w += v.w * s;
return this;
},
sub: function ( v, w ) {
if ( w !== undefined ) {
console.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
return this.subVectors( v, w );
}
this.x -= v.x;
this.y -= v.y;
this.z -= v.z;
this.w -= v.w;
return this;
},
subScalar: function ( s ) {
this.x -= s;
this.y -= s;
this.z -= s;
this.w -= s;
return this;
},
subVectors: 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;
},
multiplyScalar: function ( scalar ) {
this.x *= scalar;
this.y *= scalar;
this.z *= scalar;
this.w *= scalar;
return this;
},
applyMatrix4: function ( m ) {
var x = this.x, y = this.y, z = this.z, w = this.w;
var e = m.elements;
this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w;
this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w;
this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w;
this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w;
return this;
},
divideScalar: function ( scalar ) {
return this.multiplyScalar( 1 / scalar );
},
setAxisAngleFromQuaternion: function ( q ) {
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
// q is assumed to be normalized
this.w = 2 * Math.acos( q.w );
var s = Math.sqrt( 1 - q.w * q.w );
if ( s < 0.0001 ) {
this.x = 1;
this.y = 0;
this.z = 0;
} else {
this.x = q.x / s;
this.y = q.y / s;
this.z = q.z / s;
}
return this;
},
setAxisAngleFromRotationMatrix: function ( m ) {
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm
// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
var angle, x, y, z, // variables for result
epsilon = 0.01, // margin to allow for rounding errors
epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees
te = m.elements,
m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
if ( ( Math.abs( m12 - m21 ) < epsilon ) &&
( Math.abs( m13 - m31 ) < epsilon ) &&
( Math.abs( m23 - m32 ) < epsilon ) ) {
// singularity found
// first check for identity matrix which must have +1 for all terms
// in leading diagonal and zero in other terms
if ( ( Math.abs( m12 + m21 ) < epsilon2 ) &&
( Math.abs( m13 + m31 ) < epsilon2 ) &&
( Math.abs( m23 + m32 ) < epsilon2 ) &&
( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) {
// this singularity is identity matrix so angle = 0
this.set( 1, 0, 0, 0 );
return this; // zero angle, arbitrary axis
}
// otherwise this singularity is angle = 180
angle = Math.PI;
var xx = ( m11 + 1 ) / 2;
var yy = ( m22 + 1 ) / 2;
var zz = ( m33 + 1 ) / 2;
var xy = ( m12 + m21 ) / 4;
var xz = ( m13 + m31 ) / 4;
var yz = ( m23 + m32 ) / 4;
if ( ( xx > yy ) && ( xx > zz ) ) {
// m11 is the largest diagonal term
if ( xx < epsilon ) {
x = 0;
y = 0.707106781;
z = 0.707106781;
} else {
x = Math.sqrt( xx );
y = xy / x;
z = xz / x;
}
} else if ( yy > zz ) {
// m22 is the largest diagonal term
if ( yy < epsilon ) {
x = 0.707106781;
y = 0;
z = 0.707106781;
} else {
y = Math.sqrt( yy );
x = xy / y;
z = yz / y;
}
} else {
// m33 is the largest diagonal term so base result on this
if ( zz < epsilon ) {
x = 0.707106781;
y = 0.707106781;
z = 0;
} else {
z = Math.sqrt( zz );
x = xz / z;
y = yz / z;
}
}
this.set( x, y, z, angle );
return this; // return 180 deg rotation
}
// as we have reached here there are no singularities so we can handle normally
var s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) +
( m13 - m31 ) * ( m13 - m31 ) +
( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize
if ( Math.abs( s ) < 0.001 ) s = 1;
// prevent divide by zero, should not happen if matrix is orthogonal and should be
// caught by singularity test above, but I've left it in just in case
this.x = ( m32 - m23 ) / s;
this.y = ( m13 - m31 ) / s;
this.z = ( m21 - m12 ) / s;
this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 );
return this;
},
min: function ( v ) {
this.x = Math.min( this.x, v.x );
this.y = Math.min( this.y, v.y );
this.z = Math.min( this.z, v.z );
this.w = Math.min( this.w, v.w );
return this;
},
max: function ( v ) {
this.x = Math.max( this.x, v.x );
this.y = Math.max( this.y, v.y );
this.z = Math.max( this.z, v.z );
this.w = Math.max( this.w, v.w );
return this;
},
clamp: function ( min, max ) {
// This function assumes min < max, if this assumption isn't true it will not operate correctly
this.x = Math.max( min.x, Math.min( max.x, this.x ) );
this.y = Math.max( min.y, Math.min( max.y, this.y ) );
this.z = Math.max( min.z, Math.min( max.z, this.z ) );
this.w = Math.max( min.w, Math.min( max.w, this.w ) );
return this;
},
clampScalar: function () {
var min = new Vector4();
var max = new Vector4();
return function clampScalar( minVal, maxVal ) {
min.set( minVal, minVal, minVal, minVal );
max.set( maxVal, maxVal, maxVal, maxVal );
return this.clamp( min, max );
};
}(),
floor: function () {
this.x = Math.floor( this.x );
this.y = Math.floor( this.y );
this.z = Math.floor( this.z );
this.w = Math.floor( this.w );
return this;
},
ceil: function () {
this.x = Math.ceil( this.x );
this.y = Math.ceil( this.y );
this.z = Math.ceil( this.z );
this.w = Math.ceil( this.w );
return this;
},
round: function () {
this.x = Math.round( this.x );
this.y = Math.round( this.y );
this.z = Math.round( this.z );
this.w = Math.round( this.w );
return this;
},
roundToZero: function () {
this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w );
return this;
},
negate: function () {
this.x = - this.x;
this.y = - this.y;
this.z = - this.z;
this.w = - this.w;
return this;
},
dot: function ( v ) {
return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;
},
lengthSq: function () {
return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
},
length: function () {
return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );
},
lengthManhattan: function () {
return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w );
},
normalize: function () {
return this.divideScalar( this.length() );
},
setLength: function ( length ) {
return this.multiplyScalar( length / this.length() );
},
lerp: function ( v, alpha ) {
this.x += ( v.x - this.x ) * alpha;
this.y += ( v.y - this.y ) * alpha;
this.z += ( v.z - this.z ) * alpha;
this.w += ( v.w - this.w ) * alpha;
return this;
},
lerpVectors: function ( v1, v2, alpha ) {
return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
},
equals: function ( v ) {
return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );
},
fromArray: function ( array, offset ) {
if ( offset === undefined ) offset = 0;
this.x = array[ offset ];
this.y = array[ offset + 1 ];
this.z = array[ offset + 2 ];
this.w = array[ offset + 3 ];
return this;
},
toArray: function ( array, offset ) {
if ( array === undefined ) array = [];
if ( offset === undefined ) offset = 0;
array[ offset ] = this.x;
array[ offset + 1 ] = this.y;
array[ offset + 2 ] = this.z;
array[ offset + 3 ] = this.w;
return array;
},
fromBufferAttribute: function ( attribute, index, offset ) {
if ( offset !== undefined ) {
console.warn( 'THREE.Vector4: offset has been removed from .fromBufferAttribute().' );
}
this.x = attribute.getX( index );
this.y = attribute.getY( index );
this.z = attribute.getZ( index );
this.w = attribute.getW( index );
return this;
}
} );
/**
* @author szimek / https://github.com/szimek/
* @author alteredq / http://alteredqualia.com/
* @author Marius Kintel / https://github.com/kintel
*/
/*
In options, we can specify:
* Texture parameters for an auto-generated target texture
* depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers
*/
function WebGLRenderTarget( width, height, options ) {
this.uuid = _Math.generateUUID();
this.width = width;
this.height = height;
this.scissor = new Vector4( 0, 0, width, height );
this.scissorTest = false;
this.viewport = new Vector4( 0, 0, width, height );
options = options || {};
if ( options.minFilter === undefined ) options.minFilter = LinearFilter;
this.texture = new Texture( undefined, undefined, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding );
this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true;
this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true;
this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null;
}
Object.assign( WebGLRenderTarget.prototype, EventDispatcher.prototype, {
isWebGLRenderTarget: true,
setSize: function ( width, height ) {
if ( this.width !== width || this.height !== height ) {
this.width = width;
this.height = height;
this.dispose();
}
this.viewport.set( 0, 0, width, height );
this.scissor.set( 0, 0, width, height );
},
clone: function () {
return new this.constructor().copy( this );
},
copy: function ( source ) {
this.width = source.width;
this.height = source.height;
this.viewport.copy( source.viewport );
this.texture = source.texture.clone();
this.depthBuffer = source.depthBuffer;
this.stencilBuffer = source.stencilBuffer;
this.depthTexture = source.depthTexture;
return this;
},
dispose: function () {
this.dispatchEvent( { type: 'dispose' } );
}
} );
/**
* @author alteredq / http://alteredqualia.com
*/
function WebGLRenderTargetCube( width, height, options ) {
WebGLRenderTarget.call( this, width, height, options );
this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5
this.activeMipMapLevel = 0;
}
WebGLRenderTargetCube.prototype = Object.create( WebGLRenderTarget.prototype );
WebGLRenderTargetCube.prototype.constructor = WebGLRenderTargetCube;
WebGLRenderTargetCube.prototype.isWebGLRenderTargetCube = true;
/**
* @author mikael emtinger / http://gomo.se/
* @author alteredq / http://alteredqualia.com/
* @author WestLangley / http://github.com/WestLangley
* @author bhouston / http://clara.io
*/
function Quaternion( x, y, z, w ) {
this._x = x || 0;
this._y = y || 0;
this._z = z || 0;
this._w = ( w !== undefined ) ? w : 1;
}
Object.assign( Quaternion, {
slerp: function ( qa, qb, qm, t ) {
return qm.copy( qa ).slerp( qb, t );
},
slerpFlat: function ( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) {
// fuzz-free, array-based Quaternion SLERP operation
var x0 = src0[ srcOffset0 + 0 ],
y0 = src0[ srcOffset0 + 1 ],
z0 = src0[ srcOffset0 + 2 ],
w0 = src0[ srcOffset0 + 3 ],
x1 = src1[ srcOffset1 + 0 ],
y1 = src1[ srcOffset1 + 1 ],
z1 = src1[ srcOffset1 + 2 ],
w1 = src1[ srcOffset1 + 3 ];
if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {
var s = 1 - t,
cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
dir = ( cos >= 0 ? 1 : - 1 ),
sqrSin = 1 - cos * cos;
// Skip the Slerp for tiny steps to avoid numeric problems:
if ( sqrSin > Number.EPSILON ) {
var sin = Math.sqrt( sqrSin ),
len = Math.atan2( sin, cos * dir );
s = Math.sin( s * len ) / sin;
t = Math.sin( t * len ) / sin;
}
var tDir = t * dir;
x0 = x0 * s + x1 * tDir;
y0 = y0 * s + y1 * tDir;
z0 = z0 * s + z1 * tDir;
w0 = w0 * s + w1 * tDir;
// Normalize in case we just did a lerp:
if ( s === 1 - t ) {
var f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );
x0 *= f;
y0 *= f;
z0 *= f;
w0 *= f;
}
}
dst[ dstOffset ] = x0;
dst[ dstOffset + 1 ] = y0;
dst[ dstOffset + 2 ] = z0;
dst[ dstOffset + 3 ] = w0;
}
} );
Object.defineProperties( Quaternion.prototype, {
x: {
get: function () {
return this._x;
},
set: function ( value ) {
this._x = value;
this.onChangeCallback();
}
},
y: {
get: function () {
return this._y;
},
set: function ( value ) {
this._y = value;
this.onChangeCallback();
}
},
z: {
get: function () {
return this._z;
},
set: function ( value ) {
this._z = value;
this.onChangeCallback();
}
},
w: {
get: function () {
return this._w;
},
set: function ( value ) {
this._w = value;
this.onChangeCallback();
}
}
} );
Object.assign( Quaternion.prototype, {
set: function ( x, y, z, w ) {
this._x = x;
this._y = y;
this._z = z;
this._w = w;
this.onChangeCallback();
return this;
},
clone: function () {
return new this.constructor( this._x, this._y, this._z, this._w );
},
copy: function ( quaternion ) {
this._x = quaternion.x;
this._y = quaternion.y;
this._z = quaternion.z;
this._w = quaternion.w;
this.onChangeCallback();
return this;
},
setFromEuler: function ( euler, update ) {
if ( ( euler && euler.isEuler ) === false ) {
throw new Error( 'THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' );
}
var x = euler._x, y = euler._y, z = euler._z, order = euler.order;
// http://www.mathworks.com/matlabcentral/fileexchange/
// 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
// content/SpinCalc.m
var cos = Math.cos;
var sin = Math.sin;
var c1 = cos( x / 2 );
var c2 = cos( y / 2 );
var c3 = cos( z / 2 );
var s1 = sin( x / 2 );
var s2 = sin( y / 2 );
var s3 = sin( z / 2 );
if ( order === 'XYZ' ) {
this._x = s1 * c2 * c3 + c1 * s2 * s3;
this._y = c1 * s2 * c3 - s1 * c2 * s3;
this._z = c1 * c2 * s3 + s1 * s2 * c3;
this._w = c1 * c2 * c3 - s1 * s2 * s3;
} else if ( order === 'YXZ' ) {
this._x = s1 * c2 * c3 + c1 * s2 * s3;
this._y = c1 * s2 * c3 - s1 * c2 * s3;
this._z = c1 * c2 * s3 - s1 * s2 * c3;
this._w = c1 * c2 * c3 + s1 * s2 * s3;
} else if ( order === 'ZXY' ) {
this._x = s1 * c2 * c3 - c1 * s2 * s3;
this._y = c1 * s2 * c3 + s1 * c2 * s3;
this._z = c1 * c2 * s3 + s1 * s2 * c3;
this._w = c1 * c2 * c3 - s1 * s2 * s3;
} else if ( order === 'ZYX' ) {
this._x = s1 * c2 * c3 - c1 * s2 * s3;
this._y = c1 * s2 * c3 + s1 * c2 * s3;
this._z = c1 * c2 * s3 - s1 * s2 * c3;
this._w = c1 * c2 * c3 + s1 * s2 * s3;
} else if ( order === 'YZX' ) {
this._x = s1 * c2 * c3 + c1 * s2 * s3;
this._y = c1 * s2 * c3 + s1 * c2 * s3;
this._z = c1 * c2 * s3 - s1 * s2 * c3;
this._w = c1 * c2 * c3 - s1 * s2 * s3;
} else if ( order === 'XZY' ) {
this._x = s1 * c2 * c3 - c1 * s2 * s3;
this._y = c1 * s2 * c3 - s1 * c2 * s3;
this._z = c1 * c2 * s3 + s1 * s2 * c3;
this._w = c1 * c2 * c3 + s1 * s2 * s3;
}
if ( update !== false ) this.onChangeCallback();
return this;
},
setFromAxisAngle: function ( axis, angle ) {
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
// assumes axis is normalized
var halfAngle = angle / 2, s = Math.sin( halfAngle );
this._x = axis.x * s;
this._y = axis.y * s;
this._z = axis.z * s;
this._w = Math.cos( halfAngle );
this.onChangeCallback();
return this;
},
setFromRotationMatrix: function ( m ) {
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
var te = m.elements,
m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ],
trace = m11 + m22 + m33,
s;
if ( trace > 0 ) {
s = 0.5 / Math.sqrt( trace + 1.0 );
this._w = 0.25 / s;
this._x = ( m32 - m23 ) * s;
this._y = ( m13 - m31 ) * s;
this._z = ( m21 - m12 ) * s;
} else if ( m11 > m22 && m11 > m33 ) {
s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );
this._w = ( m32 - m23 ) / s;
this._x = 0.25 * s;
this._y = ( m12 + m21 ) / s;
this._z = ( m13 + m31 ) / s;
} else if ( m22 > m33 ) {
s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );
this._w = ( m13 - m31 ) / s;
this._x = ( m12 + m21 ) / s;
this._y = 0.25 * s;
this._z = ( m23 + m32 ) / s;
} else {
s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );
this._w = ( m21 - m12 ) / s;
this._x = ( m13 + m31 ) / s;
this._y = ( m23 + m32 ) / s;
this._z = 0.25 * s;
}
this.onChangeCallback();
return this;
},
setFromUnitVectors: function () {
// assumes direction vectors vFrom and vTo are normalized
var v1 = new Vector3();
var r;
var EPS = 0.000001;
return function setFromUnitVectors( vFrom, vTo ) {
if ( v1 === undefined ) v1 = new Vector3();
r = vFrom.dot( vTo ) + 1;
if ( r < EPS ) {
r = 0;
if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {
v1.set( - vFrom.y, vFrom.x, 0 );
} else {
v1.set( 0, - vFrom.z, vFrom.y );
}
} else {
v1.crossVectors( vFrom, vTo );
}
this._x = v1.x;
this._y = v1.y;
this._z = v1.z;
this._w = r;
return this.normalize();
};
}(),
inverse: function () {
return this.conjugate().normalize();
},
conjugate: function () {
this._x *= - 1;
this._y *= - 1;
this._z *= - 1;
this.onChangeCallback();
return this;
},
dot: function ( v ) {
return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;
},
lengthSq: function () {
return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
},
length: function () {
return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );
},
normalize: function () {
var l = this.length();
if ( l === 0 ) {
this._x = 0;
this._y = 0;
this._z = 0;
this._w = 1;
} else {
l = 1 / l;
this._x = this._x * l;
this._y = this._y * l;
this._z = this._z * l;
this._w = this._w * l;
}
this.onChangeCallback();
return this;
},
multiply: function ( q, p ) {
if ( p !== undefined ) {
console.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' );
return this.multiplyQuaternions( q, p );
}
return this.multiplyQuaternions( this, q );
},
premultiply: function ( q ) {
return this.multiplyQuaternions( q, this );
},
multiplyQuaternions: function ( a, b ) {
// from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;
var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;
this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
this.onChangeCallback();
return this;
},
slerp: function ( qb, t ) {
if ( t === 0 ) return this;
if ( t === 1 ) return this.copy( qb );
var x = this._x, y = this._y, z = this._z, w = this._w;
// http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;
if ( cosHalfTheta < 0 ) {
this._w = - qb._w;
this._x = - qb._x;
this._y = - qb._y;
this._z = - qb._z;
cosHalfTheta = - cosHalfTheta;
} else {
this.copy( qb );
}
if ( cosHalfTheta >= 1.0 ) {
this._w = w;
this._x = x;
this._y = y;
this._z = z;
return this;
}
var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta );
if ( Math.abs( sinHalfTheta ) < 0.001 ) {
this._w = 0.5 * ( w + this._w );
this._x = 0.5 * ( x + this._x );
this._y = 0.5 * ( y + this._y );
this._z = 0.5 * ( z + this._z );
return this;
}
var halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta );
var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
this._w = ( w * ratioA + this._w * ratioB );
this._x = ( x * ratioA + this._x * ratioB );
this._y = ( y * ratioA + this._y * ratioB );
this._z = ( z * ratioA + this._z * ratioB );
this.onChangeCallback();
return this;
},
equals: function ( quaternion ) {
return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );
},
fromArray: function ( array, offset ) {
if ( offset === undefined ) offset = 0;
this._x = array[ offset ];
this._y = array[ offset + 1 ];
this._z = array[ offset + 2 ];
this._w = array[ offset + 3 ];
this.onChangeCallback();
return this;
},
toArray: function ( array, offset ) {
if ( array === undefined ) array = [];
if ( offset === undefined ) offset = 0;
array[ offset ] = this._x;
array[ offset + 1 ] = this._y;
array[ offset + 2 ] = this._z;
array[ offset + 3 ] = this._w;
return array;
},
onChange: function ( callback ) {
this.onChangeCallback = callback;
return this;
},
onChangeCallback: function () {}
} );
/**
* @author mrdoob / http://mrdoob.com/
* @author *kile / http://kile.stravaganza.org/
* @author philogb / http://blog.thejit.org/
* @author mikael emtinger / http://gomo.se/
* @author egraether / http://egraether.com/
* @author WestLangley / http://github.com/WestLangley
*/
function Vector3( x, y, z ) {
this.x = x || 0;
this.y = y || 0;
this.z = z || 0;
}
Object.assign( Vector3.prototype, {
isVector3: true,
set: function ( x, y, z ) {
this.x = x;
this.y = y;
this.z = z;
return this;
},
setScalar: function ( scalar ) {
this.x = scalar;
this.y = scalar;
this.z = scalar;
return this;
},
setX: function ( x ) {
this.x = x;
return this;
},
setY: function ( y ) {
this.y = y;
return this;
},
setZ: function ( z ) {
this.z = z;
return this;
},
setComponent: function ( index, value ) {
switch ( index ) {
case 0: this.x = value; break;
case 1: this.y = value; break;
case 2: this.z = value; break;
default: throw new Error( 'index is out of range: ' + index );
}
return this;
},
getComponent: function ( index ) {
switch ( index ) {
case 0: return this.x;
case 1: return this.y;
case 2: return this.z;
default: throw new Error( 'index is out of range: ' + index );
}
},
clone: function () {
return new this.constructor( this.x, this.y, this.z );
},
copy: function ( v ) {
this.x = v.x;
this.y = v.y;
this.z = v.z;
return this;
},
add: function ( v, w ) {
if ( w !== undefined ) {
console.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
return this.addVectors( v, w );
}
this.x += v.x;
this.y += v.y;
this.z += v.z;
return this;
},
addScalar: function ( s ) {
this.x += s;
this.y += s;
this.z += s;
return this;
},
addVectors: function ( a, b ) {
this.x = a.x + b.x;
this.y = a.y + b.y;
this.z = a.z + b.z;
return this;
},
addScaledVector: function ( v, s ) {
this.x += v.x * s;
this.y += v.y * s;
this.z += v.z * s;
return this;
},
sub: function ( v, w ) {
if ( w !== undefined ) {
console.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
return this.subVectors( v, w );
}
this.x -= v.x;
this.y -= v.y;
this.z -= v.z;
return this;
},
subScalar: function ( s ) {
this.x -= s;
this.y -= s;
this.z -= s;
return this;
},
subVectors: function ( a, b ) {
this.x = a.x - b.x;
this.y = a.y - b.y;
this.z = a.z - b.z;
return this;
},
multiply: function ( v, w ) {
if ( w !== undefined ) {
console.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' );
return this.multiplyVectors( v, w );
}
this.x *= v.x;
this.y *= v.y;
this.z *= v.z;
return this;
},
multiplyScalar: function ( scalar ) {
this.x *= scalar;
this.y *= scalar;
this.z *= scalar;
return this;
},
multiplyVectors: function ( a, b ) {
this.x = a.x * b.x;
this.y = a.y * b.y;
this.z = a.z * b.z;
return this;
},
applyEuler: function () {
var quaternion = new Quaternion();
return function applyEuler( euler ) {
if ( ( euler && euler.isEuler ) === false ) {
console.error( 'THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.' );
}
return this.applyQuaternion( quaternion.setFromEuler( euler ) );
};
}(),
applyAxisAngle: function () {
var quaternion = new Quaternion();
return function applyAxisAngle( axis, angle ) {
return this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) );
};
}(),
applyMatrix3: function ( m ) {
var x = this.x, y = this.y, z = this.z;
var e = m.elements;
this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;
this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;
this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;
return this;
},
applyMatrix4: function ( m ) {
var x = this.x, y = this.y, z = this.z;
var e = m.elements;
this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ];
this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ];
this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ];
var w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ];
return this.divideScalar( w );
},
applyQuaternion: function ( q ) {
var x = this.x, y = this.y, z = this.z;
var qx = q.x, qy = q.y, qz = q.z, qw = q.w;
// calculate quat * vector
var ix = qw * x + qy * z - qz * y;
var iy = qw * y + qz * x - qx * z;
var iz = qw * z + qx * y - qy * x;
var iw = - qx * x - qy * y - qz * z;
// calculate result * inverse quat
this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy;
this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz;
this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx;
return this;
},
project: function () {
var matrix = new Matrix4();
return function project( camera ) {
matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) );
return this.applyMatrix4( matrix );
};
}(),
unproject: function () {
var matrix = new Matrix4();
return function unproject( camera ) {
matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) );
return this.applyMatrix4( matrix );
};
}(),
transformDirection: function ( m ) {
// input: THREE.Matrix4 affine matrix
// vector interpreted as a direction
var x = this.x, y = this.y, z = this.z;
var e = m.elements;
this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;
this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;
this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
return this.normalize();
},
divide: function ( v ) {
this.x /= v.x;
this.y /= v.y;
this.z /= v.z;
return this;
},
divideScalar: function ( scalar ) {
return this.multiplyScalar( 1 / scalar );
},
min: function ( v ) {
this.x = Math.min( this.x, v.x );
this.y = Math.min( this.y, v.y );
this.z = Math.min( this.z, v.z );
return this;
},
max: function ( v ) {
this.x = Math.max( this.x, v.x );
this.y = Math.max( this.y, v.y );
this.z = Math.max( this.z, v.z );
return this;
},
clamp: function ( min, max ) {
// This function assumes min < max, if this assumption isn't true it will not operate correctly
this.x = Math.max( min.x, Math.min( max.x, this.x ) );
this.y = Math.max( min.y, Math.min( max.y, this.y ) );
this.z = Math.max( min.z, Math.min( max.z, this.z ) );
return this;
},
clampScalar: function () {
var min = new Vector3();
var max = new Vector3();
return function clampScalar( minVal, maxVal ) {
min.set( minVal, minVal, minVal );
max.set( maxVal, maxVal, maxVal );
return this.clamp( min, max );
};
}(),
clampLength: function ( min, max ) {
var length = this.length();
return this.multiplyScalar( Math.max( min, Math.min( max, length ) ) / length );
},
floor: function () {
this.x = Math.floor( this.x );
this.y = Math.floor( this.y );
this.z = Math.floor( this.z );
return this;
},
ceil: function () {
this.x = Math.ceil( this.x );
this.y = Math.ceil( this.y );
this.z = Math.ceil( this.z );
return this;
},
round: function () {
this.x = Math.round( this.x );
this.y = Math.round( this.y );
this.z = Math.round( this.z );
return this;
},
roundToZero: function () {
this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
return this;
},
negate: function () {
this.x = - this.x;
this.y = - this.y;
this.z = - this.z;
return this;
},
dot: function ( v ) {
return this.x * v.x + this.y * v.y + this.z * v.z;
},
// TODO lengthSquared?
lengthSq: function () {
return this.x * this.x + this.y * this.y + this.z * this.z;
},
length: function () {
return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
},
lengthManhattan: function () {
return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );
},
normalize: function () {
return this.divideScalar( this.length() );
},
setLength: function ( length ) {
return this.multiplyScalar( length / this.length() );
},
lerp: function ( v, alpha ) {
this.x += ( v.x - this.x ) * alpha;
this.y += ( v.y - this.y ) * alpha;
this.z += ( v.z - this.z ) * alpha;
return this;
},
lerpVectors: function ( v1, v2, alpha ) {
return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
},
cross: function ( v, w ) {
if ( w !== undefined ) {
console.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' );
return this.crossVectors( v, w );
}
var x = this.x, y = this.y, z = this.z;
this.x = y * v.z - z * v.y;
this.y = z * v.x - x * v.z;
this.z = x * v.y - y * v.x;
return this;
},
crossVectors: function ( a, b ) {
var ax = a.x, ay = a.y, az = a.z;
var bx = b.x, by = b.y, bz = b.z;
this.x = ay * bz - az * by;
this.y = az * bx - ax * bz;
this.z = ax * by - ay * bx;
return this;
},
projectOnVector: function ( vector ) {
var scalar = vector.dot( this ) / vector.lengthSq();
return this.copy( vector ).multiplyScalar( scalar );
},
projectOnPlane: function () {
var v1 = new Vector3();
return function projectOnPlane( planeNormal ) {
v1.copy( this ).projectOnVector( planeNormal );
return this.sub( v1 );
};
}(),
reflect: function () {
// reflect incident vector off plane orthogonal to normal
// normal is assumed to have unit length
var v1 = new Vector3();
return function reflect( normal ) {
return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );
};
}(),
angleTo: function ( v ) {
var theta = this.dot( v ) / ( Math.sqrt( this.lengthSq() * v.lengthSq() ) );
// clamp, to handle numerical problems
return Math.acos( _Math.clamp( theta, - 1, 1 ) );
},
distanceTo: function ( v ) {
return Math.sqrt( this.distanceToSquared( v ) );
},
distanceToSquared: function ( v ) {
var dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;
return dx * dx + dy * dy + dz * dz;
},
distanceToManhattan: function ( v ) {
return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z );
},
setFromSpherical: function ( s ) {
var sinPhiRadius = Math.sin( s.phi ) * s.radius;
this.x = sinPhiRadius * Math.sin( s.theta );
this.y = Math.cos( s.phi ) * s.radius;
this.z = sinPhiRadius * Math.cos( s.theta );
return this;
},
setFromCylindrical: function ( c ) {
this.x = c.radius * Math.sin( c.theta );
this.y = c.y;
this.z = c.radius * Math.cos( c.theta );
return this;
},
setFromMatrixPosition: function ( m ) {
return this.setFromMatrixColumn( m, 3 );
},
setFromMatrixScale: function ( m ) {
var sx = this.setFromMatrixColumn( m, 0 ).length();
var sy = this.setFromMatrixColumn( m, 1 ).length();
var sz = this.setFromMatrixColumn( m, 2 ).length();
this.x = sx;
this.y = sy;
this.z = sz;
return this;
},
setFromMatrixColumn: function ( m, index ) {
return this.fromArray( m.elements, index * 4 );
},
equals: function ( v ) {
return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );
},
fromArray: function ( array, offset ) {
if ( offset === undefined ) offset = 0;
this.x = array[ offset ];
this.y = array[ offset + 1 ];
this.z = array[ offset + 2 ];
return this;
},
toArray: function ( array, offset ) {
if ( array === undefined ) array = [];
if ( offset === undefined ) offset = 0;
array[ offset ] = this.x;
array[ offset + 1 ] = this.y;
array[ offset + 2 ] = this.z;
return array;
},
fromBufferAttribute: function ( attribute, index, offset ) {
if ( offset !== undefined ) {
console.warn( 'THREE.Vector3: offset has been removed from .fromBufferAttribute().' );
}
this.x = attribute.getX( index );
this.y = attribute.getY( index );
this.z = attribute.getZ( index );
return this;
}
} );
/**
* @author mrdoob / http://mrdoob.com/
* @author supereggbert / http://www.paulbrunt.co.uk/
* @author philogb / http://blog.thejit.org/
* @author jordi_ros / http://plattsoft.com
* @author D1plo1d / http://github.com/D1plo1d
* @author alteredq / http://alteredqualia.com/
* @author mikael emtinger / http://gomo.se/
* @author timknip / http://www.floorplanner.com/
* @author bhouston / http://clara.io
* @author WestLangley / http://github.com/WestLangley
*/
function Matrix4() {
this.elements = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
];
if ( arguments.length > 0 ) {
console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' );
}
}
Object.assign( Matrix4.prototype, {
isMatrix4: true,
set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
var te = this.elements;
te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14;
te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24;
te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34;
te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44;
return this;
},
identity: function () {
this.set(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
);
return this;
},
clone: function () {
return new Matrix4().fromArray( this.elements );
},
copy: function ( m ) {
var te = this.elements;
var me = m.elements;
te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ];
te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ];
te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ];
te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ];
return this;
},
copyPosition: function ( m ) {
var te = this.elements, me = m.elements;
te[ 12 ] = me[ 12 ];
te[ 13 ] = me[ 13 ];
te[ 14 ] = me[ 14 ];
return this;
},
extractBasis: function ( xAxis, yAxis, zAxis ) {
xAxis.setFromMatrixColumn( this, 0 );
yAxis.setFromMatrixColumn( this, 1 );
zAxis.setFromMatrixColumn( this, 2 );
return this;
},
makeBasis: function ( xAxis, yAxis, zAxis ) {
this.set(
xAxis.x, yAxis.x, zAxis.x, 0,
xAxis.y, yAxis.y, zAxis.y, 0,
xAxis.z, yAxis.z, zAxis.z, 0,
0, 0, 0, 1
);
return this;
},
extractRotation: function () {
var v1 = new Vector3();
return function extractRotation( m ) {
var te = this.elements;
var me = m.elements;
var scaleX = 1 / v1.setFromMatrixColumn( m, 0 ).length();
var scaleY = 1 / v1.setFromMatrixColumn( m, 1 ).length();
var scaleZ = 1 / v1.setFromMatrixColumn( m, 2 ).length();
te[ 0 ] = me[ 0 ] * scaleX;
te[ 1 ] = me[ 1 ] * scaleX;
te[ 2 ] = me[ 2 ] * scaleX;
te[ 4 ] = me[ 4 ] * scaleY;
te[ 5 ] = me[ 5 ] * scaleY;
te[ 6 ] = me[ 6 ] * scaleY;
te[ 8 ] = me[ 8 ] * scaleZ;
te[ 9 ] = me[ 9 ] * scaleZ;
te[ 10 ] = me[ 10 ] * scaleZ;
return this;
};
}(),
makeRotationFromEuler: function ( euler ) {
if ( ( euler && euler.isEuler ) === false ) {
console.error( 'THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' );
}
var te = this.elements;
var x = euler.x, y = euler.y, z = euler.z;
var a = Math.cos( x ), b = Math.sin( x );
var c = Math.cos( y ), d = Math.sin( y );
var e = Math.cos( z ), f = Math.sin( z );
if ( euler.order === 'XYZ' ) {
var ae = a * e, af = a * f, be = b * e, bf = b * f;
te[ 0 ] = c * e;
te[ 4 ] = - c * f;
te[ 8 ] = d;
te[ 1 ] = af + be * d;
te[ 5 ] = ae - bf * d;
te[ 9 ] = - b * c;
te[ 2 ] = bf - ae * d;
te[ 6 ] = be + af * d;
te[ 10 ] = a * c;
} else if ( euler.order === 'YXZ' ) {
var ce = c * e, cf = c * f, de = d * e, df = d * f;
te[ 0 ] = ce + df * b;
te[ 4 ] = de * b - cf;
te[ 8 ] = a * d;
te[ 1 ] = a * f;
te[ 5 ] = a * e;
te[ 9 ] = - b;
te[ 2 ] = cf * b - de;
te[ 6 ] = df + ce * b;
te[ 10 ] = a * c;
} else if ( euler.order === 'ZXY' ) {
var ce = c * e, cf = c * f, de = d * e, df = d * f;
te[ 0 ] = ce - df * b;
te[ 4 ] = - a * f;
te[ 8 ] = de + cf * b;
te[ 1 ] = cf + de * b;
te[ 5 ] = a * e;
te[ 9 ] = df - ce * b;
te[ 2 ] = - a * d;
te[ 6 ] = b;
te[ 10 ] = a * c;
} else if ( euler.order === 'ZYX' ) {
var ae = a * e, af = a * f, be = b * e, bf = b * f;
te[ 0 ] = c * e;
te[ 4 ] = be * d - af;
te[ 8 ] = ae * d + bf;
te[ 1 ] = c * f;
te[ 5 ] = bf * d + ae;
te[ 9 ] = af * d - be;
te[ 2 ] = - d;
te[ 6 ] = b * c;
te[ 10 ] = a * c;
} else if ( euler.order === 'YZX' ) {
var ac = a * c, ad = a * d, bc = b * c, bd = b * d;
te[ 0 ] = c * e;
te[ 4 ] = bd - ac * f;
te[ 8 ] = bc * f + ad;
te[ 1 ] = f;
te[ 5 ] = a * e;
te[ 9 ] = - b * e;
te[ 2 ] = - d * e;
te[ 6 ] = ad * f + bc;
te[ 10 ] = ac - bd * f;
} else if ( euler.order === 'XZY' ) {
var ac = a * c, ad = a * d, bc = b * c, bd = b * d;
te[ 0 ] = c * e;
te[ 4 ] = - f;
te[ 8 ] = d * e;
te[ 1 ] = ac * f + bd;
te[ 5 ] = a * e;
te[ 9 ] = ad * f - bc;
te[ 2 ] = bc * f - ad;
te[ 6 ] = b * e;
te[ 10 ] = bd * f + ac;
}
// last column
te[ 3 ] = 0;
te[ 7 ] = 0;
te[ 11 ] = 0;
// bottom row
te[ 12 ] = 0;
te[ 13 ] = 0;
te[ 14 ] = 0;
te[ 15 ] = 1;
return this;
},
makeRotationFromQuaternion: function ( q ) {
var te = this.elements;
var x = q._x, y = q._y, z = q._z, w = q._w;
var x2 = x + x, y2 = y + y, z2 = z + z;
var xx = x * x2, xy = x * y2, xz = x * z2;
var yy = y * y2, yz = y * z2, zz = z * z2;
var wx = w * x2, wy = w * y2, wz = w * z2;
te[ 0 ] = 1 - ( yy + zz );
te[ 4 ] = xy - wz;
te[ 8 ] = xz + wy;
te[ 1 ] = xy + wz;
te[ 5 ] = 1 - ( xx + zz );
te[ 9 ] = yz - wx;
te[ 2 ] = xz - wy;
te[ 6 ] = yz + wx;
te[ 10 ] = 1 - ( xx + yy );
// last column
te[ 3 ] = 0;
te[ 7 ] = 0;
te[ 11 ] = 0;
// bottom row
te[ 12 ] = 0;
te[ 13 ] = 0;
te[ 14 ] = 0;
te[ 15 ] = 1;
return this;
},
lookAt: function () {
var x = new Vector3();
var y = new Vector3();
var z = new Vector3();
return function lookAt( eye, target, up ) {
var te = this.elements;
z.subVectors( eye, target );
if ( z.lengthSq() === 0 ) {
// eye and target are in the same position
z.z = 1;
}
z.normalize();
x.crossVectors( up, z );
if ( x.lengthSq() === 0 ) {
// eye and target are in the same vertical
z.z += 0.0001;
x.crossVectors( up, z );
}
x.normalize();
y.crossVectors( z, x );
te[ 0 ] = x.x; te[ 4 ] = y.x; te[ 8 ] = z.x;
te[ 1 ] = x.y; te[ 5 ] = y.y; te[ 9 ] = z.y;
te[ 2 ] = x.z; te[ 6 ] = y.z; te[ 10 ] = z.z;
return this;
};
}(),
multiply: function ( m, n ) {
if ( n !== undefined ) {
console.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' );
return this.multiplyMatrices( m, n );
}
return this.multiplyMatrices( this, m );
},
premultiply: function ( m ) {
return this.multiplyMatrices( m, this );
},
multiplyMatrices: function ( a, b ) {
var ae = a.elements;
var be = b.elements;
var te = this.elements;
var a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ];
var a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ];
var a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ];
var a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ];
var b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ];
var b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ];
var b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ];
var b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ];
te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
return this;
},
multiplyScalar: function ( s ) {
var te = this.elements;
te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s;
te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s;
te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s;
te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s;
return this;
},
applyToBufferAttribute: function () {
var v1 = new Vector3();
return function applyToBufferAttribute( attribute ) {
for ( var i = 0, l = attribute.count; i < l; i ++ ) {
v1.x = attribute.getX( i );
v1.y = attribute.getY( i );
v1.z = attribute.getZ( i );
v1.applyMatrix4( this );
attribute.setXYZ( i, v1.x, v1.y, v1.z );
}
return attribute;
};
}(),
determinant: function () {
var te = this.elements;
var n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ];
var n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ];
var n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ];
var n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ];
//TODO: make this more efficient
//( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )
return (
n41 * (
+ n14 * n23 * n32
- n13 * n24 * n32
- n14 * n22 * n33
+ n12 * n24 * n33
+ n13 * n22 * n34
- n12 * n23 * n34
) +
n42 * (
+ n11 * n23 * n34
- n11 * n24 * n33
+ n14 * n21 * n33
- n13 * n21 * n34
+ n13 * n24 * n31
- n14 * n23 * n31
) +
n43 * (
+ n11 * n24 * n32
- n11 * n22 * n34
- n14 * n21 * n32
+ n12 * n21 * n34
+ n14 * n22 * n31
- n12 * n24 * n31
) +
n44 * (
- n13 * n22 * n31
- n11 * n23 * n32
+ n11 * n22 * n33
+ n13 * n21 * n32
- n12 * n21 * n33
+ n12 * n23 * n31
)
);
},
transpose: function () {
var te = this.elements;
var tmp;
tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp;
tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp;
tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp;
tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp;
tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp;
tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp;
return this;
},
setPosition: function ( v ) {
var te = this.elements;
te[ 12 ] = v.x;
te[ 13 ] = v.y;
te[ 14 ] = v.z;
return this;
},
getInverse: function ( m, throwOnDegenerate ) {
// based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
var te = this.elements,
me = m.elements,
n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ], n41 = me[ 3 ],
n12 = me[ 4 ], n22 = me[ 5 ], n32 = me[ 6 ], n42 = me[ 7 ],
n13 = me[ 8 ], n23 = me[ 9 ], n33 = me[ 10 ], n43 = me[ 11 ],
n14 = me[ 12 ], n24 = me[ 13 ], n34 = me[ 14 ], n44 = me[ 15 ],
t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44,
t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44,
t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44,
t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;
var det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;
if ( det === 0 ) {
var msg = "THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0";
if ( throwOnDegenerate === true ) {
throw new Error( msg );
} else {
console.warn( msg );
}
return this.identity();
}
var detInv = 1 / det;
te[ 0 ] = t11 * detInv;
te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv;
te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv;
te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv;
te[ 4 ] = t12 * detInv;
te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv;
te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv;
te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv;
te[ 8 ] = t13 * detInv;
te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv;
te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv;
te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv;
te[ 12 ] = t14 * detInv;
te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv;
te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv;
te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv;
return this;
},
scale: function ( v ) {
var te = this.elements;
var x = v.x, y = v.y, z = v.z;
te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z;
te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z;
te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z;
te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z;
return this;
},
getMaxScaleOnAxis: function () {
var te = this.elements;
var scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ];
var scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ];
var scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ];
return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) );
},
makeTranslation: function ( x, y, z ) {
this.set(
1, 0, 0, x,
0, 1, 0, y,
0, 0, 1, z,
0, 0, 0, 1
);
return this;
},
makeRotationX: function ( theta ) {
var c = Math.cos( theta ), s = Math.sin( theta );
this.set(
1, 0, 0, 0,
0, c, - s, 0,
0, s, c, 0,
0, 0, 0, 1
);
return this;
},
makeRotationY: function ( theta ) {
var c = Math.cos( theta ), s = Math.sin( theta );
this.set(
c, 0, s, 0,
0, 1, 0, 0,
- s, 0, c, 0,
0, 0, 0, 1
);
return this;
},
makeRotationZ: function ( theta ) {
var c = Math.cos( theta ), s = Math.sin( theta );
this.set(
c, - s, 0, 0,
s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
);
return this;
},
makeRotationAxis: function ( axis, angle ) {
// Based on http://www.gamedev.net/reference/articles/article1199.asp
var c = Math.cos( angle );
var s = Math.sin( angle );
var t = 1 - c;
var x = axis.x, y = axis.y, z = axis.z;
var tx = t * x, ty = t * y;
this.set(
tx * x + c, tx * y - s * z, tx * z + s * y, 0,
tx * y + s * z, ty * y + c, ty * z - s * x, 0,
tx * z - s * y, ty * z + s * x, t * z * z + c, 0,
0, 0, 0, 1
);
return this;
},
makeScale: function ( x, y, z ) {
this.set(
x, 0, 0, 0,
0, y, 0, 0,
0, 0, z, 0,
0, 0, 0, 1
);
return this;
},
makeShear: function ( x, y, z ) {
this.set(
1, y, z, 0,
x, 1, z, 0,
x, y, 1, 0,
0, 0, 0, 1
);
return this;
},
compose: function ( position, quaternion, scale ) {
this.makeRotationFromQuaternion( quaternion );
this.scale( scale );
this.setPosition( position );
return this;
},
decompose: function () {
var vector = new Vector3();
var matrix = new Matrix4();
return function decompose( position, quaternion, scale ) {
var te = this.elements;
var sx = vector.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();
var sy = vector.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();
var sz = vector.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();
// if determine is negative, we need to invert one scale
var det = this.determinant();
if ( det < 0 ) sx = - sx;
position.x = te[ 12 ];
position.y = te[ 13 ];
position.z = te[ 14 ];
// scale the rotation part
matrix.copy( this );
var invSX = 1 / sx;
var invSY = 1 / sy;
var invSZ = 1 / sz;
matrix.elements[ 0 ] *= invSX;
matrix.elements[ 1 ] *= invSX;
matrix.elements[ 2 ] *= invSX;
matrix.elements[ 4 ] *= invSY;
matrix.elements[ 5 ] *= invSY;
matrix.elements[ 6 ] *= invSY;
matrix.elements[ 8 ] *= invSZ;
matrix.elements[ 9 ] *= invSZ;
matrix.elements[ 10 ] *= invSZ;
quaternion.setFromRotationMatrix( matrix );
scale.x = sx;
scale.y = sy;
scale.z = sz;
return this;
};
}(),
makePerspective: function ( left, right, top, bottom, near, far ) {
if ( far === undefined ) {
console.warn( 'THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.' );
}
var te = this.elements;
var x = 2 * near / ( right - left );
var y = 2 * near / ( top - bottom );
var a = ( right + left ) / ( right - left );
var b = ( top + bottom ) / ( top - bottom );
var c = - ( far + near ) / ( far - near );
var d = - 2 * far * near / ( far - near );
te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0;
te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0;
te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d;
te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0;
return this;
},
makeOrthographic: function ( left, right, top, bottom, near, far ) {
var te = this.elements;
var w = 1.0 / ( right - left );
var h = 1.0 / ( top - bottom );
var p = 1.0 / ( far - near );
var x = ( right + left ) * w;
var y = ( top + bottom ) * h;
var z = ( far + near ) * p;
te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x;
te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y;
te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = - 2 * p; te[ 14 ] = - z;
te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1;
return this;
},
equals: function ( matrix ) {
var te = this.elements;
var me = matrix.elements;
for ( var i = 0; i < 16; i ++ ) {
if ( te[ i ] !== me[ i ] ) return false;
}
return true;
},
fromArray: function ( array, offset ) {
if ( offset === undefined ) offset = 0;
for ( var i = 0; i < 16; i ++ ) {
this.elements[ i ] = array[ i + offset ];
}
return this;
},
toArray: function ( array, offset ) {
if ( array === undefined ) array = [];
if ( offset === undefined ) offset = 0;
var te = this.elements;
array[ offset ] = te[ 0 ];
array[ offset + 1 ] = te[ 1 ];
array[ offset + 2 ] = te[ 2 ];
array[ offset + 3 ] = te[ 3 ];
array[ offset + 4 ] = te[ 4 ];
array[ offset + 5 ] = te[ 5 ];
array[ offset + 6 ] = te[ 6 ];
array[ offset + 7 ] = te[ 7 ];
array[ offset + 8 ] = te[ 8 ];
array[ offset + 9 ] = te[ 9 ];
array[ offset + 10 ] = te[ 10 ];
array[ offset + 11 ] = te[ 11 ];
array[ offset + 12 ] = te[ 12 ];
array[ offset + 13 ] = te[ 13 ];
array[ offset + 14 ] = te[ 14 ];
array[ offset + 15 ] = te[ 15 ];
return array;
}
} );
/**
* @author alteredq / http://alteredqualia.com/
*/
function DataTexture( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) {
Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
this.image = { data: data, width: width, height: height };
this.magFilter = magFilter !== undefined ? magFilter : NearestFilter;
this.minFilter = minFilter !== undefined ? minFilter : NearestFilter;
this.generateMipmaps = false;
this.flipY = false;
this.unpackAlignment = 1;
}
DataTexture.prototype = Object.create( Texture.prototype );
DataTexture.prototype.constructor = DataTexture;
DataTexture.prototype.isDataTexture = true;
/**
* @author mrdoob / http://mrdoob.com/
*/
function CubeTexture( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) {
images = images !== undefined ? images : [];
mapping = mapping !== undefined ? mapping : CubeReflectionMapping;
Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
this.flipY = false;
}
CubeTexture.prototype = Object.create( Texture.prototype );
CubeTexture.prototype.constructor = CubeTexture;
CubeTexture.prototype.isCubeTexture = true;
Object.defineProperty( CubeTexture.prototype, 'images', {
get: function () {
return this.image;
},
set: function ( value ) {
this.image = value;
}
} );
/**
* @author tschw
*
* Uniforms of a program.
* Those form a tree structure with a special top-level container for the root,
* which you get by calling 'new WebGLUniforms( gl, program, renderer )'.
*
*
* Properties of inner nodes including the top-level container:
*
* .seq - array of nested uniforms
* .map - nested uniforms by name
*
*
* Methods of all nodes except the top-level container:
*
* .setValue( gl, value, [renderer] )
*
* uploads a uniform value(s)
* the 'renderer' parameter is needed for sampler uniforms
*
*
* Static methods of the top-level container (renderer factorizations):
*
* .upload( gl, seq, values, renderer )
*
* sets uniforms in 'seq' to 'values[id].value'
*
* .seqWithValue( seq, values ) : filteredSeq
*
* filters 'seq' entries with corresponding entry in values
*
*
* Methods of the top-level container (renderer factorizations):
*
* .setValue( gl, name, value )
*
* sets uniform with name 'name' to 'value'
*
* .set( gl, obj, prop )
*
* sets uniform from object and property with same name than uniform
*
* .setOptional( gl, obj, prop )
*
* like .set for an optional property of the object
*
*/
var emptyTexture = new Texture();
var emptyCubeTexture = new CubeTexture();
// --- Base for inner nodes (including the root) ---
function UniformContainer() {
this.seq = [];
this.map = {};
}
// --- Utilities ---
// Array Caches (provide typed arrays for temporary by size)
var arrayCacheF32 = [];
var arrayCacheI32 = [];
// Float32Array caches used for uploading Matrix uniforms
var mat4array = new Float32Array( 16 );
var mat3array = new Float32Array( 9 );
// Flattening for arrays of vectors and matrices
function flatten( array, nBlocks, blockSize ) {
var firstElem = array[ 0 ];
if ( firstElem <= 0 || firstElem > 0 ) return array;
// unoptimized: ! isNaN( firstElem )
// see http://jacksondunstan.com/articles/983
var n = nBlocks * blockSize,
r = arrayCacheF32[ n ];
if ( r === undefined ) {
r = new Float32Array( n );
arrayCacheF32[ n ] = r;
}
if ( nBlocks !== 0 ) {
firstElem.toArray( r, 0 );
for ( var i = 1, offset = 0; i !== nBlocks; ++ i ) {
offset += blockSize;
array[ i ].toArray( r, offset );
}
}
return r;
}
// Texture unit allocation
function allocTexUnits( renderer, n ) {
var r = arrayCacheI32[ n ];
if ( r === undefined ) {
r = new Int32Array( n );
arrayCacheI32[ n ] = r;
}
for ( var i = 0; i !== n; ++ i )
r[ i ] = renderer.allocTextureUnit();
return r;
}
// --- Setters ---
// Note: Defining these methods externally, because they come in a bunch
// and this way their names minify.
// Single scalar
function setValue1f( gl, v ) { gl.uniform1f( this.addr, v ); }
function setValue1i( gl, v ) { gl.uniform1i( this.addr, v ); }
// Single float vector (from flat array or THREE.VectorN)
function setValue2fv( gl, v ) {
if ( v.x === undefined ) gl.uniform2fv( this.addr, v );
else gl.uniform2f( this.addr, v.x, v.y );
}
function setValue3fv( gl, v ) {
if ( v.x !== undefined )
gl.uniform3f( this.addr, v.x, v.y, v.z );
else if ( v.r !== undefined )
gl.uniform3f( this.addr, v.r, v.g, v.b );
else
gl.uniform3fv( this.addr, v );
}
function setValue4fv( gl, v ) {
if ( v.x === undefined ) gl.uniform4fv( this.addr, v );
else gl.uniform4f( this.addr, v.x, v.y, v.z, v.w );
}
// Single matrix (from flat array or MatrixN)
function setValue2fm( gl, v ) {
gl.uniformMatrix2fv( this.addr, false, v.elements || v );
}
function setValue3fm( gl, v ) {
if ( v.elements === undefined ) {
gl.uniformMatrix3fv( this.addr, false, v );
} else {
mat3array.set( v.elements );
gl.uniformMatrix3fv( this.addr, false, mat3array );
}
}
function setValue4fm( gl, v ) {
if ( v.elements === undefined ) {
gl.uniformMatrix4fv( this.addr, false, v );
} else {
mat4array.set( v.elements );
gl.uniformMatrix4fv( this.addr, false, mat4array );
}
}
// Single texture (2D / Cube)
function setValueT1( gl, v, renderer ) {
var unit = renderer.allocTextureUnit();
gl.uniform1i( this.addr, unit );
renderer.setTexture2D( v || emptyTexture, unit );
}
function setValueT6( gl, v, renderer ) {
var unit = renderer.allocTextureUnit();
gl.uniform1i( this.addr, unit );
renderer.setTextureCube( v || emptyCubeTexture, unit );
}
// Integer / Boolean vectors or arrays thereof (always flat arrays)
function setValue2iv( gl, v ) { gl.uniform2iv( this.addr, v ); }
function setValue3iv( gl, v ) { gl.uniform3iv( this.addr, v ); }
function setValue4iv( gl, v ) { gl.uniform4iv( this.addr, v ); }
// Helper to pick the right setter for the singular case
function getSingularSetter( type ) {
switch ( type ) {
case 0x1406: return setValue1f; // FLOAT
case 0x8b50: return setValue2fv; // _VEC2
case 0x8b51: return setValue3fv; // _VEC3
case 0x8b52: return setValue4fv; // _VEC4
case 0x8b5a: return setValue2fm; // _MAT2
case 0x8b5b: return setValue3fm; // _MAT3
case 0x8b5c: return setValue4fm; // _MAT4
case 0x8b5e: return setValueT1; // SAMPLER_2D
case 0x8b60: return setValueT6; // SAMPLER_CUBE
case 0x1404: case 0x8b56: return setValue1i; // INT, BOOL
case 0x8b53: case 0x8b57: return setValue2iv; // _VEC2
case 0x8b54: case 0x8b58: return setValue3iv; // _VEC3
case 0x8b55: case 0x8b59: return setValue4iv; // _VEC4
}
}
// Array of scalars
function setValue1fv( gl, v ) { gl.uniform1fv( this.addr, v ); }
function setValue1iv( gl, v ) { gl.uniform1iv( this.addr, v ); }
// Array of vectors (flat or from THREE classes)
function setValueV2a( gl, v ) {
gl.uniform2fv( this.addr, flatten( v, this.size, 2 ) );
}
function setValueV3a( gl, v ) {
gl.uniform3fv( this.addr, flatten( v, this.size, 3 ) );
}
function setValueV4a( gl, v ) {
gl.uniform4fv( this.addr, flatten( v, this.size, 4 ) );
}
// Array of matrices (flat or from THREE clases)
function setValueM2a( gl, v ) {
gl.uniformMatrix2fv( this.addr, false, flatten( v, this.size, 4 ) );
}
function setValueM3a( gl, v ) {
gl.uniformMatrix3fv( this.addr, false, flatten( v, this.size, 9 ) );
}
function setValueM4a( gl, v ) {
gl.uniformMatrix4fv( this.addr, false, flatten( v, this.size, 16 ) );
}
// Array of textures (2D / Cube)
function setValueT1a( gl, v, renderer ) {
var n = v.length,
units = allocTexUnits( renderer, n );
gl.uniform1iv( this.addr, units );
for ( var i = 0; i !== n; ++ i ) {
renderer.setTexture2D( v[ i ] || emptyTexture, units[ i ] );
}
}
function setValueT6a( gl, v, renderer ) {
var n = v.length,
units = allocTexUnits( renderer, n );
gl.uniform1iv( this.addr, units );
for ( var i = 0; i !== n; ++ i ) {
renderer.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] );
}
}
// Helper to pick the right setter for a pure (bottom-level) array
function getPureArraySetter( type ) {
switch ( type ) {
case 0x1406: return setValue1fv; // FLOAT
case 0x8b50: return setValueV2a; // _VEC2
case 0x8b51: return setValueV3a; // _VEC3
case 0x8b52: return setValueV4a; // _VEC4
case 0x8b5a: return setValueM2a; // _MAT2
case 0x8b5b: return setValueM3a; // _MAT3
case 0x8b5c: return setValueM4a; // _MAT4
case 0x8b5e: return setValueT1a; // SAMPLER_2D
case 0x8b60: return setValueT6a; // SAMPLER_CUBE
case 0x1404: case 0x8b56: return setValue1iv; // INT, BOOL
case 0x8b53: case 0x8b57: return setValue2iv; // _VEC2
case 0x8b54: case 0x8b58: return setValue3iv; // _VEC3
case 0x8b55: case 0x8b59: return setValue4iv; // _VEC4
}
}
// --- Uniform Classes ---
function SingleUniform( id, activeInfo, addr ) {
this.id = id;
this.addr = addr;
this.setValue = getSingularSetter( activeInfo.type );
// this.path = activeInfo.name; // DEBUG
}
function PureArrayUniform( id, activeInfo, addr ) {
this.id = id;
this.addr = addr;
this.size = activeInfo.size;
this.setValue = getPureArraySetter( activeInfo.type );
// this.path = activeInfo.name; // DEBUG
}
function StructuredUniform( id ) {
this.id = id;
UniformContainer.call( this ); // mix-in
}
StructuredUniform.prototype.setValue = function ( gl, value ) {
// Note: Don't need an extra 'renderer' parameter, since samplers
// are not allowed in structured uniforms.
var seq = this.seq;
for ( var i = 0, n = seq.length; i !== n; ++ i ) {
var u = seq[ i ];
u.setValue( gl, value[ u.id ] );
}
};
// --- Top-level ---
// Parser - builds up the property tree from the path strings
var RePathPart = /([\w\d_]+)(\])?(\[|\.)?/g;
// extracts
// - the identifier (member name or array index)
// - followed by an optional right bracket (found when array index)
// - followed by an optional left bracket or dot (type of subscript)
//
// Note: These portions can be read in a non-overlapping fashion and
// allow straightforward parsing of the hierarchy that WebGL encodes
// in the uniform names.
function addUniform( container, uniformObject ) {
container.seq.push( uniformObject );
container.map[ uniformObject.id ] = uniformObject;
}
function parseUniform( activeInfo, addr, container ) {
var path = activeInfo.name,
pathLength = path.length;
// reset RegExp object, because of the early exit of a previous run
RePathPart.lastIndex = 0;
for ( ; ; ) {
var match = RePathPart.exec( path ),
matchEnd = RePathPart.lastIndex,
id = match[ 1 ],
idIsIndex = match[ 2 ] === ']',
subscript = match[ 3 ];
if ( idIsIndex ) id = id | 0; // convert to integer
if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) {
// bare name or "pure" bottom-level array "[0]" suffix
addUniform( container, subscript === undefined ?
new SingleUniform( id, activeInfo, addr ) :
new PureArrayUniform( id, activeInfo, addr ) );
break;
} else {
// step into inner node / create it in case it doesn't exist
var map = container.map, next = map[ id ];
if ( next === undefined ) {
next = new StructuredUniform( id );
addUniform( container, next );
}
container = next;
}
}
}
// Root Container
function WebGLUniforms( gl, program, renderer ) {
UniformContainer.call( this );
this.renderer = renderer;
var n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS );
for ( var i = 0; i < n; ++ i ) {
var info = gl.getActiveUniform( program, i ),
path = info.name,
addr = gl.getUniformLocation( program, path );
parseUniform( info, addr, this );
}
}
WebGLUniforms.prototype.setValue = function ( gl, name, value ) {
var u = this.map[ name ];
if ( u !== undefined ) u.setValue( gl, value, this.renderer );
};
WebGLUniforms.prototype.setOptional = function ( gl, object, name ) {
var v = object[ name ];
if ( v !== undefined ) this.setValue( gl, name, v );
};
// Static interface
WebGLUniforms.upload = function ( gl, seq, values, renderer ) {
for ( var i = 0, n = seq.length; i !== n; ++ i ) {
var u = seq[ i ],
v = values[ u.id ];
if ( v.needsUpdate !== false ) {
// note: always updating when .needsUpdate is undefined
u.setValue( gl, v.value, renderer );
}
}
};
WebGLUniforms.seqWithValue = function ( seq, values ) {
var r = [];
for ( var i = 0, n = seq.length; i !== n; ++ i ) {
var u = seq[ i ];
if ( u.id in values ) r.push( u );
}
return r;
};
/**
* @author mrdoob / http://mrdoob.com/
*/
var ColorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,
'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,
'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,
'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,
'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,
'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,
'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,
'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,
'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,
'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,
'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,
'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,
'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,
'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,
'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,
'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,
'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,
'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,
'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,
'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,
'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };
function Color( r, g, b ) {
if ( g === undefined && b === undefined ) {
// r is THREE.Color, hex or string
return this.set( r );
}
return this.setRGB( r, g, b );
}
Object.assign( Color.prototype, {
isColor: true,
r: 1, g: 1, b: 1,
set: function ( value ) {
if ( value && value.isColor ) {
this.copy( value );
} else if ( typeof value === 'number' ) {
this.setHex( value );
} else if ( typeof value === 'string' ) {
this.setStyle( value );
}
return this;
},
setScalar: function ( scalar ) {
this.r = scalar;
this.g = scalar;
this.b = scalar;
return this;
},
setHex: function ( hex ) {
hex = Math.floor( hex );
this.r = ( hex >> 16 & 255 ) / 255;
this.g = ( hex >> 8 & 255 ) / 255;
this.b = ( hex & 255 ) / 255;
return this;
},
setRGB: function ( r, g, b ) {
this.r = r;
this.g = g;
this.b = b;
return this;
},
setHSL: function () {
function hue2rgb( p, q, t ) {
if ( t < 0 ) t += 1;
if ( t > 1 ) t -= 1;
if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;
if ( t < 1 / 2 ) return q;
if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );
return p;
}
return function setHSL( h, s, l ) {
// h,s,l ranges are in 0.0 - 1.0
h = _Math.euclideanModulo( h, 1 );
s = _Math.clamp( s, 0, 1 );
l = _Math.clamp( l, 0, 1 );
if ( s === 0 ) {
this.r = this.g = this.b = l;
} else {
var p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );
var q = ( 2 * l ) - p;
this.r = hue2rgb( q, p, h + 1 / 3 );
this.g = hue2rgb( q, p, h );
this.b = hue2rgb( q, p, h - 1 / 3 );
}
return this;
};
}(),
setStyle: function ( style ) {
function handleAlpha( string ) {
if ( string === undefined ) return;
if ( parseFloat( string ) < 1 ) {
console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' );
}
}
var m;
if ( m = /^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec( style ) ) {
// rgb / hsl
var color;
var name = m[ 1 ];
var components = m[ 2 ];
switch ( name ) {
case 'rgb':
case 'rgba':
if ( color = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {
// rgb(255,0,0) rgba(255,0,0,0.5)
this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255;
this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255;
this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255;
handleAlpha( color[ 5 ] );
return this;
}
if ( color = /^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {
// rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)
this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100;
this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100;
this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100;
handleAlpha( color[ 5 ] );
return this;
}
break;
case 'hsl':
case 'hsla':
if ( color = /^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {
// hsl(120,50%,50%) hsla(120,50%,50%,0.5)
var h = parseFloat( color[ 1 ] ) / 360;
var s = parseInt( color[ 2 ], 10 ) / 100;
var l = parseInt( color[ 3 ], 10 ) / 100;
handleAlpha( color[ 5 ] );
return this.setHSL( h, s, l );
}
break;
}
} else if ( m = /^\#([A-Fa-f0-9]+)$/.exec( style ) ) {
// hex color
var hex = m[ 1 ];
var size = hex.length;
if ( size === 3 ) {
// #ff0
this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255;
this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255;
this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255;
return this;
} else if ( size === 6 ) {
// #ff0000
this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255;
this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255;
this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255;
return this;
}
}
if ( style && style.length > 0 ) {
// color keywords
var hex = ColorKeywords[ style ];
if ( hex !== undefined ) {
// red
this.setHex( hex );
} else {
// unknown color
console.warn( 'THREE.Color: Unknown color ' + style );
}
}
return this;
},
clone: function () {
return new this.constructor( this.r, this.g, this.b );
},
copy: function ( color ) {
this.r = color.r;
this.g = color.g;
this.b = color.b;
return this;
},
copyGammaToLinear: function ( color, gammaFactor ) {
if ( gammaFactor === undefined ) gammaFactor = 2.0;
this.r = Math.pow( color.r, gammaFactor );
this.g = Math.pow( color.g, gammaFactor );
this.b = Math.pow( color.b, gammaFactor );
return this;
},
copyLinearToGamma: function ( color, gammaFactor ) {
if ( gammaFactor === undefined ) gammaFactor = 2.0;
var safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0;
this.r = Math.pow( color.r, safeInverse );
this.g = Math.pow( color.g, safeInverse );
this.b = Math.pow( color.b, safeInverse );
return this;
},
convertGammaToLinear: function () {
var r = this.r, g = this.g, b = this.b;
this.r = r * r;
this.g = g * g;
this.b = b * b;
return this;
},
convertLinearToGamma: function () {
this.r = Math.sqrt( this.r );
this.g = Math.sqrt( this.g );
this.b = Math.sqrt( this.b );
return this;
},
getHex: function () {
return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0;
},
getHexString: function () {
return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 );
},
getHSL: function ( optionalTarget ) {
// h,s,l ranges are in 0.0 - 1.0
var hsl = optionalTarget || { h: 0, s: 0, l: 0 };
var r = this.r, g = this.g, b = this.b;
var max = Math.max( r, g, b );
var min = Math.min( r, g, b );
var hue, saturation;
var lightness = ( min + max ) / 2.0;
if ( min === max ) {
hue = 0;
saturation = 0;
} else {
var delta = max - min;
saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min );
switch ( max ) {
case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break;
case g: hue = ( b - r ) / delta + 2; break;
case b: hue = ( r - g ) / delta + 4; break;
}
hue /= 6;
}
hsl.h = hue;
hsl.s = saturation;
hsl.l = lightness;
return hsl;
},
getStyle: function () {
return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')';
},
offsetHSL: function ( h, s, l ) {
var hsl = this.getHSL();
hsl.h += h; hsl.s += s; hsl.l += l;
this.setHSL( hsl.h, hsl.s, hsl.l );
return this;
},
add: function ( color ) {
this.r += color.r;
this.g += color.g;
this.b += color.b;
return this;
},
addColors: function ( color1, color2 ) {
this.r = color1.r + color2.r;
this.g = color1.g + color2.g;
this.b = color1.b + color2.b;
return this;
},
addScalar: function ( s ) {
this.r += s;
this.g += s;
this.b += s;
return this;
},
sub: function( color ) {
this.r = Math.max( 0, this.r - color.r );
this.g = Math.max( 0, this.g - color.g );
this.b = Math.max( 0, this.b - color.b );
return this;
},
multiply: function ( color ) {
this.r *= color.r;
this.g *= color.g;
this.b *= color.b;
return this;
},
multiplyScalar: function ( s ) {
this.r *= s;
this.g *= s;
this.b *= s;
return this;
},
lerp: function ( color, alpha ) {
this.r += ( color.r - this.r ) * alpha;
this.g += ( color.g - this.g ) * alpha;
this.b += ( color.b - this.b ) * alpha;
return this;
},
equals: function ( c ) {
return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );
},
fromArray: function ( array, offset ) {
if ( offset === undefined ) offset = 0;
this.r = array[ offset ];
this.g = array[ offset + 1 ];
this.b = array[ offset + 2 ];
return this;
},
toArray: function ( array, offset ) {
if ( array === undefined ) array = [];
if ( offset === undefined ) offset = 0;
array[ offset ] = this.r;
array[ offset + 1 ] = this.g;
array[ offset + 2 ] = this.b;
return array;
},
toJSON: function () {
return this.getHex();
}
} );
/**
* Uniforms library for shared webgl shaders
*/
var UniformsLib = {
common: {
diffuse: { value: new Color( 0xeeeeee ) },
opacity: { value: 1.0 },
map: { value: null },
offsetRepeat: { value: new Vector4( 0, 0, 1, 1 ) },
specularMap: { value: null },
alphaMap: { value: null },
envMap: { value: null },
flipEnvMap: { value: - 1 },
reflectivity: { value: 1.0 },
refractionRatio: { value: 0.98 }
},
aomap: {
aoMap: { value: null },
aoMapIntensity: { value: 1 }
},
lightmap: {
lightMap: { value: null },
lightMapIntensity: { value: 1 }
},
emissivemap: {
emissiveMap: { value: null }
},
bumpmap: {
bumpMap: { value: null },
bumpScale: { value: 1 }
},
normalmap: {
normalMap: { value: null },
normalScale: { value: new Vector2( 1, 1 ) }
},
displacementmap: {
displacementMap: { value: null },
displacementScale: { value: 1 },
displacementBias: { value: 0 }
},
roughnessmap: {
roughnessMap: { value: null }
},
metalnessmap: {
metalnessMap: { value: null }
},
gradientmap: {
gradientMap: { value: null }
},
fog: {
fogDensity: { value: 0.00025 },
fogNear: { value: 1 },
fogFar: { value: 2000 },
fogColor: { value: new Color( 0xffffff ) }
},
lights: {
ambientLightColor: { value: [] },
directionalLights: { value: [], properties: {
direction: {},
color: {},
shadow: {},
shadowBias: {},
shadowRadius: {},
shadowMapSize: {}
} },
directionalShadowMap: { value: [] },
directionalShadowMatrix: { value: [] },
spotLights: { value: [], properties: {
color: {},
position: {},
direction: {},
distance: {},
coneCos: {},
penumbraCos: {},
decay: {},
shadow: {},
shadowBias: {},
shadowRadius: {},
shadowMapSize: {}
} },
spotShadowMap: { value: [] },
spotShadowMatrix: { value: [] },
pointLights: { value: [], properties: {
color: {},
position: {},
decay: {},
distance: {},
shadow: {},
shadowBias: {},
shadowRadius: {},
shadowMapSize: {}
} },
pointShadowMap: { value: [] },
pointShadowMatrix: { value: [] },
hemisphereLights: { value: [], properties: {
direction: {},
skyColor: {},
groundColor: {}
} },
// TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src
rectAreaLights: { value: [], properties: {
color: {},
position: {},
width: {},
height: {}
} }
},
points: {
diffuse: { value: new Color( 0xeeeeee ) },
opacity: { value: 1.0 },
size: { value: 1.0 },
scale: { value: 1.0 },
map: { value: null },
offsetRepeat: { value: new Vector4( 0, 0, 1, 1 ) }
}
};
/**
* Uniform Utilities
*/
var UniformsUtils = {
merge: function ( uniforms ) {
var merged = {};
for ( var u = 0; u < uniforms.length; u ++ ) {
var tmp = this.clone( uniforms[ u ] );
for ( var p in tmp ) {
merged[ p ] = tmp[ p ];
}
}
return merged;
},
clone: function ( uniforms_src ) {
var uniforms_dst = {};
for ( var u in uniforms_src ) {
uniforms_dst[ u ] = {};
for ( var p in uniforms_src[ u ] ) {
var parameter_src = uniforms_src[ u ][ p ];
if ( parameter_src && ( parameter_src.isColor ||
parameter_src.isMatrix3 || parameter_src.isMatrix4 ||
parameter_src.isVector2 || parameter_src.isVector3 || parameter_src.isVector4 ||
parameter_src.isTexture ) ) {
uniforms_dst[ u ][ p ] = parameter_src.clone();
} else if ( Array.isArray( parameter_src ) ) {
uniforms_dst[ u ][ p ] = parameter_src.slice();
} else {
uniforms_dst[ u ][ p ] = parameter_src;
}
}
}
return uniforms_dst;
}
};
var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif\n";
var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif\n";
var alphatest_fragment = "#ifdef ALPHATEST\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n#endif\n";
var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL )\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.specularRoughness );\n\t#endif\n#endif\n";
var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif";
var begin_vertex = "\nvec3 transformed = vec3( position );\n";
var beginnormal_vertex = "\nvec3 objectNormal = vec3( normal );\n";
var bsdfs = "float punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\tif( decayExponent > 0.0 ) {\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tfloat maxDistanceCutoffFactor = pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\treturn distanceFalloff * maxDistanceCutoffFactor;\n#else\n\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n#endif\n\t}\n\treturn 1.0;\n}\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\n}\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\treturn 1.0 / ( gl * gv );\n}\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( G * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat theta = acos( dot( N, V ) );\n\tvec2 uv = vec2(\n\t\tsqrt( saturate( roughness ) ),\n\t\tsaturate( theta / ( 0.5 * PI ) ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.86267 + (0.49788 + 0.01436 * y ) * y;\n\tfloat b = 3.45068 + (4.18814 + y) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = (x > 0.0) ? v : 0.5 * inversesqrt( 1.0 - x * x ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transpose( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tvec3 result = vec3( LTC_ClippedSphereFormFactor( vectorFormFactor ) );\n\treturn result;\n}\nvec3 BRDF_Specular_GGX_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n\treturn specularColor * AB.x + AB.y;\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\n}\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\n\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\n}\n";
var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\t\tvec3 vSigmaX = dFdx( surf_pos );\n\t\tvec3 vSigmaY = dFdy( surf_pos );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 );\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif\n";
var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; ++ i ) {\n\t\tvec4 plane = clippingPlanes[ i ];\n\t\tif ( dot( vViewPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t\t\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; ++ i ) {\n\t\t\tvec4 plane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vViewPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\tif ( clipped ) discard;\n\t\n\t#endif\n#endif\n";
var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\t#if ! defined( PHYSICAL ) && ! defined( PHONG )\n\t\tvarying vec3 vViewPosition;\n\t#endif\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif\n";
var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvarying vec3 vViewPosition;\n#endif\n";
var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n";
var color_fragment = "#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif";
var color_pars_fragment = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif\n";
var color_pars_vertex = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif";
var color_vertex = "#ifdef USE_COLOR\n\tvColor.xyz = color.xyz;\n#endif";
var common = "#define PI 3.14159265359\n#define PI2 6.28318530718\n#define PI_HALF 1.5707963267949\n#define RECIPROCAL_PI 0.31830988618\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.442695\n#define EPSILON 1e-6\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#define whiteCompliment(a) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract(sin(sn) * c);\n}\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\tfloat distance = dot( planeNormal, point - pointOnPlane );\n\treturn - distance * planeNormal + point;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\n}\nmat3 transpose( const in mat3 v ) {\n\tmat3 tmp;\n\ttmp[0] = vec3(v[0].x, v[1].x, v[2].x);\n\ttmp[1] = vec3(v[0].y, v[1].y, v[2].y);\n\ttmp[2] = vec3(v[0].z, v[1].z, v[2].z);\n\treturn tmp;\n}\n";
var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n#define cubeUV_textureSize (1024.0)\nint getFaceFromDirection(vec3 direction) {\n\tvec3 absDirection = abs(direction);\n\tint face = -1;\n\tif( absDirection.x > absDirection.z ) {\n\t\tif(absDirection.x > absDirection.y )\n\t\t\tface = direction.x > 0.0 ? 0 : 3;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\telse {\n\t\tif(absDirection.z > absDirection.y )\n\t\t\tface = direction.z > 0.0 ? 2 : 5;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\treturn face;\n}\n#define cubeUV_maxLods1 (log2(cubeUV_textureSize*0.25) - 1.0)\n#define cubeUV_rangeClamp (exp2((6.0 - 1.0) * 2.0))\nvec2 MipLevelInfo( vec3 vec, float roughnessLevel, float roughness ) {\n\tfloat scale = exp2(cubeUV_maxLods1 - roughnessLevel);\n\tfloat dxRoughness = dFdx(roughness);\n\tfloat dyRoughness = dFdy(roughness);\n\tvec3 dx = dFdx( vec * scale * dxRoughness );\n\tvec3 dy = dFdy( vec * scale * dyRoughness );\n\tfloat d = max( dot( dx, dx ), dot( dy, dy ) );\n\td = clamp(d, 1.0, cubeUV_rangeClamp);\n\tfloat mipLevel = 0.5 * log2(d);\n\treturn vec2(floor(mipLevel), fract(mipLevel));\n}\n#define cubeUV_maxLods2 (log2(cubeUV_textureSize*0.25) - 2.0)\n#define cubeUV_rcpTextureSize (1.0 / cubeUV_textureSize)\nvec2 getCubeUV(vec3 direction, float roughnessLevel, float mipLevel) {\n\tmipLevel = roughnessLevel > cubeUV_maxLods2 - 3.0 ? 0.0 : mipLevel;\n\tfloat a = 16.0 * cubeUV_rcpTextureSize;\n\tvec2 exp2_packed = exp2( vec2( roughnessLevel, mipLevel ) );\n\tvec2 rcp_exp2_packed = vec2( 1.0 ) / exp2_packed;\n\tfloat powScale = exp2_packed.x * exp2_packed.y;\n\tfloat scale = rcp_exp2_packed.x * rcp_exp2_packed.y * 0.25;\n\tfloat mipOffset = 0.75*(1.0 - rcp_exp2_packed.y) * rcp_exp2_packed.x;\n\tbool bRes = mipLevel == 0.0;\n\tscale = bRes && (scale < a) ? a : scale;\n\tvec3 r;\n\tvec2 offset;\n\tint face = getFaceFromDirection(direction);\n\tfloat rcpPowScale = 1.0 / powScale;\n\tif( face == 0) {\n\t\tr = vec3(direction.x, -direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 1) {\n\t\tr = vec3(direction.y, direction.x, direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 2) {\n\t\tr = vec3(direction.z, direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 3) {\n\t\tr = vec3(direction.x, direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse if( face == 4) {\n\t\tr = vec3(direction.y, direction.x, -direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse {\n\t\tr = vec3(direction.z, -direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\tr = normalize(r);\n\tfloat texelOffset = 0.5 * cubeUV_rcpTextureSize;\n\tvec2 s = ( r.yz / abs( r.x ) + vec2( 1.0 ) ) * 0.5;\n\tvec2 base = offset + vec2( texelOffset );\n\treturn base + s * ( scale - 2.0 * texelOffset );\n}\n#define cubeUV_maxLods3 (log2(cubeUV_textureSize*0.25) - 3.0)\nvec4 textureCubeUV(vec3 reflectedDirection, float roughness ) {\n\tfloat roughnessVal = roughness* cubeUV_maxLods3;\n\tfloat r1 = floor(roughnessVal);\n\tfloat r2 = r1 + 1.0;\n\tfloat t = fract(roughnessVal);\n\tvec2 mipInfo = MipLevelInfo(reflectedDirection, r1, roughness);\n\tfloat s = mipInfo.y;\n\tfloat level0 = mipInfo.x;\n\tfloat level1 = level0 + 1.0;\n\tlevel1 = level1 > 5.0 ? 5.0 : level1;\n\tlevel0 += min( floor( s + 0.5 ), 5.0 );\n\tvec2 uv_10 = getCubeUV(reflectedDirection, r1, level0);\n\tvec4 color10 = envMapTexelToLinear(texture2D(envMap, uv_10));\n\tvec2 uv_20 = getCubeUV(reflectedDirection, r2, level0);\n\tvec4 color20 = envMapTexelToLinear(texture2D(envMap, uv_20));\n\tvec4 result = mix(color10, color20, t);\n\treturn vec4(result.rgb, 1.0);\n}\n#endif\n";
var defaultnormal_vertex = "#ifdef FLIP_SIDED\n\tobjectNormal = -objectNormal;\n#endif\nvec3 transformedNormal = normalMatrix * objectNormal;\n";
var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif\n";
var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normal * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );\n#endif\n";
var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif\n";
var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif\n";
var encodings_fragment = " gl_FragColor = linearToOutputTexel( gl_FragColor );\n";
var encodings_pars_fragment = "\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );\n}\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );\n}\nvec4 sRGBToLinear( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.w );\n}\nvec4 RGBEToLinear( in vec4 value ) {\n\treturn vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );\n}\nvec4 LinearToRGBE( in vec4 value ) {\n\tfloat maxComponent = max( max( value.r, value.g ), value.b );\n\tfloat fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );\n\treturn vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );\n}\nvec4 RGBMToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.xyz * value.w * maxRange, 1.0 );\n}\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\n\tfloat M = clamp( maxRGB / maxRange, 0.0, 1.0 );\n\tM = ceil( M * 255.0 ) / 255.0;\n\treturn vec4( value.rgb / ( M * maxRange ), M );\n}\nvec4 RGBDToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );\n}\nvec4 LinearToRGBD( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\n\tfloat D = max( maxRange / maxRGB, 1.0 );\n\tD = min( floor( D ) / 255.0, 1.0 );\n\treturn vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\n}\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\nvec4 LinearToLogLuv( in vec4 value ) {\n\tvec3 Xp_Y_XYZp = value.rgb * cLogLuvM;\n\tXp_Y_XYZp = max(Xp_Y_XYZp, vec3(1e-6, 1e-6, 1e-6));\n\tvec4 vResult;\n\tvResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\n\tfloat Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\n\tvResult.w = fract(Le);\n\tvResult.z = (Le - (floor(vResult.w*255.0))/255.0)/255.0;\n\treturn vResult;\n}\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\nvec4 LogLuvToLinear( in vec4 value ) {\n\tfloat Le = value.z * 255.0 + value.w;\n\tvec3 Xp_Y_XYZp;\n\tXp_Y_XYZp.y = exp2((Le - 127.0) / 2.0);\n\tXp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\n\tXp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\n\tvec3 vRGB = Xp_Y_XYZp.rgb * cLogLuvInverseM;\n\treturn vec4( max(vRGB, 0.0), 1.0 );\n}\n";
var envmap_fragment = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\tvec2 sampleUV;\n\t\tsampleUV.y = saturate( flipNormal * reflectVec.y * 0.5 + 0.5 );\n\t\tsampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\n\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\tvec3 reflectView = flipNormal * normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) );\n\t\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\tenvColor = envMapTexelToLinear( envColor );\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif\n";
var envmap_pars_fragment = "#if defined( USE_ENVMAP ) || defined( PHYSICAL )\n\tuniform float reflectivity;\n\tuniform float envMapIntensity;\n#endif\n#ifdef USE_ENVMAP\n\t#if ! defined( PHYSICAL ) && ( defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) )\n\t\tvarying vec3 vWorldPosition;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\tuniform float flipEnvMap;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( PHYSICAL )\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif\n";
var envmap_pars_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif\n";
var envmap_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif\n";
var fog_vertex = "\n#ifdef USE_FOG\nfogDepth = -mvPosition.z;\n#endif";
var fog_pars_vertex = "#ifdef USE_FOG\n varying float fogDepth;\n#endif\n";
var fog_fragment = "#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 ) );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, fogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif\n";
var fog_pars_fragment = "#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float fogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif\n";
var gradientmap_pars_fragment = "#ifdef TOON\n\tuniform sampler2D gradientMap;\n\tvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\t\tfloat dotNL = dot( normal, lightDirection );\n\t\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t\t#ifdef USE_GRADIENTMAP\n\t\t\treturn texture2D( gradientMap, coord ).rgb;\n\t\t#else\n\t\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\n\t\t#endif\n\t}\n#endif\n";
var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\treflectedLight.indirectDiffuse += PI * texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n#endif\n";
var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif";
var lights_lambert_vertex = "vec3 diffuse = vec3( 1.0 );\nGeometricContext geometry;\ngeometry.position = mvPosition.xyz;\ngeometry.normal = normalize( transformedNormal );\ngeometry.viewDir = normalize( -mvPosition.xyz );\nGeometricContext backGeometry;\nbackGeometry.position = geometry.position;\nbackGeometry.normal = -geometry.normal;\nbackGeometry.viewDir = geometry.viewDir;\nvLightFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\n\tvLightBack = vec3( 0.0 );\n#endif\nIncidentLight directLight;\nfloat dotNL;\nvec3 directLightColor_Diffuse;\n#if NUM_POINT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tgetPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tgetSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_DIR_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tgetDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\tvLightFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\n\t\t#endif\n\t}\n#endif\n";
var lights_pars = "uniform vec3 ambientLightColor;\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treturn irradiance;\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tdirectLight.color = directionalLight.color;\n\t\tdirectLight.direction = directionalLight.direction;\n\t\tdirectLight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tdirectLight.color = pointLight.color;\n\t\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );\n\t\tdirectLight.visible = ( directLight.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tfloat angleCos = dot( directLight.direction, spotLight.direction );\n\t\tif ( angleCos > spotLight.coneCos ) {\n\t\t\tfloat spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\t\tdirectLight.color = spotLight.color;\n\t\t\tdirectLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tdirectLight.visible = true;\n\t\t} else {\n\t\t\tdirectLight.color = vec3( 0.0 );\n\t\t\tdirectLight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltcMat;\tuniform sampler2D ltcMag;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) {\n\t\tfloat dotNL = dot( geometry.normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tirradiance *= PI;\n\t\t#endif\n\t\treturn irradiance;\n\t}\n#endif\n#if defined( USE_ENVMAP ) && defined( PHYSICAL )\n\tvec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {\n\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\tvec4 envMapColor = textureCubeUV( queryVec, 1.0 );\n\t\t#else\n\t\t\tvec4 envMapColor = vec4( 0.0 );\n\t\t#endif\n\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t}\n\tfloat getSpecularMIPLevel( const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar - 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\n\t}\n\tvec3 getLightProbeIndirectRadiance( const in GeometricContext geometry, const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( -geometry.viewDir, geometry.normal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( -geometry.viewDir, geometry.normal, refractionRatio );\n\t\t#endif\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( blinnShininessExponent, maxMIPLevel );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\tvec4 envMapColor = textureCubeUV(queryReflectVec, BlinnExponentToGGXRoughness(blinnShininessExponent));\n\t\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\t\tvec2 sampleUV;\n\t\t\tsampleUV.y = saturate( reflectVec.y * 0.5 + 0.5 );\n\t\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, sampleUV, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, sampleUV, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0,0.0,1.0 ) );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#endif\n\t\treturn envMapColor.rgb * envMapIntensity;\n\t}\n#endif\n";
var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;\n";
var lights_phong_pars_fragment = "varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct BlinnPhongMaterial {\n\tvec3\tdiffuseColor;\n\tvec3\tspecularColor;\n\tfloat\tspecularShininess;\n\tfloat\tspecularStrength;\n};\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_BlinnPhong( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometry.normal;\n\t\tvec3 viewDir = geometry.viewDir;\n\t\tvec3 position = geometry.position;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = BlinnExponentToGGXRoughness( material.specularShininess );\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos - halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos + halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos + halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos - halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tfloat norm = texture2D( ltcMag, uv ).a;\n\t\tvec4 t = texture2D( ltcMat, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( 1, 0, t.y ),\n\t\t\tvec3( 0, t.z, 0 ),\n\t\t\tvec3( t.w, 0, t.x )\n\t\t);\n\t\treflectedLight.directSpecular += lightColor * material.specularColor * norm * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifdef TOON\n\t\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\t#else\n\t\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\t\tvec3 irradiance = dotNL * directLight.color;\n\t#endif\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)\n";
var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nmaterial.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );\n#ifdef STANDARD\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.clearCoat = saturate( clearCoat );\tmaterial.clearCoatRoughness = clamp( clearCoatRoughness, 0.04, 1.0 );\n#endif\n";
var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3\tdiffuseColor;\n\tfloat\tspecularRoughness;\n\tvec3\tspecularColor;\n\t#ifndef STANDARD\n\t\tfloat clearCoat;\n\t\tfloat clearCoatRoughness;\n\t#endif\n};\n#define MAXIMUM_SPECULAR_COEFFICIENT 0.16\n#define DEFAULT_SPECULAR_COEFFICIENT 0.04\nfloat clearCoatDHRApprox( const in float roughness, const in float dotNL ) {\n\treturn DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometry.normal;\n\t\tvec3 viewDir = geometry.viewDir;\n\t\tvec3 position = geometry.position;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.specularRoughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos - halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos + halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos + halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos - halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tfloat norm = texture2D( ltcMag, uv ).a;\n\t\tvec4 t = texture2D( ltcMat, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( 1, 0, t.y ),\n\t\t\tvec3( 0, t.z, 0 ),\n\t\t\tvec3( t.w, 0, t.x )\n\t\t);\n\t\treflectedLight.directSpecular += lightColor * material.specularColor * norm * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\t#ifndef STANDARD\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry, material.specularColor, material.specularRoughness );\n\treflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\t#ifndef STANDARD\n\t\treflectedLight.directSpecular += irradiance * material.clearCoat * BRDF_Specular_GGX( directLight, geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 clearCoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifndef STANDARD\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\tfloat dotNL = dotNV;\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.indirectSpecular += ( 1.0 - clearCoatDHR ) * radiance * BRDF_Specular_GGX_Environment( geometry, material.specularColor, material.specularRoughness );\n\t#ifndef STANDARD\n\t\treflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * BRDF_Specular_GGX_Environment( geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\n#define Material_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.specularRoughness )\n#define Material_ClearCoat_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.clearCoatRoughness )\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}\n";
var lights_template = "\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = normalize( vViewPosition );\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( pointLight.shadow, directLight.visible ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( directionalLight.shadow, directLight.visible ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#ifdef USE_LIGHTMAP\n\t\tvec3 lightMapIrradiance = texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tlightMapIrradiance *= PI;\n\t\t#endif\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t}\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tirradiance += getLightProbeIndirectIrradiance( geometry, 8 );\n\t#endif\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tvec3 radiance = getLightProbeIndirectRadiance( geometry, Material_BlinnShininessExponent( material ), 8 );\n\t#ifndef STANDARD\n\t\tvec3 clearCoatRadiance = getLightProbeIndirectRadiance( geometry, Material_ClearCoat_BlinnShininessExponent( material ), 8 );\n\t#else\n\t\tvec3 clearCoatRadiance = vec3( 0.0 );\n\t#endif\n\tRE_IndirectSpecular( radiance, clearCoatRadiance, geometry, material, reflectedLight );\n#endif\n";
var logdepthbuf_fragment = "#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)\n\tgl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;\n#endif";
var logdepthbuf_pars_fragment = "#ifdef USE_LOGDEPTHBUF\n\tuniform float logDepthBufFC;\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#endif\n#endif\n";
var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#endif\n\tuniform float logDepthBufFC;\n#endif";
var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\tgl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC;\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t#else\n\t\tgl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;\n\t#endif\n#endif\n";
var map_fragment = "#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif\n";
var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n";
var map_particle_fragment = "#ifdef USE_MAP\n\tvec4 mapTexel = texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\n#endif\n";
var map_particle_pars_fragment = "#ifdef USE_MAP\n\tuniform vec4 offsetRepeat;\n\tuniform sampler2D map;\n#endif\n";
var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif\n";
var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif";
var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\n\tobjectNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\n\tobjectNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\n\tobjectNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\n#endif\n";
var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\t#ifndef USE_MORPHNORMALS\n\tuniform float morphTargetInfluences[ 8 ];\n\t#else\n\tuniform float morphTargetInfluences[ 4 ];\n\t#endif\n#endif";
var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\n\ttransformed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\n\ttransformed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\n\ttransformed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n\t#ifndef USE_MORPHNORMALS\n\ttransformed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\n\ttransformed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\n\ttransformed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\n\ttransformed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n\t#endif\n#endif\n";
var normal_flip = "#ifdef DOUBLE_SIDED\n\tfloat flipNormal = ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n#else\n\tfloat flipNormal = 1.0;\n#endif\n";
var normal_fragment = "#ifdef FLAT_SHADED\n\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\n\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal ) * flipNormal;\n#endif\n#ifdef USE_NORMALMAP\n\tnormal = perturbNormal2Arb( -vViewPosition, normal );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif\n";
var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tvec3 S = normalize( q0 * st1.t - q1 * st0.t );\n\t\tvec3 T = normalize( -q0 * st1.s + q1 * st0.s );\n\t\tvec3 N = normalize( surf_norm );\n\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\tmapN.xy = normalScale * mapN.xy;\n\t\tmat3 tsn = mat3( S, T, N );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif\n";
var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 1.0 - 2.0 * rgb.xyz;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn (( near + viewZ ) * far ) / (( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}\n";
var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif\n";
var project_vertex = "#ifdef USE_SKINNING\n\tvec4 mvPosition = modelViewMatrix * skinned;\n#else\n\tvec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\n#endif\ngl_Position = projectionMatrix * mvPosition;\n";
var dithering_fragment = "#if defined( DITHERING )\n gl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif\n";
var dithering_pars_fragment = "#if defined( DITHERING )\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif\n";
var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif\n";
var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif";
var shadowmap_pars_fragment = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tfloat texture2DShadowLerp( sampler2D depths, vec2 size, vec2 uv, float compare ) {\n\t\tconst vec2 offset = vec2( 0.0, 1.0 );\n\t\tvec2 texelSize = vec2( 1.0 ) / size;\n\t\tvec2 centroidUV = floor( uv * size + 0.5 ) / size;\n\t\tfloat lb = texture2DCompare( depths, centroidUV + texelSize * offset.xx, compare );\n\t\tfloat lt = texture2DCompare( depths, centroidUV + texelSize * offset.xy, compare );\n\t\tfloat rb = texture2DCompare( depths, centroidUV + texelSize * offset.yx, compare );\n\t\tfloat rt = texture2DCompare( depths, centroidUV + texelSize * offset.yy, compare );\n\t\tvec2 f = fract( uv * size + 0.5 );\n\t\tfloat a = mix( lb, lt, f.y );\n\t\tfloat b = mix( rb, rt, f.y );\n\t\tfloat c = mix( a, b, f.x );\n\t\treturn c;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\treturn (\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn 1.0;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\tfloat dp = ( length( lightToPosition ) - shadowBias ) / 1000.0;\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif\n";
var shadowmap_pars_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n#endif\n";
var shadowmap_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n#endif\n";
var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\tDirectionalLight directionalLight;\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tshadow *= bool( directionalLight.shadow ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\tSpotLight spotLight;\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tshadow *= bool( spotLight.shadow ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\tPointLight pointLight;\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tshadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#endif\n\treturn shadow;\n}\n";
var skinbase_vertex = "#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif";
var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\t#ifdef BONE_TEXTURE\n\t\tuniform sampler2D boneTexture;\n\t\tuniform int boneTextureSize;\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tfloat j = i * 4.0;\n\t\t\tfloat x = mod( j, float( boneTextureSize ) );\n\t\t\tfloat y = floor( j / float( boneTextureSize ) );\n\t\t\tfloat dx = 1.0 / float( boneTextureSize );\n\t\t\tfloat dy = 1.0 / float( boneTextureSize );\n\t\t\ty = dy * ( y + 0.5 );\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\t\treturn bone;\n\t\t}\n\t#else\n\t\tuniform mat4 boneMatrices[ MAX_BONES ];\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tmat4 bone = boneMatrices[ int(i) ];\n\t\t\treturn bone;\n\t\t}\n\t#endif\n#endif\n";
var skinning_vertex = "#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\tskinned = bindMatrixInverse * skinned;\n#endif\n";
var skinnormal_vertex = "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n#endif\n";
var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif";
var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif";
var tonemapping_fragment = "#if defined( TONE_MAPPING )\n gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif\n";
var tonemapping_pars_fragment = "#define saturate(a) clamp( a, 0.0, 1.0 )\nuniform float toneMappingExposure;\nuniform float toneMappingWhitePoint;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\n#define Uncharted2Helper( x ) max( ( ( x * ( 0.15 * x + 0.10 * 0.50 ) + 0.20 * 0.02 ) / ( x * ( 0.15 * x + 0.50 ) + 0.20 * 0.30 ) ) - 0.02 / 0.30, vec3( 0.0 ) )\nvec3 Uncharted2ToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\n";
var uv_pars_fragment = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n#endif";
var uv_pars_vertex = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n\tuniform vec4 offsetRepeat;\n#endif\n";
var uv_vertex = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvUv = uv * offsetRepeat.zw + offsetRepeat.xy;\n#endif";
var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif";
var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n#endif";
var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = uv2;\n#endif";
var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( PHYSICAL ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )\n\t#ifdef USE_SKINNING\n\t\tvec4 worldPosition = modelMatrix * skinned;\n\t#else\n\t\tvec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\n\t#endif\n#endif\n";
var cube_frag = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldPosition;\n#include \nvoid main() {\n\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\n\tgl_FragColor.a *= opacity;\n}\n";
var cube_vert = "varying vec3 vWorldPosition;\n#include \nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}\n";
var depth_frag = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( gl_FragCoord.z ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( gl_FragCoord.z );\n\t#endif\n}\n";
var depth_vert = "#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n";
var distanceRGBA_frag = "uniform vec3 lightPos;\nvarying vec4 vWorldPosition;\n#include \n#include \n#include \nvoid main () {\n\t#include \n\tgl_FragColor = packDepthToRGBA( length( vWorldPosition.xyz - lightPos.xyz ) / 1000.0 );\n}\n";
var distanceRGBA_vert = "varying vec4 vWorldPosition;\n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition;\n}\n";
var equirect_frag = "uniform sampler2D tEquirect;\nuniform float tFlip;\nvarying vec3 vWorldPosition;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldPosition );\n\tvec2 sampleUV;\n\tsampleUV.y = saturate( tFlip * direction.y * -0.5 + 0.5 );\n\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n}\n";
var equirect_vert = "varying vec3 vWorldPosition;\n#include \nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}\n";
var linedashed_frag = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n";
var linedashed_vert = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvLineDistance = scale * lineDistance;\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}\n";
var meshbasic_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\treflectedLight.indirectDiffuse += texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n";
var meshbasic_vert = "#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#ifdef USE_ENVMAP\n\t#include \n\t#include \n\t#include \n\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n";
var meshlambert_frag = "uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\treflectedLight.indirectDiffuse = getAmbientLightIrradiance( ambientLightColor );\n\t#include \n\treflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\n\t#else\n\t\treflectedLight.directDiffuse = vLightFront;\n\t#endif\n\treflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();\n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n";
var meshlambert_vert = "#define LAMBERT\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n";
var meshphong_frag = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n";
var meshphong_vert = "#define PHONG\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include