|
/******/ (function(modules) { // webpackBootstrap |
|
/******/ // The module cache |
|
/******/ var installedModules = {}; |
|
/******/ |
|
/******/ // The require function |
|
/******/ function __webpack_require__(moduleId) { |
|
/******/ |
|
/******/ // Check if module is in cache |
|
/******/ if(installedModules[moduleId]) { |
|
/******/ return installedModules[moduleId].exports; |
|
/******/ } |
|
/******/ // Create a new module (and put it into the cache) |
|
/******/ var module = installedModules[moduleId] = { |
|
/******/ i: moduleId, |
|
/******/ l: false, |
|
/******/ exports: {} |
|
/******/ }; |
|
/******/ |
|
/******/ // Execute the module function |
|
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); |
|
/******/ |
|
/******/ // Flag the module as loaded |
|
/******/ module.l = true; |
|
/******/ |
|
/******/ // Return the exports of the module |
|
/******/ return module.exports; |
|
/******/ } |
|
/******/ |
|
/******/ |
|
/******/ // expose the modules object (__webpack_modules__) |
|
/******/ __webpack_require__.m = modules; |
|
/******/ |
|
/******/ // expose the module cache |
|
/******/ __webpack_require__.c = installedModules; |
|
/******/ |
|
/******/ // identity function for calling harmony imports with the correct context |
|
/******/ __webpack_require__.i = function(value) { return value; }; |
|
/******/ |
|
/******/ // define getter function for harmony exports |
|
/******/ __webpack_require__.d = function(exports, name, getter) { |
|
/******/ if(!__webpack_require__.o(exports, name)) { |
|
/******/ Object.defineProperty(exports, name, { |
|
/******/ configurable: false, |
|
/******/ enumerable: true, |
|
/******/ get: getter |
|
/******/ }); |
|
/******/ } |
|
/******/ }; |
|
/******/ |
|
/******/ // getDefaultExport function for compatibility with non-harmony modules |
|
/******/ __webpack_require__.n = function(module) { |
|
/******/ var getter = module && module.__esModule ? |
|
/******/ function getDefault() { return module['default']; } : |
|
/******/ function getModuleExports() { return module; }; |
|
/******/ __webpack_require__.d(getter, 'a', getter); |
|
/******/ return getter; |
|
/******/ }; |
|
/******/ |
|
/******/ // Object.prototype.hasOwnProperty.call |
|
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; |
|
/******/ |
|
/******/ // __webpack_public_path__ |
|
/******/ __webpack_require__.p = ""; |
|
/******/ |
|
/******/ // Load entry module and return exports |
|
/******/ return __webpack_require__(__webpack_require__.s = 48); |
|
/******/ }) |
|
/************************************************************************/ |
|
/******/ ([ |
|
/* 0 */ |
|
/***/ (function(module, __webpack_exports__, __webpack_require__) { |
|
|
|
"use strict"; |
|
Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); |
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ARRAY_TYPE", function() { return ARRAY_TYPE; }); |
|
/* harmony export (immutable) */ __webpack_exports__["setMatrixArrayType"] = setMatrixArrayType; |
|
/* harmony export (immutable) */ __webpack_exports__["toRadian"] = toRadian; |
|
/* harmony export (immutable) */ __webpack_exports__["equals"] = equals; |
|
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. |
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
|
of this software and associated documentation files (the "Software"), to deal |
|
in the Software without restriction, including without limitation the rights |
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
copies of the Software, and to permit persons to whom the Software is |
|
furnished to do so, subject to the following conditions: |
|
|
|
The above copyright notice and this permission notice shall be included in |
|
all copies or substantial portions of the Software. |
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
THE SOFTWARE. */ |
|
|
|
/** |
|
* Common utilities |
|
* @module glMatrix |
|
*/ |
|
|
|
// Configuration Constants |
|
const EPSILON = 0.000001; |
|
/* harmony export (immutable) */ __webpack_exports__["EPSILON"] = EPSILON; |
|
|
|
let ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array; |
|
const RANDOM = Math.random; |
|
/* harmony export (immutable) */ __webpack_exports__["RANDOM"] = RANDOM; |
|
|
|
|
|
/** |
|
* Sets the type of array used when creating new vectors and matrices |
|
* |
|
* @param {Type} type Array type, such as Float32Array or Array |
|
*/ |
|
function setMatrixArrayType(type) { |
|
ARRAY_TYPE = type; |
|
} |
|
|
|
const degree = Math.PI / 180; |
|
|
|
/** |
|
* Convert Degree To Radian |
|
* |
|
* @param {Number} a Angle in Degrees |
|
*/ |
|
function toRadian(a) { |
|
return a * degree; |
|
} |
|
|
|
/** |
|
* Tests whether or not the arguments have approximately the same value, within an absolute |
|
* or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less |
|
* than or equal to 1.0, and a relative tolerance is used for larger values) |
|
* |
|
* @param {Number} a The first number to test. |
|
* @param {Number} b The second number to test. |
|
* @returns {Boolean} True if the numbers are approximately equal, false otherwise. |
|
*/ |
|
function equals(a, b) { |
|
return Math.abs(a - b) <= EPSILON*Math.max(1.0, Math.abs(a), Math.abs(b)); |
|
} |
|
|
|
|
|
/***/ }), |
|
/* 1 */ |
|
/***/ (function(module, exports) { |
|
|
|
// Copyright Joyent, Inc. and other Node contributors. |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a |
|
// copy of this software and associated documentation files (the |
|
// "Software"), to deal in the Software without restriction, including |
|
// without limitation the rights to use, copy, modify, merge, publish, |
|
// distribute, sublicense, and/or sell copies of the Software, and to permit |
|
// persons to whom the Software is furnished to do so, subject to the |
|
// following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be included |
|
// in all copies or substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
|
// USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
|
|
function EventEmitter() { |
|
this._events = this._events || {}; |
|
this._maxListeners = this._maxListeners || undefined; |
|
} |
|
module.exports = EventEmitter; |
|
|
|
// Backwards-compat with node 0.10.x |
|
EventEmitter.EventEmitter = EventEmitter; |
|
|
|
EventEmitter.prototype._events = undefined; |
|
EventEmitter.prototype._maxListeners = undefined; |
|
|
|
// By default EventEmitters will print a warning if more than 10 listeners are |
|
// added to it. This is a useful default which helps finding memory leaks. |
|
EventEmitter.defaultMaxListeners = 10; |
|
|
|
// Obviously not all Emitters should be limited to 10. This function allows |
|
// that to be increased. Set to zero for unlimited. |
|
EventEmitter.prototype.setMaxListeners = function(n) { |
|
if (!isNumber(n) || n < 0 || isNaN(n)) |
|
throw TypeError('n must be a positive number'); |
|
this._maxListeners = n; |
|
return this; |
|
}; |
|
|
|
EventEmitter.prototype.emit = function(type) { |
|
var er, handler, len, args, i, listeners; |
|
|
|
if (!this._events) |
|
this._events = {}; |
|
|
|
// If there is no 'error' event listener then throw. |
|
if (type === 'error') { |
|
if (!this._events.error || |
|
(isObject(this._events.error) && !this._events.error.length)) { |
|
er = arguments[1]; |
|
if (er instanceof Error) { |
|
throw er; // Unhandled 'error' event |
|
} else { |
|
// At least give some kind of context to the user |
|
var err = new Error('Uncaught, unspecified "error" event. (' + er + ')'); |
|
err.context = er; |
|
throw err; |
|
} |
|
} |
|
} |
|
|
|
handler = this._events[type]; |
|
|
|
if (isUndefined(handler)) |
|
return false; |
|
|
|
if (isFunction(handler)) { |
|
switch (arguments.length) { |
|
// fast cases |
|
case 1: |
|
handler.call(this); |
|
break; |
|
case 2: |
|
handler.call(this, arguments[1]); |
|
break; |
|
case 3: |
|
handler.call(this, arguments[1], arguments[2]); |
|
break; |
|
// slower |
|
default: |
|
args = Array.prototype.slice.call(arguments, 1); |
|
handler.apply(this, args); |
|
} |
|
} else if (isObject(handler)) { |
|
args = Array.prototype.slice.call(arguments, 1); |
|
listeners = handler.slice(); |
|
len = listeners.length; |
|
for (i = 0; i < len; i++) |
|
listeners[i].apply(this, args); |
|
} |
|
|
|
return true; |
|
}; |
|
|
|
EventEmitter.prototype.addListener = function(type, listener) { |
|
var m; |
|
|
|
if (!isFunction(listener)) |
|
throw TypeError('listener must be a function'); |
|
|
|
if (!this._events) |
|
this._events = {}; |
|
|
|
// To avoid recursion in the case that type === "newListener"! Before |
|
// adding it to the listeners, first emit "newListener". |
|
if (this._events.newListener) |
|
this.emit('newListener', type, |
|
isFunction(listener.listener) ? |
|
listener.listener : listener); |
|
|
|
if (!this._events[type]) |
|
// Optimize the case of one listener. Don't need the extra array object. |
|
this._events[type] = listener; |
|
else if (isObject(this._events[type])) |
|
// If we've already got an array, just append. |
|
this._events[type].push(listener); |
|
else |
|
// Adding the second element, need to change to array. |
|
this._events[type] = [this._events[type], listener]; |
|
|
|
// Check for listener leak |
|
if (isObject(this._events[type]) && !this._events[type].warned) { |
|
if (!isUndefined(this._maxListeners)) { |
|
m = this._maxListeners; |
|
} else { |
|
m = EventEmitter.defaultMaxListeners; |
|
} |
|
|
|
if (m && m > 0 && this._events[type].length > m) { |
|
this._events[type].warned = true; |
|
console.error('(node) warning: possible EventEmitter memory ' + |
|
'leak detected. %d listeners added. ' + |
|
'Use emitter.setMaxListeners() to increase limit.', |
|
this._events[type].length); |
|
if (typeof console.trace === 'function') { |
|
// not supported in IE 10 |
|
console.trace(); |
|
} |
|
} |
|
} |
|
|
|
return this; |
|
}; |
|
|
|
EventEmitter.prototype.on = EventEmitter.prototype.addListener; |
|
|
|
EventEmitter.prototype.once = function(type, listener) { |
|
if (!isFunction(listener)) |
|
throw TypeError('listener must be a function'); |
|
|
|
var fired = false; |
|
|
|
function g() { |
|
this.removeListener(type, g); |
|
|
|
if (!fired) { |
|
fired = true; |
|
listener.apply(this, arguments); |
|
} |
|
} |
|
|
|
g.listener = listener; |
|
this.on(type, g); |
|
|
|
return this; |
|
}; |
|
|
|
// emits a 'removeListener' event iff the listener was removed |
|
EventEmitter.prototype.removeListener = function(type, listener) { |
|
var list, position, length, i; |
|
|
|
if (!isFunction(listener)) |
|
throw TypeError('listener must be a function'); |
|
|
|
if (!this._events || !this._events[type]) |
|
return this; |
|
|
|
list = this._events[type]; |
|
length = list.length; |
|
position = -1; |
|
|
|
if (list === listener || |
|
(isFunction(list.listener) && list.listener === listener)) { |
|
delete this._events[type]; |
|
if (this._events.removeListener) |
|
this.emit('removeListener', type, listener); |
|
|
|
} else if (isObject(list)) { |
|
for (i = length; i-- > 0;) { |
|
if (list[i] === listener || |
|
(list[i].listener && list[i].listener === listener)) { |
|
position = i; |
|
break; |
|
} |
|
} |
|
|
|
if (position < 0) |
|
return this; |
|
|
|
if (list.length === 1) { |
|
list.length = 0; |
|
delete this._events[type]; |
|
} else { |
|
list.splice(position, 1); |
|
} |
|
|
|
if (this._events.removeListener) |
|
this.emit('removeListener', type, listener); |
|
} |
|
|
|
return this; |
|
}; |
|
|
|
EventEmitter.prototype.removeAllListeners = function(type) { |
|
var key, listeners; |
|
|
|
if (!this._events) |
|
return this; |
|
|
|
// not listening for removeListener, no need to emit |
|
if (!this._events.removeListener) { |
|
if (arguments.length === 0) |
|
this._events = {}; |
|
else if (this._events[type]) |
|
delete this._events[type]; |
|
return this; |
|
} |
|
|
|
// emit removeListener for all listeners on all events |
|
if (arguments.length === 0) { |
|
for (key in this._events) { |
|
if (key === 'removeListener') continue; |
|
this.removeAllListeners(key); |
|
} |
|
this.removeAllListeners('removeListener'); |
|
this._events = {}; |
|
return this; |
|
} |
|
|
|
listeners = this._events[type]; |
|
|
|
if (isFunction(listeners)) { |
|
this.removeListener(type, listeners); |
|
} else if (listeners) { |
|
// LIFO order |
|
while (listeners.length) |
|
this.removeListener(type, listeners[listeners.length - 1]); |
|
} |
|
delete this._events[type]; |
|
|
|
return this; |
|
}; |
|
|
|
EventEmitter.prototype.listeners = function(type) { |
|
var ret; |
|
if (!this._events || !this._events[type]) |
|
ret = []; |
|
else if (isFunction(this._events[type])) |
|
ret = [this._events[type]]; |
|
else |
|
ret = this._events[type].slice(); |
|
return ret; |
|
}; |
|
|
|
EventEmitter.prototype.listenerCount = function(type) { |
|
if (this._events) { |
|
var evlistener = this._events[type]; |
|
|
|
if (isFunction(evlistener)) |
|
return 1; |
|
else if (evlistener) |
|
return evlistener.length; |
|
} |
|
return 0; |
|
}; |
|
|
|
EventEmitter.listenerCount = function(emitter, type) { |
|
return emitter.listenerCount(type); |
|
}; |
|
|
|
function isFunction(arg) { |
|
return typeof arg === 'function'; |
|
} |
|
|
|
function isNumber(arg) { |
|
return typeof arg === 'number'; |
|
} |
|
|
|
function isObject(arg) { |
|
return typeof arg === 'object' && arg !== null; |
|
} |
|
|
|
function isUndefined(arg) { |
|
return arg === void 0; |
|
} |
|
|
|
|
|
/***/ }), |
|
/* 2 */ |
|
/***/ (function(module, __webpack_exports__, __webpack_require__) { |
|
|
|
"use strict"; |
|
Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); |
|
/* harmony export (immutable) */ __webpack_exports__["create"] = create; |
|
/* harmony export (immutable) */ __webpack_exports__["fromMat4"] = fromMat4; |
|
/* harmony export (immutable) */ __webpack_exports__["clone"] = clone; |
|
/* harmony export (immutable) */ __webpack_exports__["copy"] = copy; |
|
/* harmony export (immutable) */ __webpack_exports__["fromValues"] = fromValues; |
|
/* harmony export (immutable) */ __webpack_exports__["set"] = set; |
|
/* harmony export (immutable) */ __webpack_exports__["identity"] = identity; |
|
/* harmony export (immutable) */ __webpack_exports__["transpose"] = transpose; |
|
/* harmony export (immutable) */ __webpack_exports__["invert"] = invert; |
|
/* harmony export (immutable) */ __webpack_exports__["adjoint"] = adjoint; |
|
/* harmony export (immutable) */ __webpack_exports__["determinant"] = determinant; |
|
/* harmony export (immutable) */ __webpack_exports__["multiply"] = multiply; |
|
/* harmony export (immutable) */ __webpack_exports__["translate"] = translate; |
|
/* harmony export (immutable) */ __webpack_exports__["rotate"] = rotate; |
|
/* harmony export (immutable) */ __webpack_exports__["scale"] = scale; |
|
/* harmony export (immutable) */ __webpack_exports__["fromTranslation"] = fromTranslation; |
|
/* harmony export (immutable) */ __webpack_exports__["fromRotation"] = fromRotation; |
|
/* harmony export (immutable) */ __webpack_exports__["fromScaling"] = fromScaling; |
|
/* harmony export (immutable) */ __webpack_exports__["fromMat2d"] = fromMat2d; |
|
/* harmony export (immutable) */ __webpack_exports__["fromQuat"] = fromQuat; |
|
/* harmony export (immutable) */ __webpack_exports__["normalFromMat4"] = normalFromMat4; |
|
/* harmony export (immutable) */ __webpack_exports__["projection"] = projection; |
|
/* harmony export (immutable) */ __webpack_exports__["str"] = str; |
|
/* harmony export (immutable) */ __webpack_exports__["frob"] = frob; |
|
/* harmony export (immutable) */ __webpack_exports__["add"] = add; |
|
/* harmony export (immutable) */ __webpack_exports__["subtract"] = subtract; |
|
/* harmony export (immutable) */ __webpack_exports__["multiplyScalar"] = multiplyScalar; |
|
/* harmony export (immutable) */ __webpack_exports__["multiplyScalarAndAdd"] = multiplyScalarAndAdd; |
|
/* harmony export (immutable) */ __webpack_exports__["exactEquals"] = exactEquals; |
|
/* harmony export (immutable) */ __webpack_exports__["equals"] = equals; |
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__common__ = __webpack_require__(0); |
|
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. |
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
|
of this software and associated documentation files (the "Software"), to deal |
|
in the Software without restriction, including without limitation the rights |
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
copies of the Software, and to permit persons to whom the Software is |
|
furnished to do so, subject to the following conditions: |
|
|
|
The above copyright notice and this permission notice shall be included in |
|
all copies or substantial portions of the Software. |
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
THE SOFTWARE. */ |
|
|
|
|
|
|
|
/** |
|
* 3x3 Matrix |
|
* @module mat3 |
|
*/ |
|
|
|
/** |
|
* Creates a new identity mat3 |
|
* |
|
* @returns {mat3} a new 3x3 matrix |
|
*/ |
|
function create() { |
|
let out = new __WEBPACK_IMPORTED_MODULE_0__common__["ARRAY_TYPE"](9); |
|
out[0] = 1; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 0; |
|
out[4] = 1; |
|
out[5] = 0; |
|
out[6] = 0; |
|
out[7] = 0; |
|
out[8] = 1; |
|
return out; |
|
} |
|
|
|
/** |
|
* Copies the upper-left 3x3 values into the given mat3. |
|
* |
|
* @param {mat3} out the receiving 3x3 matrix |
|
* @param {mat4} a the source 4x4 matrix |
|
* @returns {mat3} out |
|
*/ |
|
function fromMat4(out, a) { |
|
out[0] = a[0]; |
|
out[1] = a[1]; |
|
out[2] = a[2]; |
|
out[3] = a[4]; |
|
out[4] = a[5]; |
|
out[5] = a[6]; |
|
out[6] = a[8]; |
|
out[7] = a[9]; |
|
out[8] = a[10]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a new mat3 initialized with values from an existing matrix |
|
* |
|
* @param {mat3} a matrix to clone |
|
* @returns {mat3} a new 3x3 matrix |
|
*/ |
|
function clone(a) { |
|
let out = new __WEBPACK_IMPORTED_MODULE_0__common__["ARRAY_TYPE"](9); |
|
out[0] = a[0]; |
|
out[1] = a[1]; |
|
out[2] = a[2]; |
|
out[3] = a[3]; |
|
out[4] = a[4]; |
|
out[5] = a[5]; |
|
out[6] = a[6]; |
|
out[7] = a[7]; |
|
out[8] = a[8]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Copy the values from one mat3 to another |
|
* |
|
* @param {mat3} out the receiving matrix |
|
* @param {mat3} a the source matrix |
|
* @returns {mat3} out |
|
*/ |
|
function copy(out, a) { |
|
out[0] = a[0]; |
|
out[1] = a[1]; |
|
out[2] = a[2]; |
|
out[3] = a[3]; |
|
out[4] = a[4]; |
|
out[5] = a[5]; |
|
out[6] = a[6]; |
|
out[7] = a[7]; |
|
out[8] = a[8]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Create a new mat3 with the given values |
|
* |
|
* @param {Number} m00 Component in column 0, row 0 position (index 0) |
|
* @param {Number} m01 Component in column 0, row 1 position (index 1) |
|
* @param {Number} m02 Component in column 0, row 2 position (index 2) |
|
* @param {Number} m10 Component in column 1, row 0 position (index 3) |
|
* @param {Number} m11 Component in column 1, row 1 position (index 4) |
|
* @param {Number} m12 Component in column 1, row 2 position (index 5) |
|
* @param {Number} m20 Component in column 2, row 0 position (index 6) |
|
* @param {Number} m21 Component in column 2, row 1 position (index 7) |
|
* @param {Number} m22 Component in column 2, row 2 position (index 8) |
|
* @returns {mat3} A new mat3 |
|
*/ |
|
function fromValues(m00, m01, m02, m10, m11, m12, m20, m21, m22) { |
|
let out = new __WEBPACK_IMPORTED_MODULE_0__common__["ARRAY_TYPE"](9); |
|
out[0] = m00; |
|
out[1] = m01; |
|
out[2] = m02; |
|
out[3] = m10; |
|
out[4] = m11; |
|
out[5] = m12; |
|
out[6] = m20; |
|
out[7] = m21; |
|
out[8] = m22; |
|
return out; |
|
} |
|
|
|
/** |
|
* Set the components of a mat3 to the given values |
|
* |
|
* @param {mat3} out the receiving matrix |
|
* @param {Number} m00 Component in column 0, row 0 position (index 0) |
|
* @param {Number} m01 Component in column 0, row 1 position (index 1) |
|
* @param {Number} m02 Component in column 0, row 2 position (index 2) |
|
* @param {Number} m10 Component in column 1, row 0 position (index 3) |
|
* @param {Number} m11 Component in column 1, row 1 position (index 4) |
|
* @param {Number} m12 Component in column 1, row 2 position (index 5) |
|
* @param {Number} m20 Component in column 2, row 0 position (index 6) |
|
* @param {Number} m21 Component in column 2, row 1 position (index 7) |
|
* @param {Number} m22 Component in column 2, row 2 position (index 8) |
|
* @returns {mat3} out |
|
*/ |
|
function set(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) { |
|
out[0] = m00; |
|
out[1] = m01; |
|
out[2] = m02; |
|
out[3] = m10; |
|
out[4] = m11; |
|
out[5] = m12; |
|
out[6] = m20; |
|
out[7] = m21; |
|
out[8] = m22; |
|
return out; |
|
} |
|
|
|
/** |
|
* Set a mat3 to the identity matrix |
|
* |
|
* @param {mat3} out the receiving matrix |
|
* @returns {mat3} out |
|
*/ |
|
function identity(out) { |
|
out[0] = 1; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 0; |
|
out[4] = 1; |
|
out[5] = 0; |
|
out[6] = 0; |
|
out[7] = 0; |
|
out[8] = 1; |
|
return out; |
|
} |
|
|
|
/** |
|
* Transpose the values of a mat3 |
|
* |
|
* @param {mat3} out the receiving matrix |
|
* @param {mat3} a the source matrix |
|
* @returns {mat3} out |
|
*/ |
|
function transpose(out, a) { |
|
// If we are transposing ourselves we can skip a few steps but have to cache some values |
|
if (out === a) { |
|
let a01 = a[1], a02 = a[2], a12 = a[5]; |
|
out[1] = a[3]; |
|
out[2] = a[6]; |
|
out[3] = a01; |
|
out[5] = a[7]; |
|
out[6] = a02; |
|
out[7] = a12; |
|
} else { |
|
out[0] = a[0]; |
|
out[1] = a[3]; |
|
out[2] = a[6]; |
|
out[3] = a[1]; |
|
out[4] = a[4]; |
|
out[5] = a[7]; |
|
out[6] = a[2]; |
|
out[7] = a[5]; |
|
out[8] = a[8]; |
|
} |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Inverts a mat3 |
|
* |
|
* @param {mat3} out the receiving matrix |
|
* @param {mat3} a the source matrix |
|
* @returns {mat3} out |
|
*/ |
|
function invert(out, a) { |
|
let a00 = a[0], a01 = a[1], a02 = a[2]; |
|
let a10 = a[3], a11 = a[4], a12 = a[5]; |
|
let a20 = a[6], a21 = a[7], a22 = a[8]; |
|
|
|
let b01 = a22 * a11 - a12 * a21; |
|
let b11 = -a22 * a10 + a12 * a20; |
|
let b21 = a21 * a10 - a11 * a20; |
|
|
|
// Calculate the determinant |
|
let det = a00 * b01 + a01 * b11 + a02 * b21; |
|
|
|
if (!det) { |
|
return null; |
|
} |
|
det = 1.0 / det; |
|
|
|
out[0] = b01 * det; |
|
out[1] = (-a22 * a01 + a02 * a21) * det; |
|
out[2] = (a12 * a01 - a02 * a11) * det; |
|
out[3] = b11 * det; |
|
out[4] = (a22 * a00 - a02 * a20) * det; |
|
out[5] = (-a12 * a00 + a02 * a10) * det; |
|
out[6] = b21 * det; |
|
out[7] = (-a21 * a00 + a01 * a20) * det; |
|
out[8] = (a11 * a00 - a01 * a10) * det; |
|
return out; |
|
} |
|
|
|
/** |
|
* Calculates the adjugate of a mat3 |
|
* |
|
* @param {mat3} out the receiving matrix |
|
* @param {mat3} a the source matrix |
|
* @returns {mat3} out |
|
*/ |
|
function adjoint(out, a) { |
|
let a00 = a[0], a01 = a[1], a02 = a[2]; |
|
let a10 = a[3], a11 = a[4], a12 = a[5]; |
|
let a20 = a[6], a21 = a[7], a22 = a[8]; |
|
|
|
out[0] = (a11 * a22 - a12 * a21); |
|
out[1] = (a02 * a21 - a01 * a22); |
|
out[2] = (a01 * a12 - a02 * a11); |
|
out[3] = (a12 * a20 - a10 * a22); |
|
out[4] = (a00 * a22 - a02 * a20); |
|
out[5] = (a02 * a10 - a00 * a12); |
|
out[6] = (a10 * a21 - a11 * a20); |
|
out[7] = (a01 * a20 - a00 * a21); |
|
out[8] = (a00 * a11 - a01 * a10); |
|
return out; |
|
} |
|
|
|
/** |
|
* Calculates the determinant of a mat3 |
|
* |
|
* @param {mat3} a the source matrix |
|
* @returns {Number} determinant of a |
|
*/ |
|
function determinant(a) { |
|
let a00 = a[0], a01 = a[1], a02 = a[2]; |
|
let a10 = a[3], a11 = a[4], a12 = a[5]; |
|
let a20 = a[6], a21 = a[7], a22 = a[8]; |
|
|
|
return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20); |
|
} |
|
|
|
/** |
|
* Multiplies two mat3's |
|
* |
|
* @param {mat3} out the receiving matrix |
|
* @param {mat3} a the first operand |
|
* @param {mat3} b the second operand |
|
* @returns {mat3} out |
|
*/ |
|
function multiply(out, a, b) { |
|
let a00 = a[0], a01 = a[1], a02 = a[2]; |
|
let a10 = a[3], a11 = a[4], a12 = a[5]; |
|
let a20 = a[6], a21 = a[7], a22 = a[8]; |
|
|
|
let b00 = b[0], b01 = b[1], b02 = b[2]; |
|
let b10 = b[3], b11 = b[4], b12 = b[5]; |
|
let b20 = b[6], b21 = b[7], b22 = b[8]; |
|
|
|
out[0] = b00 * a00 + b01 * a10 + b02 * a20; |
|
out[1] = b00 * a01 + b01 * a11 + b02 * a21; |
|
out[2] = b00 * a02 + b01 * a12 + b02 * a22; |
|
|
|
out[3] = b10 * a00 + b11 * a10 + b12 * a20; |
|
out[4] = b10 * a01 + b11 * a11 + b12 * a21; |
|
out[5] = b10 * a02 + b11 * a12 + b12 * a22; |
|
|
|
out[6] = b20 * a00 + b21 * a10 + b22 * a20; |
|
out[7] = b20 * a01 + b21 * a11 + b22 * a21; |
|
out[8] = b20 * a02 + b21 * a12 + b22 * a22; |
|
return out; |
|
} |
|
|
|
/** |
|
* Translate a mat3 by the given vector |
|
* |
|
* @param {mat3} out the receiving matrix |
|
* @param {mat3} a the matrix to translate |
|
* @param {vec2} v vector to translate by |
|
* @returns {mat3} out |
|
*/ |
|
function translate(out, a, v) { |
|
let a00 = a[0], a01 = a[1], a02 = a[2], |
|
a10 = a[3], a11 = a[4], a12 = a[5], |
|
a20 = a[6], a21 = a[7], a22 = a[8], |
|
x = v[0], y = v[1]; |
|
|
|
out[0] = a00; |
|
out[1] = a01; |
|
out[2] = a02; |
|
|
|
out[3] = a10; |
|
out[4] = a11; |
|
out[5] = a12; |
|
|
|
out[6] = x * a00 + y * a10 + a20; |
|
out[7] = x * a01 + y * a11 + a21; |
|
out[8] = x * a02 + y * a12 + a22; |
|
return out; |
|
} |
|
|
|
/** |
|
* Rotates a mat3 by the given angle |
|
* |
|
* @param {mat3} out the receiving matrix |
|
* @param {mat3} a the matrix to rotate |
|
* @param {Number} rad the angle to rotate the matrix by |
|
* @returns {mat3} out |
|
*/ |
|
function rotate(out, a, rad) { |
|
let a00 = a[0], a01 = a[1], a02 = a[2], |
|
a10 = a[3], a11 = a[4], a12 = a[5], |
|
a20 = a[6], a21 = a[7], a22 = a[8], |
|
|
|
s = Math.sin(rad), |
|
c = Math.cos(rad); |
|
|
|
out[0] = c * a00 + s * a10; |
|
out[1] = c * a01 + s * a11; |
|
out[2] = c * a02 + s * a12; |
|
|
|
out[3] = c * a10 - s * a00; |
|
out[4] = c * a11 - s * a01; |
|
out[5] = c * a12 - s * a02; |
|
|
|
out[6] = a20; |
|
out[7] = a21; |
|
out[8] = a22; |
|
return out; |
|
}; |
|
|
|
/** |
|
* Scales the mat3 by the dimensions in the given vec2 |
|
* |
|
* @param {mat3} out the receiving matrix |
|
* @param {mat3} a the matrix to rotate |
|
* @param {vec2} v the vec2 to scale the matrix by |
|
* @returns {mat3} out |
|
**/ |
|
function scale(out, a, v) { |
|
let x = v[0], y = v[1]; |
|
|
|
out[0] = x * a[0]; |
|
out[1] = x * a[1]; |
|
out[2] = x * a[2]; |
|
|
|
out[3] = y * a[3]; |
|
out[4] = y * a[4]; |
|
out[5] = y * a[5]; |
|
|
|
out[6] = a[6]; |
|
out[7] = a[7]; |
|
out[8] = a[8]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a matrix from a vector translation |
|
* This is equivalent to (but much faster than): |
|
* |
|
* mat3.identity(dest); |
|
* mat3.translate(dest, dest, vec); |
|
* |
|
* @param {mat3} out mat3 receiving operation result |
|
* @param {vec2} v Translation vector |
|
* @returns {mat3} out |
|
*/ |
|
function fromTranslation(out, v) { |
|
out[0] = 1; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 0; |
|
out[4] = 1; |
|
out[5] = 0; |
|
out[6] = v[0]; |
|
out[7] = v[1]; |
|
out[8] = 1; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a matrix from a given angle |
|
* This is equivalent to (but much faster than): |
|
* |
|
* mat3.identity(dest); |
|
* mat3.rotate(dest, dest, rad); |
|
* |
|
* @param {mat3} out mat3 receiving operation result |
|
* @param {Number} rad the angle to rotate the matrix by |
|
* @returns {mat3} out |
|
*/ |
|
function fromRotation(out, rad) { |
|
let s = Math.sin(rad), c = Math.cos(rad); |
|
|
|
out[0] = c; |
|
out[1] = s; |
|
out[2] = 0; |
|
|
|
out[3] = -s; |
|
out[4] = c; |
|
out[5] = 0; |
|
|
|
out[6] = 0; |
|
out[7] = 0; |
|
out[8] = 1; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a matrix from a vector scaling |
|
* This is equivalent to (but much faster than): |
|
* |
|
* mat3.identity(dest); |
|
* mat3.scale(dest, dest, vec); |
|
* |
|
* @param {mat3} out mat3 receiving operation result |
|
* @param {vec2} v Scaling vector |
|
* @returns {mat3} out |
|
*/ |
|
function fromScaling(out, v) { |
|
out[0] = v[0]; |
|
out[1] = 0; |
|
out[2] = 0; |
|
|
|
out[3] = 0; |
|
out[4] = v[1]; |
|
out[5] = 0; |
|
|
|
out[6] = 0; |
|
out[7] = 0; |
|
out[8] = 1; |
|
return out; |
|
} |
|
|
|
/** |
|
* Copies the values from a mat2d into a mat3 |
|
* |
|
* @param {mat3} out the receiving matrix |
|
* @param {mat2d} a the matrix to copy |
|
* @returns {mat3} out |
|
**/ |
|
function fromMat2d(out, a) { |
|
out[0] = a[0]; |
|
out[1] = a[1]; |
|
out[2] = 0; |
|
|
|
out[3] = a[2]; |
|
out[4] = a[3]; |
|
out[5] = 0; |
|
|
|
out[6] = a[4]; |
|
out[7] = a[5]; |
|
out[8] = 1; |
|
return out; |
|
} |
|
|
|
/** |
|
* Calculates a 3x3 matrix from the given quaternion |
|
* |
|
* @param {mat3} out mat3 receiving operation result |
|
* @param {quat} q Quaternion to create matrix from |
|
* |
|
* @returns {mat3} out |
|
*/ |
|
function fromQuat(out, q) { |
|
let x = q[0], y = q[1], z = q[2], w = q[3]; |
|
let x2 = x + x; |
|
let y2 = y + y; |
|
let z2 = z + z; |
|
|
|
let xx = x * x2; |
|
let yx = y * x2; |
|
let yy = y * y2; |
|
let zx = z * x2; |
|
let zy = z * y2; |
|
let zz = z * z2; |
|
let wx = w * x2; |
|
let wy = w * y2; |
|
let wz = w * z2; |
|
|
|
out[0] = 1 - yy - zz; |
|
out[3] = yx - wz; |
|
out[6] = zx + wy; |
|
|
|
out[1] = yx + wz; |
|
out[4] = 1 - xx - zz; |
|
out[7] = zy - wx; |
|
|
|
out[2] = zx - wy; |
|
out[5] = zy + wx; |
|
out[8] = 1 - xx - yy; |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix |
|
* |
|
* @param {mat3} out mat3 receiving operation result |
|
* @param {mat4} a Mat4 to derive the normal matrix from |
|
* |
|
* @returns {mat3} out |
|
*/ |
|
function normalFromMat4(out, a) { |
|
let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; |
|
let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; |
|
let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; |
|
let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; |
|
|
|
let b00 = a00 * a11 - a01 * a10; |
|
let b01 = a00 * a12 - a02 * a10; |
|
let b02 = a00 * a13 - a03 * a10; |
|
let b03 = a01 * a12 - a02 * a11; |
|
let b04 = a01 * a13 - a03 * a11; |
|
let b05 = a02 * a13 - a03 * a12; |
|
let b06 = a20 * a31 - a21 * a30; |
|
let b07 = a20 * a32 - a22 * a30; |
|
let b08 = a20 * a33 - a23 * a30; |
|
let b09 = a21 * a32 - a22 * a31; |
|
let b10 = a21 * a33 - a23 * a31; |
|
let b11 = a22 * a33 - a23 * a32; |
|
|
|
// Calculate the determinant |
|
let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; |
|
|
|
if (!det) { |
|
return null; |
|
} |
|
det = 1.0 / det; |
|
|
|
out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; |
|
out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det; |
|
out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det; |
|
|
|
out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det; |
|
out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det; |
|
out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det; |
|
|
|
out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det; |
|
out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det; |
|
out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det; |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Generates a 2D projection matrix with the given bounds |
|
* |
|
* @param {mat3} out mat3 frustum matrix will be written into |
|
* @param {number} width Width of your gl context |
|
* @param {number} height Height of gl context |
|
* @returns {mat3} out |
|
*/ |
|
function projection(out, width, height) { |
|
out[0] = 2 / width; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 0; |
|
out[4] = -2 / height; |
|
out[5] = 0; |
|
out[6] = -1; |
|
out[7] = 1; |
|
out[8] = 1; |
|
return out; |
|
} |
|
|
|
/** |
|
* Returns a string representation of a mat3 |
|
* |
|
* @param {mat3} a matrix to represent as a string |
|
* @returns {String} string representation of the matrix |
|
*/ |
|
function str(a) { |
|
return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + |
|
a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + |
|
a[6] + ', ' + a[7] + ', ' + a[8] + ')'; |
|
} |
|
|
|
/** |
|
* Returns Frobenius norm of a mat3 |
|
* |
|
* @param {mat3} a the matrix to calculate Frobenius norm of |
|
* @returns {Number} Frobenius norm |
|
*/ |
|
function frob(a) { |
|
return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2))) |
|
} |
|
|
|
/** |
|
* Adds two mat3's |
|
* |
|
* @param {mat3} out the receiving matrix |
|
* @param {mat3} a the first operand |
|
* @param {mat3} b the second operand |
|
* @returns {mat3} out |
|
*/ |
|
function add(out, a, b) { |
|
out[0] = a[0] + b[0]; |
|
out[1] = a[1] + b[1]; |
|
out[2] = a[2] + b[2]; |
|
out[3] = a[3] + b[3]; |
|
out[4] = a[4] + b[4]; |
|
out[5] = a[5] + b[5]; |
|
out[6] = a[6] + b[6]; |
|
out[7] = a[7] + b[7]; |
|
out[8] = a[8] + b[8]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Subtracts matrix b from matrix a |
|
* |
|
* @param {mat3} out the receiving matrix |
|
* @param {mat3} a the first operand |
|
* @param {mat3} b the second operand |
|
* @returns {mat3} out |
|
*/ |
|
function subtract(out, a, b) { |
|
out[0] = a[0] - b[0]; |
|
out[1] = a[1] - b[1]; |
|
out[2] = a[2] - b[2]; |
|
out[3] = a[3] - b[3]; |
|
out[4] = a[4] - b[4]; |
|
out[5] = a[5] - b[5]; |
|
out[6] = a[6] - b[6]; |
|
out[7] = a[7] - b[7]; |
|
out[8] = a[8] - b[8]; |
|
return out; |
|
} |
|
|
|
|
|
|
|
/** |
|
* Multiply each element of the matrix by a scalar. |
|
* |
|
* @param {mat3} out the receiving matrix |
|
* @param {mat3} a the matrix to scale |
|
* @param {Number} b amount to scale the matrix's elements by |
|
* @returns {mat3} out |
|
*/ |
|
function multiplyScalar(out, a, b) { |
|
out[0] = a[0] * b; |
|
out[1] = a[1] * b; |
|
out[2] = a[2] * b; |
|
out[3] = a[3] * b; |
|
out[4] = a[4] * b; |
|
out[5] = a[5] * b; |
|
out[6] = a[6] * b; |
|
out[7] = a[7] * b; |
|
out[8] = a[8] * b; |
|
return out; |
|
} |
|
|
|
/** |
|
* Adds two mat3's after multiplying each element of the second operand by a scalar value. |
|
* |
|
* @param {mat3} out the receiving vector |
|
* @param {mat3} a the first operand |
|
* @param {mat3} b the second operand |
|
* @param {Number} scale the amount to scale b's elements by before adding |
|
* @returns {mat3} out |
|
*/ |
|
function multiplyScalarAndAdd(out, a, b, scale) { |
|
out[0] = a[0] + (b[0] * scale); |
|
out[1] = a[1] + (b[1] * scale); |
|
out[2] = a[2] + (b[2] * scale); |
|
out[3] = a[3] + (b[3] * scale); |
|
out[4] = a[4] + (b[4] * scale); |
|
out[5] = a[5] + (b[5] * scale); |
|
out[6] = a[6] + (b[6] * scale); |
|
out[7] = a[7] + (b[7] * scale); |
|
out[8] = a[8] + (b[8] * scale); |
|
return out; |
|
} |
|
|
|
/** |
|
* Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===) |
|
* |
|
* @param {mat3} a The first matrix. |
|
* @param {mat3} b The second matrix. |
|
* @returns {Boolean} True if the matrices are equal, false otherwise. |
|
*/ |
|
function exactEquals(a, b) { |
|
return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && |
|
a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && |
|
a[6] === b[6] && a[7] === b[7] && a[8] === b[8]; |
|
} |
|
|
|
/** |
|
* Returns whether or not the matrices have approximately the same elements in the same position. |
|
* |
|
* @param {mat3} a The first matrix. |
|
* @param {mat3} b The second matrix. |
|
* @returns {Boolean} True if the matrices are equal, false otherwise. |
|
*/ |
|
function equals(a, b) { |
|
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], a6 = a[6], a7 = a[7], a8 = a[8]; |
|
let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7], b8 = b[8]; |
|
return (Math.abs(a0 - b0) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a0), Math.abs(b0)) && |
|
Math.abs(a1 - b1) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a1), Math.abs(b1)) && |
|
Math.abs(a2 - b2) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a2), Math.abs(b2)) && |
|
Math.abs(a3 - b3) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a3), Math.abs(b3)) && |
|
Math.abs(a4 - b4) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a4), Math.abs(b4)) && |
|
Math.abs(a5 - b5) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a5), Math.abs(b5)) && |
|
Math.abs(a6 - b6) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a6), Math.abs(b6)) && |
|
Math.abs(a7 - b7) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a7), Math.abs(b7)) && |
|
Math.abs(a8 - b8) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a8), Math.abs(b8))); |
|
} |
|
|
|
/** |
|
* Alias for {@link mat3.multiply} |
|
* @function |
|
*/ |
|
const mul = multiply; |
|
/* harmony export (immutable) */ __webpack_exports__["mul"] = mul; |
|
|
|
|
|
/** |
|
* Alias for {@link mat3.subtract} |
|
* @function |
|
*/ |
|
const sub = subtract; |
|
/* harmony export (immutable) */ __webpack_exports__["sub"] = sub; |
|
|
|
|
|
|
|
/***/ }), |
|
/* 3 */ |
|
/***/ (function(module, __webpack_exports__, __webpack_require__) { |
|
|
|
"use strict"; |
|
Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); |
|
/* harmony export (immutable) */ __webpack_exports__["create"] = create; |
|
/* harmony export (immutable) */ __webpack_exports__["clone"] = clone; |
|
/* harmony export (immutable) */ __webpack_exports__["length"] = length; |
|
/* harmony export (immutable) */ __webpack_exports__["fromValues"] = fromValues; |
|
/* harmony export (immutable) */ __webpack_exports__["copy"] = copy; |
|
/* harmony export (immutable) */ __webpack_exports__["set"] = set; |
|
/* harmony export (immutable) */ __webpack_exports__["add"] = add; |
|
/* harmony export (immutable) */ __webpack_exports__["subtract"] = subtract; |
|
/* harmony export (immutable) */ __webpack_exports__["multiply"] = multiply; |
|
/* harmony export (immutable) */ __webpack_exports__["divide"] = divide; |
|
/* harmony export (immutable) */ __webpack_exports__["ceil"] = ceil; |
|
/* harmony export (immutable) */ __webpack_exports__["floor"] = floor; |
|
/* harmony export (immutable) */ __webpack_exports__["min"] = min; |
|
/* harmony export (immutable) */ __webpack_exports__["max"] = max; |
|
/* harmony export (immutable) */ __webpack_exports__["round"] = round; |
|
/* harmony export (immutable) */ __webpack_exports__["scale"] = scale; |
|
/* harmony export (immutable) */ __webpack_exports__["scaleAndAdd"] = scaleAndAdd; |
|
/* harmony export (immutable) */ __webpack_exports__["distance"] = distance; |
|
/* harmony export (immutable) */ __webpack_exports__["squaredDistance"] = squaredDistance; |
|
/* harmony export (immutable) */ __webpack_exports__["squaredLength"] = squaredLength; |
|
/* harmony export (immutable) */ __webpack_exports__["negate"] = negate; |
|
/* harmony export (immutable) */ __webpack_exports__["inverse"] = inverse; |
|
/* harmony export (immutable) */ __webpack_exports__["normalize"] = normalize; |
|
/* harmony export (immutable) */ __webpack_exports__["dot"] = dot; |
|
/* harmony export (immutable) */ __webpack_exports__["cross"] = cross; |
|
/* harmony export (immutable) */ __webpack_exports__["lerp"] = lerp; |
|
/* harmony export (immutable) */ __webpack_exports__["hermite"] = hermite; |
|
/* harmony export (immutable) */ __webpack_exports__["bezier"] = bezier; |
|
/* harmony export (immutable) */ __webpack_exports__["random"] = random; |
|
/* harmony export (immutable) */ __webpack_exports__["transformMat4"] = transformMat4; |
|
/* harmony export (immutable) */ __webpack_exports__["transformMat3"] = transformMat3; |
|
/* harmony export (immutable) */ __webpack_exports__["transformQuat"] = transformQuat; |
|
/* harmony export (immutable) */ __webpack_exports__["rotateX"] = rotateX; |
|
/* harmony export (immutable) */ __webpack_exports__["rotateY"] = rotateY; |
|
/* harmony export (immutable) */ __webpack_exports__["rotateZ"] = rotateZ; |
|
/* harmony export (immutable) */ __webpack_exports__["angle"] = angle; |
|
/* harmony export (immutable) */ __webpack_exports__["str"] = str; |
|
/* harmony export (immutable) */ __webpack_exports__["exactEquals"] = exactEquals; |
|
/* harmony export (immutable) */ __webpack_exports__["equals"] = equals; |
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__common__ = __webpack_require__(0); |
|
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. |
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
|
of this software and associated documentation files (the "Software"), to deal |
|
in the Software without restriction, including without limitation the rights |
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
copies of the Software, and to permit persons to whom the Software is |
|
furnished to do so, subject to the following conditions: |
|
|
|
The above copyright notice and this permission notice shall be included in |
|
all copies or substantial portions of the Software. |
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
THE SOFTWARE. */ |
|
|
|
|
|
|
|
/** |
|
* 3 Dimensional Vector |
|
* @module vec3 |
|
*/ |
|
|
|
/** |
|
* Creates a new, empty vec3 |
|
* |
|
* @returns {vec3} a new 3D vector |
|
*/ |
|
function create() { |
|
let out = new __WEBPACK_IMPORTED_MODULE_0__common__["ARRAY_TYPE"](3); |
|
out[0] = 0; |
|
out[1] = 0; |
|
out[2] = 0; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a new vec3 initialized with values from an existing vector |
|
* |
|
* @param {vec3} a vector to clone |
|
* @returns {vec3} a new 3D vector |
|
*/ |
|
function clone(a) { |
|
var out = new __WEBPACK_IMPORTED_MODULE_0__common__["ARRAY_TYPE"](3); |
|
out[0] = a[0]; |
|
out[1] = a[1]; |
|
out[2] = a[2]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Calculates the length of a vec3 |
|
* |
|
* @param {vec3} a vector to calculate length of |
|
* @returns {Number} length of a |
|
*/ |
|
function length(a) { |
|
let x = a[0]; |
|
let y = a[1]; |
|
let z = a[2]; |
|
return Math.sqrt(x*x + y*y + z*z); |
|
} |
|
|
|
/** |
|
* Creates a new vec3 initialized with the given values |
|
* |
|
* @param {Number} x X component |
|
* @param {Number} y Y component |
|
* @param {Number} z Z component |
|
* @returns {vec3} a new 3D vector |
|
*/ |
|
function fromValues(x, y, z) { |
|
let out = new __WEBPACK_IMPORTED_MODULE_0__common__["ARRAY_TYPE"](3); |
|
out[0] = x; |
|
out[1] = y; |
|
out[2] = z; |
|
return out; |
|
} |
|
|
|
/** |
|
* Copy the values from one vec3 to another |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {vec3} a the source vector |
|
* @returns {vec3} out |
|
*/ |
|
function copy(out, a) { |
|
out[0] = a[0]; |
|
out[1] = a[1]; |
|
out[2] = a[2]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Set the components of a vec3 to the given values |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {Number} x X component |
|
* @param {Number} y Y component |
|
* @param {Number} z Z component |
|
* @returns {vec3} out |
|
*/ |
|
function set(out, x, y, z) { |
|
out[0] = x; |
|
out[1] = y; |
|
out[2] = z; |
|
return out; |
|
} |
|
|
|
/** |
|
* Adds two vec3's |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {vec3} a the first operand |
|
* @param {vec3} b the second operand |
|
* @returns {vec3} out |
|
*/ |
|
function add(out, a, b) { |
|
out[0] = a[0] + b[0]; |
|
out[1] = a[1] + b[1]; |
|
out[2] = a[2] + b[2]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Subtracts vector b from vector a |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {vec3} a the first operand |
|
* @param {vec3} b the second operand |
|
* @returns {vec3} out |
|
*/ |
|
function subtract(out, a, b) { |
|
out[0] = a[0] - b[0]; |
|
out[1] = a[1] - b[1]; |
|
out[2] = a[2] - b[2]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Multiplies two vec3's |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {vec3} a the first operand |
|
* @param {vec3} b the second operand |
|
* @returns {vec3} out |
|
*/ |
|
function multiply(out, a, b) { |
|
out[0] = a[0] * b[0]; |
|
out[1] = a[1] * b[1]; |
|
out[2] = a[2] * b[2]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Divides two vec3's |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {vec3} a the first operand |
|
* @param {vec3} b the second operand |
|
* @returns {vec3} out |
|
*/ |
|
function divide(out, a, b) { |
|
out[0] = a[0] / b[0]; |
|
out[1] = a[1] / b[1]; |
|
out[2] = a[2] / b[2]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Math.ceil the components of a vec3 |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {vec3} a vector to ceil |
|
* @returns {vec3} out |
|
*/ |
|
function ceil(out, a) { |
|
out[0] = Math.ceil(a[0]); |
|
out[1] = Math.ceil(a[1]); |
|
out[2] = Math.ceil(a[2]); |
|
return out; |
|
} |
|
|
|
/** |
|
* Math.floor the components of a vec3 |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {vec3} a vector to floor |
|
* @returns {vec3} out |
|
*/ |
|
function floor(out, a) { |
|
out[0] = Math.floor(a[0]); |
|
out[1] = Math.floor(a[1]); |
|
out[2] = Math.floor(a[2]); |
|
return out; |
|
} |
|
|
|
/** |
|
* Returns the minimum of two vec3's |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {vec3} a the first operand |
|
* @param {vec3} b the second operand |
|
* @returns {vec3} out |
|
*/ |
|
function min(out, a, b) { |
|
out[0] = Math.min(a[0], b[0]); |
|
out[1] = Math.min(a[1], b[1]); |
|
out[2] = Math.min(a[2], b[2]); |
|
return out; |
|
} |
|
|
|
/** |
|
* Returns the maximum of two vec3's |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {vec3} a the first operand |
|
* @param {vec3} b the second operand |
|
* @returns {vec3} out |
|
*/ |
|
function max(out, a, b) { |
|
out[0] = Math.max(a[0], b[0]); |
|
out[1] = Math.max(a[1], b[1]); |
|
out[2] = Math.max(a[2], b[2]); |
|
return out; |
|
} |
|
|
|
/** |
|
* Math.round the components of a vec3 |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {vec3} a vector to round |
|
* @returns {vec3} out |
|
*/ |
|
function round(out, a) { |
|
out[0] = Math.round(a[0]); |
|
out[1] = Math.round(a[1]); |
|
out[2] = Math.round(a[2]); |
|
return out; |
|
} |
|
|
|
/** |
|
* Scales a vec3 by a scalar number |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {vec3} a the vector to scale |
|
* @param {Number} b amount to scale the vector by |
|
* @returns {vec3} out |
|
*/ |
|
function scale(out, a, b) { |
|
out[0] = a[0] * b; |
|
out[1] = a[1] * b; |
|
out[2] = a[2] * b; |
|
return out; |
|
} |
|
|
|
/** |
|
* Adds two vec3's after scaling the second operand by a scalar value |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {vec3} a the first operand |
|
* @param {vec3} b the second operand |
|
* @param {Number} scale the amount to scale b by before adding |
|
* @returns {vec3} out |
|
*/ |
|
function scaleAndAdd(out, a, b, scale) { |
|
out[0] = a[0] + (b[0] * scale); |
|
out[1] = a[1] + (b[1] * scale); |
|
out[2] = a[2] + (b[2] * scale); |
|
return out; |
|
} |
|
|
|
/** |
|
* Calculates the euclidian distance between two vec3's |
|
* |
|
* @param {vec3} a the first operand |
|
* @param {vec3} b the second operand |
|
* @returns {Number} distance between a and b |
|
*/ |
|
function distance(a, b) { |
|
let x = b[0] - a[0]; |
|
let y = b[1] - a[1]; |
|
let z = b[2] - a[2]; |
|
return Math.sqrt(x*x + y*y + z*z); |
|
} |
|
|
|
/** |
|
* Calculates the squared euclidian distance between two vec3's |
|
* |
|
* @param {vec3} a the first operand |
|
* @param {vec3} b the second operand |
|
* @returns {Number} squared distance between a and b |
|
*/ |
|
function squaredDistance(a, b) { |
|
let x = b[0] - a[0]; |
|
let y = b[1] - a[1]; |
|
let z = b[2] - a[2]; |
|
return x*x + y*y + z*z; |
|
} |
|
|
|
/** |
|
* Calculates the squared length of a vec3 |
|
* |
|
* @param {vec3} a vector to calculate squared length of |
|
* @returns {Number} squared length of a |
|
*/ |
|
function squaredLength(a) { |
|
let x = a[0]; |
|
let y = a[1]; |
|
let z = a[2]; |
|
return x*x + y*y + z*z; |
|
} |
|
|
|
/** |
|
* Negates the components of a vec3 |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {vec3} a vector to negate |
|
* @returns {vec3} out |
|
*/ |
|
function negate(out, a) { |
|
out[0] = -a[0]; |
|
out[1] = -a[1]; |
|
out[2] = -a[2]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Returns the inverse of the components of a vec3 |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {vec3} a vector to invert |
|
* @returns {vec3} out |
|
*/ |
|
function inverse(out, a) { |
|
out[0] = 1.0 / a[0]; |
|
out[1] = 1.0 / a[1]; |
|
out[2] = 1.0 / a[2]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Normalize a vec3 |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {vec3} a vector to normalize |
|
* @returns {vec3} out |
|
*/ |
|
function normalize(out, a) { |
|
let x = a[0]; |
|
let y = a[1]; |
|
let z = a[2]; |
|
let len = x*x + y*y + z*z; |
|
if (len > 0) { |
|
//TODO: evaluate use of glm_invsqrt here? |
|
len = 1 / Math.sqrt(len); |
|
out[0] = a[0] * len; |
|
out[1] = a[1] * len; |
|
out[2] = a[2] * len; |
|
} |
|
return out; |
|
} |
|
|
|
/** |
|
* Calculates the dot product of two vec3's |
|
* |
|
* @param {vec3} a the first operand |
|
* @param {vec3} b the second operand |
|
* @returns {Number} dot product of a and b |
|
*/ |
|
function dot(a, b) { |
|
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; |
|
} |
|
|
|
/** |
|
* Computes the cross product of two vec3's |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {vec3} a the first operand |
|
* @param {vec3} b the second operand |
|
* @returns {vec3} out |
|
*/ |
|
function cross(out, a, b) { |
|
let ax = a[0], ay = a[1], az = a[2]; |
|
let bx = b[0], by = b[1], bz = b[2]; |
|
|
|
out[0] = ay * bz - az * by; |
|
out[1] = az * bx - ax * bz; |
|
out[2] = ax * by - ay * bx; |
|
return out; |
|
} |
|
|
|
/** |
|
* Performs a linear interpolation between two vec3's |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {vec3} a the first operand |
|
* @param {vec3} b the second operand |
|
* @param {Number} t interpolation amount between the two inputs |
|
* @returns {vec3} out |
|
*/ |
|
function lerp(out, a, b, t) { |
|
let ax = a[0]; |
|
let ay = a[1]; |
|
let az = a[2]; |
|
out[0] = ax + t * (b[0] - ax); |
|
out[1] = ay + t * (b[1] - ay); |
|
out[2] = az + t * (b[2] - az); |
|
return out; |
|
} |
|
|
|
/** |
|
* Performs a hermite interpolation with two control points |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {vec3} a the first operand |
|
* @param {vec3} b the second operand |
|
* @param {vec3} c the third operand |
|
* @param {vec3} d the fourth operand |
|
* @param {Number} t interpolation amount between the two inputs |
|
* @returns {vec3} out |
|
*/ |
|
function hermite(out, a, b, c, d, t) { |
|
let factorTimes2 = t * t; |
|
let factor1 = factorTimes2 * (2 * t - 3) + 1; |
|
let factor2 = factorTimes2 * (t - 2) + t; |
|
let factor3 = factorTimes2 * (t - 1); |
|
let factor4 = factorTimes2 * (3 - 2 * t); |
|
|
|
out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4; |
|
out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4; |
|
out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4; |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Performs a bezier interpolation with two control points |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {vec3} a the first operand |
|
* @param {vec3} b the second operand |
|
* @param {vec3} c the third operand |
|
* @param {vec3} d the fourth operand |
|
* @param {Number} t interpolation amount between the two inputs |
|
* @returns {vec3} out |
|
*/ |
|
function bezier(out, a, b, c, d, t) { |
|
let inverseFactor = 1 - t; |
|
let inverseFactorTimesTwo = inverseFactor * inverseFactor; |
|
let factorTimes2 = t * t; |
|
let factor1 = inverseFactorTimesTwo * inverseFactor; |
|
let factor2 = 3 * t * inverseFactorTimesTwo; |
|
let factor3 = 3 * factorTimes2 * inverseFactor; |
|
let factor4 = factorTimes2 * t; |
|
|
|
out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4; |
|
out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4; |
|
out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4; |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Generates a random vector with the given scale |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned |
|
* @returns {vec3} out |
|
*/ |
|
function random(out, scale) { |
|
scale = scale || 1.0; |
|
|
|
let r = __WEBPACK_IMPORTED_MODULE_0__common__["RANDOM"]() * 2.0 * Math.PI; |
|
let z = (__WEBPACK_IMPORTED_MODULE_0__common__["RANDOM"]() * 2.0) - 1.0; |
|
let zScale = Math.sqrt(1.0-z*z) * scale; |
|
|
|
out[0] = Math.cos(r) * zScale; |
|
out[1] = Math.sin(r) * zScale; |
|
out[2] = z * scale; |
|
return out; |
|
} |
|
|
|
/** |
|
* Transforms the vec3 with a mat4. |
|
* 4th vector component is implicitly '1' |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {vec3} a the vector to transform |
|
* @param {mat4} m matrix to transform with |
|
* @returns {vec3} out |
|
*/ |
|
function transformMat4(out, a, m) { |
|
let x = a[0], y = a[1], z = a[2]; |
|
let w = m[3] * x + m[7] * y + m[11] * z + m[15]; |
|
w = w || 1.0; |
|
out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w; |
|
out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w; |
|
out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w; |
|
return out; |
|
} |
|
|
|
/** |
|
* Transforms the vec3 with a mat3. |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {vec3} a the vector to transform |
|
* @param {mat3} m the 3x3 matrix to transform with |
|
* @returns {vec3} out |
|
*/ |
|
function transformMat3(out, a, m) { |
|
let x = a[0], y = a[1], z = a[2]; |
|
out[0] = x * m[0] + y * m[3] + z * m[6]; |
|
out[1] = x * m[1] + y * m[4] + z * m[7]; |
|
out[2] = x * m[2] + y * m[5] + z * m[8]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Transforms the vec3 with a quat |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {vec3} a the vector to transform |
|
* @param {quat} q quaternion to transform with |
|
* @returns {vec3} out |
|
*/ |
|
function transformQuat(out, a, q) { |
|
// benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations |
|
|
|
let x = a[0], y = a[1], z = a[2]; |
|
let qx = q[0], qy = q[1], qz = q[2], qw = q[3]; |
|
|
|
// calculate quat * vec |
|
let ix = qw * x + qy * z - qz * y; |
|
let iy = qw * y + qz * x - qx * z; |
|
let iz = qw * z + qx * y - qy * x; |
|
let iw = -qx * x - qy * y - qz * z; |
|
|
|
// calculate result * inverse quat |
|
out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; |
|
out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; |
|
out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; |
|
return out; |
|
} |
|
|
|
/** |
|
* Rotate a 3D vector around the x-axis |
|
* @param {vec3} out The receiving vec3 |
|
* @param {vec3} a The vec3 point to rotate |
|
* @param {vec3} b The origin of the rotation |
|
* @param {Number} c The angle of rotation |
|
* @returns {vec3} out |
|
*/ |
|
function rotateX(out, a, b, c){ |
|
let p = [], r=[]; |
|
//Translate point to the origin |
|
p[0] = a[0] - b[0]; |
|
p[1] = a[1] - b[1]; |
|
p[2] = a[2] - b[2]; |
|
|
|
//perform rotation |
|
r[0] = p[0]; |
|
r[1] = p[1]*Math.cos(c) - p[2]*Math.sin(c); |
|
r[2] = p[1]*Math.sin(c) + p[2]*Math.cos(c); |
|
|
|
//translate to correct position |
|
out[0] = r[0] + b[0]; |
|
out[1] = r[1] + b[1]; |
|
out[2] = r[2] + b[2]; |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Rotate a 3D vector around the y-axis |
|
* @param {vec3} out The receiving vec3 |
|
* @param {vec3} a The vec3 point to rotate |
|
* @param {vec3} b The origin of the rotation |
|
* @param {Number} c The angle of rotation |
|
* @returns {vec3} out |
|
*/ |
|
function rotateY(out, a, b, c){ |
|
let p = [], r=[]; |
|
//Translate point to the origin |
|
p[0] = a[0] - b[0]; |
|
p[1] = a[1] - b[1]; |
|
p[2] = a[2] - b[2]; |
|
|
|
//perform rotation |
|
r[0] = p[2]*Math.sin(c) + p[0]*Math.cos(c); |
|
r[1] = p[1]; |
|
r[2] = p[2]*Math.cos(c) - p[0]*Math.sin(c); |
|
|
|
//translate to correct position |
|
out[0] = r[0] + b[0]; |
|
out[1] = r[1] + b[1]; |
|
out[2] = r[2] + b[2]; |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Rotate a 3D vector around the z-axis |
|
* @param {vec3} out The receiving vec3 |
|
* @param {vec3} a The vec3 point to rotate |
|
* @param {vec3} b The origin of the rotation |
|
* @param {Number} c The angle of rotation |
|
* @returns {vec3} out |
|
*/ |
|
function rotateZ(out, a, b, c){ |
|
let p = [], r=[]; |
|
//Translate point to the origin |
|
p[0] = a[0] - b[0]; |
|
p[1] = a[1] - b[1]; |
|
p[2] = a[2] - b[2]; |
|
|
|
//perform rotation |
|
r[0] = p[0]*Math.cos(c) - p[1]*Math.sin(c); |
|
r[1] = p[0]*Math.sin(c) + p[1]*Math.cos(c); |
|
r[2] = p[2]; |
|
|
|
//translate to correct position |
|
out[0] = r[0] + b[0]; |
|
out[1] = r[1] + b[1]; |
|
out[2] = r[2] + b[2]; |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Get the angle between two 3D vectors |
|
* @param {vec3} a The first operand |
|
* @param {vec3} b The second operand |
|
* @returns {Number} The angle in radians |
|
*/ |
|
function angle(a, b) { |
|
let tempA = fromValues(a[0], a[1], a[2]); |
|
let tempB = fromValues(b[0], b[1], b[2]); |
|
|
|
normalize(tempA, tempA); |
|
normalize(tempB, tempB); |
|
|
|
let cosine = dot(tempA, tempB); |
|
|
|
if(cosine > 1.0) { |
|
return 0; |
|
} |
|
else if(cosine < -1.0) { |
|
return Math.PI; |
|
} else { |
|
return Math.acos(cosine); |
|
} |
|
} |
|
|
|
/** |
|
* Returns a string representation of a vector |
|
* |
|
* @param {vec3} a vector to represent as a string |
|
* @returns {String} string representation of the vector |
|
*/ |
|
function str(a) { |
|
return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')'; |
|
} |
|
|
|
/** |
|
* Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===) |
|
* |
|
* @param {vec3} a The first vector. |
|
* @param {vec3} b The second vector. |
|
* @returns {Boolean} True if the vectors are equal, false otherwise. |
|
*/ |
|
function exactEquals(a, b) { |
|
return a[0] === b[0] && a[1] === b[1] && a[2] === b[2]; |
|
} |
|
|
|
/** |
|
* Returns whether or not the vectors have approximately the same elements in the same position. |
|
* |
|
* @param {vec3} a The first vector. |
|
* @param {vec3} b The second vector. |
|
* @returns {Boolean} True if the vectors are equal, false otherwise. |
|
*/ |
|
function equals(a, b) { |
|
let a0 = a[0], a1 = a[1], a2 = a[2]; |
|
let b0 = b[0], b1 = b[1], b2 = b[2]; |
|
return (Math.abs(a0 - b0) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a0), Math.abs(b0)) && |
|
Math.abs(a1 - b1) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a1), Math.abs(b1)) && |
|
Math.abs(a2 - b2) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a2), Math.abs(b2))); |
|
} |
|
|
|
/** |
|
* Alias for {@link vec3.subtract} |
|
* @function |
|
*/ |
|
const sub = subtract; |
|
/* harmony export (immutable) */ __webpack_exports__["sub"] = sub; |
|
|
|
|
|
/** |
|
* Alias for {@link vec3.multiply} |
|
* @function |
|
*/ |
|
const mul = multiply; |
|
/* harmony export (immutable) */ __webpack_exports__["mul"] = mul; |
|
|
|
|
|
/** |
|
* Alias for {@link vec3.divide} |
|
* @function |
|
*/ |
|
const div = divide; |
|
/* harmony export (immutable) */ __webpack_exports__["div"] = div; |
|
|
|
|
|
/** |
|
* Alias for {@link vec3.distance} |
|
* @function |
|
*/ |
|
const dist = distance; |
|
/* harmony export (immutable) */ __webpack_exports__["dist"] = dist; |
|
|
|
|
|
/** |
|
* Alias for {@link vec3.squaredDistance} |
|
* @function |
|
*/ |
|
const sqrDist = squaredDistance; |
|
/* harmony export (immutable) */ __webpack_exports__["sqrDist"] = sqrDist; |
|
|
|
|
|
/** |
|
* Alias for {@link vec3.length} |
|
* @function |
|
*/ |
|
const len = length; |
|
/* harmony export (immutable) */ __webpack_exports__["len"] = len; |
|
|
|
|
|
/** |
|
* Alias for {@link vec3.squaredLength} |
|
* @function |
|
*/ |
|
const sqrLen = squaredLength; |
|
/* harmony export (immutable) */ __webpack_exports__["sqrLen"] = sqrLen; |
|
|
|
|
|
/** |
|
* Perform some operation over an array of vec3s. |
|
* |
|
* @param {Array} a the array of vectors to iterate over |
|
* @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed |
|
* @param {Number} offset Number of elements to skip at the beginning of the array |
|
* @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array |
|
* @param {Function} fn Function to call for each vector in the array |
|
* @param {Object} [arg] additional argument to pass to fn |
|
* @returns {Array} a |
|
* @function |
|
*/ |
|
const forEach = (function() { |
|
let vec = create(); |
|
|
|
return function(a, stride, offset, count, fn, arg) { |
|
let i, l; |
|
if(!stride) { |
|
stride = 3; |
|
} |
|
|
|
if(!offset) { |
|
offset = 0; |
|
} |
|
|
|
if(count) { |
|
l = Math.min((count * stride) + offset, a.length); |
|
} else { |
|
l = a.length; |
|
} |
|
|
|
for(i = offset; i < l; i += stride) { |
|
vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; |
|
fn(vec, vec, arg); |
|
a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; |
|
} |
|
|
|
return a; |
|
}; |
|
})(); |
|
/* harmony export (immutable) */ __webpack_exports__["forEach"] = forEach; |
|
|
|
|
|
|
|
/***/ }), |
|
/* 4 */ |
|
/***/ (function(module, __webpack_exports__, __webpack_require__) { |
|
|
|
"use strict"; |
|
Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); |
|
/* harmony export (immutable) */ __webpack_exports__["create"] = create; |
|
/* harmony export (immutable) */ __webpack_exports__["clone"] = clone; |
|
/* harmony export (immutable) */ __webpack_exports__["fromValues"] = fromValues; |
|
/* harmony export (immutable) */ __webpack_exports__["copy"] = copy; |
|
/* harmony export (immutable) */ __webpack_exports__["set"] = set; |
|
/* harmony export (immutable) */ __webpack_exports__["add"] = add; |
|
/* harmony export (immutable) */ __webpack_exports__["subtract"] = subtract; |
|
/* harmony export (immutable) */ __webpack_exports__["multiply"] = multiply; |
|
/* harmony export (immutable) */ __webpack_exports__["divide"] = divide; |
|
/* harmony export (immutable) */ __webpack_exports__["ceil"] = ceil; |
|
/* harmony export (immutable) */ __webpack_exports__["floor"] = floor; |
|
/* harmony export (immutable) */ __webpack_exports__["min"] = min; |
|
/* harmony export (immutable) */ __webpack_exports__["max"] = max; |
|
/* harmony export (immutable) */ __webpack_exports__["round"] = round; |
|
/* harmony export (immutable) */ __webpack_exports__["scale"] = scale; |
|
/* harmony export (immutable) */ __webpack_exports__["scaleAndAdd"] = scaleAndAdd; |
|
/* harmony export (immutable) */ __webpack_exports__["distance"] = distance; |
|
/* harmony export (immutable) */ __webpack_exports__["squaredDistance"] = squaredDistance; |
|
/* harmony export (immutable) */ __webpack_exports__["length"] = length; |
|
/* harmony export (immutable) */ __webpack_exports__["squaredLength"] = squaredLength; |
|
/* harmony export (immutable) */ __webpack_exports__["negate"] = negate; |
|
/* harmony export (immutable) */ __webpack_exports__["inverse"] = inverse; |
|
/* harmony export (immutable) */ __webpack_exports__["normalize"] = normalize; |
|
/* harmony export (immutable) */ __webpack_exports__["dot"] = dot; |
|
/* harmony export (immutable) */ __webpack_exports__["lerp"] = lerp; |
|
/* harmony export (immutable) */ __webpack_exports__["random"] = random; |
|
/* harmony export (immutable) */ __webpack_exports__["transformMat4"] = transformMat4; |
|
/* harmony export (immutable) */ __webpack_exports__["transformQuat"] = transformQuat; |
|
/* harmony export (immutable) */ __webpack_exports__["str"] = str; |
|
/* harmony export (immutable) */ __webpack_exports__["exactEquals"] = exactEquals; |
|
/* harmony export (immutable) */ __webpack_exports__["equals"] = equals; |
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__common__ = __webpack_require__(0); |
|
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. |
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
|
of this software and associated documentation files (the "Software"), to deal |
|
in the Software without restriction, including without limitation the rights |
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
copies of the Software, and to permit persons to whom the Software is |
|
furnished to do so, subject to the following conditions: |
|
|
|
The above copyright notice and this permission notice shall be included in |
|
all copies or substantial portions of the Software. |
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
THE SOFTWARE. */ |
|
|
|
|
|
|
|
/** |
|
* 4 Dimensional Vector |
|
* @module vec4 |
|
*/ |
|
|
|
/** |
|
* Creates a new, empty vec4 |
|
* |
|
* @returns {vec4} a new 4D vector |
|
*/ |
|
function create() { |
|
let out = new __WEBPACK_IMPORTED_MODULE_0__common__["ARRAY_TYPE"](4); |
|
out[0] = 0; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 0; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a new vec4 initialized with values from an existing vector |
|
* |
|
* @param {vec4} a vector to clone |
|
* @returns {vec4} a new 4D vector |
|
*/ |
|
function clone(a) { |
|
let out = new __WEBPACK_IMPORTED_MODULE_0__common__["ARRAY_TYPE"](4); |
|
out[0] = a[0]; |
|
out[1] = a[1]; |
|
out[2] = a[2]; |
|
out[3] = a[3]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a new vec4 initialized with the given values |
|
* |
|
* @param {Number} x X component |
|
* @param {Number} y Y component |
|
* @param {Number} z Z component |
|
* @param {Number} w W component |
|
* @returns {vec4} a new 4D vector |
|
*/ |
|
function fromValues(x, y, z, w) { |
|
let out = new __WEBPACK_IMPORTED_MODULE_0__common__["ARRAY_TYPE"](4); |
|
out[0] = x; |
|
out[1] = y; |
|
out[2] = z; |
|
out[3] = w; |
|
return out; |
|
} |
|
|
|
/** |
|
* Copy the values from one vec4 to another |
|
* |
|
* @param {vec4} out the receiving vector |
|
* @param {vec4} a the source vector |
|
* @returns {vec4} out |
|
*/ |
|
function copy(out, a) { |
|
out[0] = a[0]; |
|
out[1] = a[1]; |
|
out[2] = a[2]; |
|
out[3] = a[3]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Set the components of a vec4 to the given values |
|
* |
|
* @param {vec4} out the receiving vector |
|
* @param {Number} x X component |
|
* @param {Number} y Y component |
|
* @param {Number} z Z component |
|
* @param {Number} w W component |
|
* @returns {vec4} out |
|
*/ |
|
function set(out, x, y, z, w) { |
|
out[0] = x; |
|
out[1] = y; |
|
out[2] = z; |
|
out[3] = w; |
|
return out; |
|
} |
|
|
|
/** |
|
* Adds two vec4's |
|
* |
|
* @param {vec4} out the receiving vector |
|
* @param {vec4} a the first operand |
|
* @param {vec4} b the second operand |
|
* @returns {vec4} out |
|
*/ |
|
function add(out, a, b) { |
|
out[0] = a[0] + b[0]; |
|
out[1] = a[1] + b[1]; |
|
out[2] = a[2] + b[2]; |
|
out[3] = a[3] + b[3]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Subtracts vector b from vector a |
|
* |
|
* @param {vec4} out the receiving vector |
|
* @param {vec4} a the first operand |
|
* @param {vec4} b the second operand |
|
* @returns {vec4} out |
|
*/ |
|
function subtract(out, a, b) { |
|
out[0] = a[0] - b[0]; |
|
out[1] = a[1] - b[1]; |
|
out[2] = a[2] - b[2]; |
|
out[3] = a[3] - b[3]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Multiplies two vec4's |
|
* |
|
* @param {vec4} out the receiving vector |
|
* @param {vec4} a the first operand |
|
* @param {vec4} b the second operand |
|
* @returns {vec4} out |
|
*/ |
|
function multiply(out, a, b) { |
|
out[0] = a[0] * b[0]; |
|
out[1] = a[1] * b[1]; |
|
out[2] = a[2] * b[2]; |
|
out[3] = a[3] * b[3]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Divides two vec4's |
|
* |
|
* @param {vec4} out the receiving vector |
|
* @param {vec4} a the first operand |
|
* @param {vec4} b the second operand |
|
* @returns {vec4} out |
|
*/ |
|
function divide(out, a, b) { |
|
out[0] = a[0] / b[0]; |
|
out[1] = a[1] / b[1]; |
|
out[2] = a[2] / b[2]; |
|
out[3] = a[3] / b[3]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Math.ceil the components of a vec4 |
|
* |
|
* @param {vec4} out the receiving vector |
|
* @param {vec4} a vector to ceil |
|
* @returns {vec4} out |
|
*/ |
|
function ceil(out, a) { |
|
out[0] = Math.ceil(a[0]); |
|
out[1] = Math.ceil(a[1]); |
|
out[2] = Math.ceil(a[2]); |
|
out[3] = Math.ceil(a[3]); |
|
return out; |
|
} |
|
|
|
/** |
|
* Math.floor the components of a vec4 |
|
* |
|
* @param {vec4} out the receiving vector |
|
* @param {vec4} a vector to floor |
|
* @returns {vec4} out |
|
*/ |
|
function floor(out, a) { |
|
out[0] = Math.floor(a[0]); |
|
out[1] = Math.floor(a[1]); |
|
out[2] = Math.floor(a[2]); |
|
out[3] = Math.floor(a[3]); |
|
return out; |
|
} |
|
|
|
/** |
|
* Returns the minimum of two vec4's |
|
* |
|
* @param {vec4} out the receiving vector |
|
* @param {vec4} a the first operand |
|
* @param {vec4} b the second operand |
|
* @returns {vec4} out |
|
*/ |
|
function min(out, a, b) { |
|
out[0] = Math.min(a[0], b[0]); |
|
out[1] = Math.min(a[1], b[1]); |
|
out[2] = Math.min(a[2], b[2]); |
|
out[3] = Math.min(a[3], b[3]); |
|
return out; |
|
} |
|
|
|
/** |
|
* Returns the maximum of two vec4's |
|
* |
|
* @param {vec4} out the receiving vector |
|
* @param {vec4} a the first operand |
|
* @param {vec4} b the second operand |
|
* @returns {vec4} out |
|
*/ |
|
function max(out, a, b) { |
|
out[0] = Math.max(a[0], b[0]); |
|
out[1] = Math.max(a[1], b[1]); |
|
out[2] = Math.max(a[2], b[2]); |
|
out[3] = Math.max(a[3], b[3]); |
|
return out; |
|
} |
|
|
|
/** |
|
* Math.round the components of a vec4 |
|
* |
|
* @param {vec4} out the receiving vector |
|
* @param {vec4} a vector to round |
|
* @returns {vec4} out |
|
*/ |
|
function round(out, a) { |
|
out[0] = Math.round(a[0]); |
|
out[1] = Math.round(a[1]); |
|
out[2] = Math.round(a[2]); |
|
out[3] = Math.round(a[3]); |
|
return out; |
|
} |
|
|
|
/** |
|
* Scales a vec4 by a scalar number |
|
* |
|
* @param {vec4} out the receiving vector |
|
* @param {vec4} a the vector to scale |
|
* @param {Number} b amount to scale the vector by |
|
* @returns {vec4} out |
|
*/ |
|
function scale(out, a, b) { |
|
out[0] = a[0] * b; |
|
out[1] = a[1] * b; |
|
out[2] = a[2] * b; |
|
out[3] = a[3] * b; |
|
return out; |
|
} |
|
|
|
/** |
|
* Adds two vec4's after scaling the second operand by a scalar value |
|
* |
|
* @param {vec4} out the receiving vector |
|
* @param {vec4} a the first operand |
|
* @param {vec4} b the second operand |
|
* @param {Number} scale the amount to scale b by before adding |
|
* @returns {vec4} out |
|
*/ |
|
function scaleAndAdd(out, a, b, scale) { |
|
out[0] = a[0] + (b[0] * scale); |
|
out[1] = a[1] + (b[1] * scale); |
|
out[2] = a[2] + (b[2] * scale); |
|
out[3] = a[3] + (b[3] * scale); |
|
return out; |
|
} |
|
|
|
/** |
|
* Calculates the euclidian distance between two vec4's |
|
* |
|
* @param {vec4} a the first operand |
|
* @param {vec4} b the second operand |
|
* @returns {Number} distance between a and b |
|
*/ |
|
function distance(a, b) { |
|
let x = b[0] - a[0]; |
|
let y = b[1] - a[1]; |
|
let z = b[2] - a[2]; |
|
let w = b[3] - a[3]; |
|
return Math.sqrt(x*x + y*y + z*z + w*w); |
|
} |
|
|
|
/** |
|
* Calculates the squared euclidian distance between two vec4's |
|
* |
|
* @param {vec4} a the first operand |
|
* @param {vec4} b the second operand |
|
* @returns {Number} squared distance between a and b |
|
*/ |
|
function squaredDistance(a, b) { |
|
let x = b[0] - a[0]; |
|
let y = b[1] - a[1]; |
|
let z = b[2] - a[2]; |
|
let w = b[3] - a[3]; |
|
return x*x + y*y + z*z + w*w; |
|
} |
|
|
|
/** |
|
* Calculates the length of a vec4 |
|
* |
|
* @param {vec4} a vector to calculate length of |
|
* @returns {Number} length of a |
|
*/ |
|
function length(a) { |
|
let x = a[0]; |
|
let y = a[1]; |
|
let z = a[2]; |
|
let w = a[3]; |
|
return Math.sqrt(x*x + y*y + z*z + w*w); |
|
} |
|
|
|
/** |
|
* Calculates the squared length of a vec4 |
|
* |
|
* @param {vec4} a vector to calculate squared length of |
|
* @returns {Number} squared length of a |
|
*/ |
|
function squaredLength(a) { |
|
let x = a[0]; |
|
let y = a[1]; |
|
let z = a[2]; |
|
let w = a[3]; |
|
return x*x + y*y + z*z + w*w; |
|
} |
|
|
|
/** |
|
* Negates the components of a vec4 |
|
* |
|
* @param {vec4} out the receiving vector |
|
* @param {vec4} a vector to negate |
|
* @returns {vec4} out |
|
*/ |
|
function negate(out, a) { |
|
out[0] = -a[0]; |
|
out[1] = -a[1]; |
|
out[2] = -a[2]; |
|
out[3] = -a[3]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Returns the inverse of the components of a vec4 |
|
* |
|
* @param {vec4} out the receiving vector |
|
* @param {vec4} a vector to invert |
|
* @returns {vec4} out |
|
*/ |
|
function inverse(out, a) { |
|
out[0] = 1.0 / a[0]; |
|
out[1] = 1.0 / a[1]; |
|
out[2] = 1.0 / a[2]; |
|
out[3] = 1.0 / a[3]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Normalize a vec4 |
|
* |
|
* @param {vec4} out the receiving vector |
|
* @param {vec4} a vector to normalize |
|
* @returns {vec4} out |
|
*/ |
|
function normalize(out, a) { |
|
let x = a[0]; |
|
let y = a[1]; |
|
let z = a[2]; |
|
let w = a[3]; |
|
let len = x*x + y*y + z*z + w*w; |
|
if (len > 0) { |
|
len = 1 / Math.sqrt(len); |
|
out[0] = x * len; |
|
out[1] = y * len; |
|
out[2] = z * len; |
|
out[3] = w * len; |
|
} |
|
return out; |
|
} |
|
|
|
/** |
|
* Calculates the dot product of two vec4's |
|
* |
|
* @param {vec4} a the first operand |
|
* @param {vec4} b the second operand |
|
* @returns {Number} dot product of a and b |
|
*/ |
|
function dot(a, b) { |
|
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; |
|
} |
|
|
|
/** |
|
* Performs a linear interpolation between two vec4's |
|
* |
|
* @param {vec4} out the receiving vector |
|
* @param {vec4} a the first operand |
|
* @param {vec4} b the second operand |
|
* @param {Number} t interpolation amount between the two inputs |
|
* @returns {vec4} out |
|
*/ |
|
function lerp(out, a, b, t) { |
|
let ax = a[0]; |
|
let ay = a[1]; |
|
let az = a[2]; |
|
let aw = a[3]; |
|
out[0] = ax + t * (b[0] - ax); |
|
out[1] = ay + t * (b[1] - ay); |
|
out[2] = az + t * (b[2] - az); |
|
out[3] = aw + t * (b[3] - aw); |
|
return out; |
|
} |
|
|
|
/** |
|
* Generates a random vector with the given scale |
|
* |
|
* @param {vec4} out the receiving vector |
|
* @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned |
|
* @returns {vec4} out |
|
*/ |
|
function random(out, vectorScale) { |
|
vectorScale = vectorScale || 1.0; |
|
|
|
//TODO: This is a pretty awful way of doing this. Find something better. |
|
out[0] = __WEBPACK_IMPORTED_MODULE_0__common__["RANDOM"](); |
|
out[1] = __WEBPACK_IMPORTED_MODULE_0__common__["RANDOM"](); |
|
out[2] = __WEBPACK_IMPORTED_MODULE_0__common__["RANDOM"](); |
|
out[3] = __WEBPACK_IMPORTED_MODULE_0__common__["RANDOM"](); |
|
normalize(out, out); |
|
scale(out, out, vectorScale); |
|
return out; |
|
} |
|
|
|
/** |
|
* Transforms the vec4 with a mat4. |
|
* |
|
* @param {vec4} out the receiving vector |
|
* @param {vec4} a the vector to transform |
|
* @param {mat4} m matrix to transform with |
|
* @returns {vec4} out |
|
*/ |
|
function transformMat4(out, a, m) { |
|
let x = a[0], y = a[1], z = a[2], w = a[3]; |
|
out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w; |
|
out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w; |
|
out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w; |
|
out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w; |
|
return out; |
|
} |
|
|
|
/** |
|
* Transforms the vec4 with a quat |
|
* |
|
* @param {vec4} out the receiving vector |
|
* @param {vec4} a the vector to transform |
|
* @param {quat} q quaternion to transform with |
|
* @returns {vec4} out |
|
*/ |
|
function transformQuat(out, a, q) { |
|
let x = a[0], y = a[1], z = a[2]; |
|
let qx = q[0], qy = q[1], qz = q[2], qw = q[3]; |
|
|
|
// calculate quat * vec |
|
let ix = qw * x + qy * z - qz * y; |
|
let iy = qw * y + qz * x - qx * z; |
|
let iz = qw * z + qx * y - qy * x; |
|
let iw = -qx * x - qy * y - qz * z; |
|
|
|
// calculate result * inverse quat |
|
out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; |
|
out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; |
|
out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; |
|
out[3] = a[3]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Returns a string representation of a vector |
|
* |
|
* @param {vec4} a vector to represent as a string |
|
* @returns {String} string representation of the vector |
|
*/ |
|
function str(a) { |
|
return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; |
|
} |
|
|
|
/** |
|
* Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===) |
|
* |
|
* @param {vec4} a The first vector. |
|
* @param {vec4} b The second vector. |
|
* @returns {Boolean} True if the vectors are equal, false otherwise. |
|
*/ |
|
function exactEquals(a, b) { |
|
return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3]; |
|
} |
|
|
|
/** |
|
* Returns whether or not the vectors have approximately the same elements in the same position. |
|
* |
|
* @param {vec4} a The first vector. |
|
* @param {vec4} b The second vector. |
|
* @returns {Boolean} True if the vectors are equal, false otherwise. |
|
*/ |
|
function equals(a, b) { |
|
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; |
|
let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; |
|
return (Math.abs(a0 - b0) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a0), Math.abs(b0)) && |
|
Math.abs(a1 - b1) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a1), Math.abs(b1)) && |
|
Math.abs(a2 - b2) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a2), Math.abs(b2)) && |
|
Math.abs(a3 - b3) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a3), Math.abs(b3))); |
|
} |
|
|
|
/** |
|
* Alias for {@link vec4.subtract} |
|
* @function |
|
*/ |
|
const sub = subtract; |
|
/* harmony export (immutable) */ __webpack_exports__["sub"] = sub; |
|
|
|
|
|
/** |
|
* Alias for {@link vec4.multiply} |
|
* @function |
|
*/ |
|
const mul = multiply; |
|
/* harmony export (immutable) */ __webpack_exports__["mul"] = mul; |
|
|
|
|
|
/** |
|
* Alias for {@link vec4.divide} |
|
* @function |
|
*/ |
|
const div = divide; |
|
/* harmony export (immutable) */ __webpack_exports__["div"] = div; |
|
|
|
|
|
/** |
|
* Alias for {@link vec4.distance} |
|
* @function |
|
*/ |
|
const dist = distance; |
|
/* harmony export (immutable) */ __webpack_exports__["dist"] = dist; |
|
|
|
|
|
/** |
|
* Alias for {@link vec4.squaredDistance} |
|
* @function |
|
*/ |
|
const sqrDist = squaredDistance; |
|
/* harmony export (immutable) */ __webpack_exports__["sqrDist"] = sqrDist; |
|
|
|
|
|
/** |
|
* Alias for {@link vec4.length} |
|
* @function |
|
*/ |
|
const len = length; |
|
/* harmony export (immutable) */ __webpack_exports__["len"] = len; |
|
|
|
|
|
/** |
|
* Alias for {@link vec4.squaredLength} |
|
* @function |
|
*/ |
|
const sqrLen = squaredLength; |
|
/* harmony export (immutable) */ __webpack_exports__["sqrLen"] = sqrLen; |
|
|
|
|
|
/** |
|
* Perform some operation over an array of vec4s. |
|
* |
|
* @param {Array} a the array of vectors to iterate over |
|
* @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed |
|
* @param {Number} offset Number of elements to skip at the beginning of the array |
|
* @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array |
|
* @param {Function} fn Function to call for each vector in the array |
|
* @param {Object} [arg] additional argument to pass to fn |
|
* @returns {Array} a |
|
* @function |
|
*/ |
|
const forEach = (function() { |
|
let vec = create(); |
|
|
|
return function(a, stride, offset, count, fn, arg) { |
|
let i, l; |
|
if(!stride) { |
|
stride = 4; |
|
} |
|
|
|
if(!offset) { |
|
offset = 0; |
|
} |
|
|
|
if(count) { |
|
l = Math.min((count * stride) + offset, a.length); |
|
} else { |
|
l = a.length; |
|
} |
|
|
|
for(i = offset; i < l; i += stride) { |
|
vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3]; |
|
fn(vec, vec, arg); |
|
a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3]; |
|
} |
|
|
|
return a; |
|
}; |
|
})(); |
|
/* harmony export (immutable) */ __webpack_exports__["forEach"] = forEach; |
|
|
|
|
|
|
|
/***/ }), |
|
/* 5 */ |
|
/***/ (function(module, exports) { |
|
|
|
module.exports = identity; |
|
|
|
/** |
|
* Set a mat4 to the identity matrix |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @returns {mat4} out |
|
*/ |
|
function identity(out) { |
|
out[0] = 1; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 0; |
|
out[4] = 0; |
|
out[5] = 1; |
|
out[6] = 0; |
|
out[7] = 0; |
|
out[8] = 0; |
|
out[9] = 0; |
|
out[10] = 1; |
|
out[11] = 0; |
|
out[12] = 0; |
|
out[13] = 0; |
|
out[14] = 0; |
|
out[15] = 1; |
|
return out; |
|
}; |
|
|
|
/***/ }), |
|
/* 6 */ |
|
/***/ (function(module, exports, __webpack_require__) { |
|
|
|
const createRegl = __webpack_require__(46) |
|
const createCamera = __webpack_require__(9) |
|
const mat4 = __webpack_require__(31) |
|
const fit = __webpack_require__(7) |
|
|
|
window.createRegl = createRegl; |
|
window.createCamera = createCamera; |
|
window.mat4 = mat4; |
|
window.fit = fit; |
|
|
|
|
|
/***/ }), |
|
/* 7 */ |
|
/***/ (function(module, exports, __webpack_require__) { |
|
|
|
var size = __webpack_require__(8) |
|
|
|
module.exports = fit |
|
|
|
var scratch = new Float32Array(2) |
|
|
|
function fit(canvas, parent, scale) { |
|
var isSVG = canvas.nodeName.toUpperCase() === 'SVG' |
|
|
|
canvas.style.position = canvas.style.position || 'absolute' |
|
canvas.style.top = 0 |
|
canvas.style.left = 0 |
|
|
|
resize.scale = parseFloat(scale || 1) |
|
resize.parent = parent |
|
|
|
return resize() |
|
|
|
function resize() { |
|
var p = resize.parent || canvas.parentNode |
|
if (typeof p === 'function') { |
|
var dims = p(scratch) || scratch |
|
var width = dims[0] |
|
var height = dims[1] |
|
} else |
|
if (p && p !== document.body) { |
|
var psize = size(p) |
|
var width = psize[0]|0 |
|
var height = psize[1]|0 |
|
} else { |
|
var width = window.innerWidth |
|
var height = window.innerHeight |
|
} |
|
|
|
if (isSVG) { |
|
canvas.setAttribute('width', width * resize.scale + 'px') |
|
canvas.setAttribute('height', height * resize.scale + 'px') |
|
} else { |
|
canvas.width = width * resize.scale |
|
canvas.height = height * resize.scale |
|
} |
|
|
|
canvas.style.width = width + 'px' |
|
canvas.style.height = height + 'px' |
|
|
|
return resize |
|
} |
|
} |
|
|
|
|
|
/***/ }), |
|
/* 8 */ |
|
/***/ (function(module, exports) { |
|
|
|
module.exports = getSize |
|
|
|
function getSize(element) { |
|
// Handle cases where the element is not already |
|
// attached to the DOM by briefly appending it |
|
// to document.body, and removing it again later. |
|
if (element === window || element === document.body) { |
|
return [window.innerWidth, window.innerHeight] |
|
} |
|
|
|
if (!element.parentNode) { |
|
var temporary = true |
|
document.body.appendChild(element) |
|
} |
|
|
|
var bounds = element.getBoundingClientRect() |
|
var styles = getComputedStyle(element) |
|
var height = (bounds.height|0) |
|
+ parse(styles.getPropertyValue('margin-top')) |
|
+ parse(styles.getPropertyValue('margin-bottom')) |
|
var width = (bounds.width|0) |
|
+ parse(styles.getPropertyValue('margin-left')) |
|
+ parse(styles.getPropertyValue('margin-right')) |
|
|
|
if (temporary) { |
|
document.body.removeChild(element) |
|
} |
|
|
|
return [width, height] |
|
} |
|
|
|
function parse(prop) { |
|
return parseFloat(prop) || 0 |
|
} |
|
|
|
|
|
/***/ }), |
|
/* 9 */ |
|
/***/ (function(module, exports, __webpack_require__) { |
|
|
|
var createCamera = __webpack_require__(20) |
|
var createScroll = __webpack_require__(21) |
|
var mp = __webpack_require__(12) |
|
var mb = __webpack_require__(13) |
|
var key = __webpack_require__(10) |
|
|
|
var panSpeed = 1 |
|
|
|
module.exports = attachCamera |
|
|
|
function attachCamera(canvas, opts) { |
|
opts = opts || {} |
|
opts.pan = opts.pan !== false |
|
opts.scale = opts.scale !== false |
|
opts.rotate = opts.rotate !== false |
|
|
|
var scroll = createScroll(canvas, opts.scale) |
|
var mbut = mb(canvas, opts.rotate) |
|
var mpos = mp(canvas) |
|
var camera = createCamera( |
|
[0, 10, 30] |
|
, [0, 0, 0] |
|
, [0, 1, 0] |
|
) |
|
|
|
camera.tick = tick |
|
|
|
return camera |
|
|
|
function tick() { |
|
var ctrl = key('<control>') || key('<alt>') |
|
var alt = key('<shift>') |
|
var height = canvas.height |
|
var width = canvas.width |
|
|
|
if (opts.rotate && mbut.left && !ctrl && !alt) { |
|
camera.rotate( |
|
[ mpos.x / width - 0.5, mpos.y / height - 0.5 ] |
|
, [ mpos.prevX / width - 0.5, mpos.prevY / height - 0.5 ] |
|
) |
|
} |
|
|
|
if (opts.pan && mbut.right || (mbut.left && ctrl && !alt)) { |
|
camera.pan([ |
|
panSpeed * (mpos.x - mpos.prevX) / width |
|
, panSpeed * (mpos.y - mpos.prevY) / height |
|
]) |
|
} |
|
|
|
if (opts.scale && scroll[1]) { |
|
camera.distance *= Math.exp(scroll[1] / height) |
|
} |
|
|
|
if (opts.scale && (mbut.middle || (mbut.left && !ctrl && alt))) { |
|
var d = mpos.y - mpos.prevY |
|
if (!d) return; |
|
|
|
camera.distance *= Math.exp(d / height) |
|
} |
|
|
|
scroll.flush() |
|
mpos.flush() |
|
} |
|
} |
|
|
|
|
|
/***/ }), |
|
/* 10 */ |
|
/***/ (function(module, exports, __webpack_require__) { |
|
|
|
/* WEBPACK VAR INJECTION */(function(process) {var keys = __webpack_require__(11) |
|
var list = Object.keys(keys) |
|
var down = {} |
|
|
|
reset() |
|
|
|
module.exports = pressed |
|
|
|
if (process.browser) { |
|
window.addEventListener('keydown', keydown, false) |
|
window.addEventListener('keyup', keyup, false) |
|
window.addEventListener('blur', reset, false) |
|
} |
|
|
|
function pressed(key) { |
|
return key |
|
? down[key] |
|
: down |
|
} |
|
|
|
function reset() { |
|
list.forEach(function(code) { |
|
down[keys[code]] = false |
|
}) |
|
} |
|
|
|
function keyup(e) { |
|
down[keys[e.keyCode]] = false |
|
} |
|
|
|
function keydown(e) { |
|
down[keys[e.keyCode]] = true |
|
} |
|
|
|
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(47))) |
|
|
|
/***/ }), |
|
/* 11 */ |
|
/***/ (function(module, exports) { |
|
|
|
var ua = typeof window !== 'undefined' ? window.navigator.userAgent : '' |
|
, isOSX = /OS X/.test(ua) |
|
, isOpera = /Opera/.test(ua) |
|
, maybeFirefox = !/like Gecko/.test(ua) && !isOpera |
|
|
|
var i, output = module.exports = { |
|
0: isOSX ? '<menu>' : '<UNK>' |
|
, 1: '<mouse 1>' |
|
, 2: '<mouse 2>' |
|
, 3: '<break>' |
|
, 4: '<mouse 3>' |
|
, 5: '<mouse 4>' |
|
, 6: '<mouse 5>' |
|
, 8: '<backspace>' |
|
, 9: '<tab>' |
|
, 12: '<clear>' |
|
, 13: '<enter>' |
|
, 16: '<shift>' |
|
, 17: '<control>' |
|
, 18: '<alt>' |
|
, 19: '<pause>' |
|
, 20: '<caps-lock>' |
|
, 21: '<ime-hangul>' |
|
, 23: '<ime-junja>' |
|
, 24: '<ime-final>' |
|
, 25: '<ime-kanji>' |
|
, 27: '<escape>' |
|
, 28: '<ime-convert>' |
|
, 29: '<ime-nonconvert>' |
|
, 30: '<ime-accept>' |
|
, 31: '<ime-mode-change>' |
|
, 27: '<escape>' |
|
, 32: '<space>' |
|
, 33: '<page-up>' |
|
, 34: '<page-down>' |
|
, 35: '<end>' |
|
, 36: '<home>' |
|
, 37: '<left>' |
|
, 38: '<up>' |
|
, 39: '<right>' |
|
, 40: '<down>' |
|
, 41: '<select>' |
|
, 42: '<print>' |
|
, 43: '<execute>' |
|
, 44: '<snapshot>' |
|
, 45: '<insert>' |
|
, 46: '<delete>' |
|
, 47: '<help>' |
|
, 91: '<meta>' // meta-left -- no one handles left and right properly, so we coerce into one. |
|
, 92: '<meta>' // meta-right |
|
, 93: isOSX ? '<meta>' : '<menu>' // chrome,opera,safari all report this for meta-right (osx mbp). |
|
, 95: '<sleep>' |
|
, 106: '<num-*>' |
|
, 107: '<num-+>' |
|
, 108: '<num-enter>' |
|
, 109: '<num-->' |
|
, 110: '<num-.>' |
|
, 111: '<num-/>' |
|
, 144: '<num-lock>' |
|
, 145: '<scroll-lock>' |
|
, 160: '<shift-left>' |
|
, 161: '<shift-right>' |
|
, 162: '<control-left>' |
|
, 163: '<control-right>' |
|
, 164: '<alt-left>' |
|
, 165: '<alt-right>' |
|
, 166: '<browser-back>' |
|
, 167: '<browser-forward>' |
|
, 168: '<browser-refresh>' |
|
, 169: '<browser-stop>' |
|
, 170: '<browser-search>' |
|
, 171: '<browser-favorites>' |
|
, 172: '<browser-home>' |
|
|
|
// ff/osx reports '<volume-mute>' for '-' |
|
, 173: isOSX && maybeFirefox ? '-' : '<volume-mute>' |
|
, 174: '<volume-down>' |
|
, 175: '<volume-up>' |
|
, 176: '<next-track>' |
|
, 177: '<prev-track>' |
|
, 178: '<stop>' |
|
, 179: '<play-pause>' |
|
, 180: '<launch-mail>' |
|
, 181: '<launch-media-select>' |
|
, 182: '<launch-app 1>' |
|
, 183: '<launch-app 2>' |
|
, 186: ';' |
|
, 187: '=' |
|
, 188: ',' |
|
, 189: '-' |
|
, 190: '.' |
|
, 191: '/' |
|
, 192: '`' |
|
, 219: '[' |
|
, 220: '\\' |
|
, 221: ']' |
|
, 222: "'" |
|
, 223: '<meta>' |
|
, 224: '<meta>' // firefox reports meta here. |
|
, 226: '<alt-gr>' |
|
, 229: '<ime-process>' |
|
, 231: isOpera ? '`' : '<unicode>' |
|
, 246: '<attention>' |
|
, 247: '<crsel>' |
|
, 248: '<exsel>' |
|
, 249: '<erase-eof>' |
|
, 250: '<play>' |
|
, 251: '<zoom>' |
|
, 252: '<no-name>' |
|
, 253: '<pa-1>' |
|
, 254: '<clear>' |
|
} |
|
|
|
for(i = 58; i < 65; ++i) { |
|
output[i] = String.fromCharCode(i) |
|
} |
|
|
|
// 0-9 |
|
for(i = 48; i < 58; ++i) { |
|
output[i] = (i - 48)+'' |
|
} |
|
|
|
// A-Z |
|
for(i = 65; i < 91; ++i) { |
|
output[i] = String.fromCharCode(i) |
|
} |
|
|
|
// num0-9 |
|
for(i = 96; i < 106; ++i) { |
|
output[i] = '<num-'+(i - 96)+'>' |
|
} |
|
|
|
// F1-F24 |
|
for(i = 112; i < 136; ++i) { |
|
output[i] = 'F'+(i-111) |
|
} |
|
|
|
|
|
/***/ }), |
|
/* 12 */ |
|
/***/ (function(module, exports, __webpack_require__) { |
|
|
|
var Emitter = __webpack_require__(1) |
|
|
|
module.exports = attach |
|
|
|
function attach(element, listener) { |
|
var position = new Emitter |
|
|
|
position.x = 0 |
|
position.y = 0 |
|
position.prevX = 0 |
|
position.prevY = 0 |
|
position.flush = flush |
|
|
|
if (typeof window === 'undefined') { |
|
return position |
|
} |
|
|
|
listener = listener || element || window |
|
element = element || document.body |
|
listener.addEventListener('mousemove', ( |
|
element === document.body |
|
|| element === window |
|
) ? function(e) { |
|
position.prevX = position.x |
|
position.prevY = position.y |
|
position.x = e.clientX |
|
position.y = e.clientY |
|
position.emit('move', e) |
|
} |
|
: function(e) { |
|
position.prevX = position.x |
|
position.prevY = position.y |
|
var bounds = element.getBoundingClientRect() |
|
position.x = e.clientX - bounds.left |
|
position.y = e.clientY - bounds.top |
|
position.emit('move', e) |
|
} |
|
, false) |
|
|
|
return position |
|
|
|
function flush() { |
|
this.prevX = this.x |
|
this.prevY = this.y |
|
} |
|
} |
|
|
|
|
|
/***/ }), |
|
/* 13 */ |
|
/***/ (function(module, exports, __webpack_require__) { |
|
|
|
var Emitter = __webpack_require__(1) |
|
var map = [ |
|
'left' |
|
, 'middle' |
|
, 'right' |
|
] |
|
|
|
module.exports = pressed |
|
|
|
function pressed(element, preventDefault) { |
|
var mouse = new Emitter |
|
|
|
mouse.left = false |
|
mouse.right = false |
|
mouse.middle = false |
|
|
|
if (typeof window !== 'undefined') { |
|
element = element || window |
|
element.addEventListener('mousedown', mousedown, false) |
|
element.addEventListener('mouseup', mouseup, false) |
|
|
|
if (preventDefault) { |
|
element.addEventListener('contextmenu', function(e) { |
|
return e.preventDefault && e.preventDefault() && false |
|
}, false) |
|
} |
|
} |
|
|
|
return mouse |
|
|
|
function mousedown(e) { |
|
mouse.right = false |
|
mouse[map[e.button]] = true |
|
mouse.emit('down', e) |
|
|
|
if (!preventDefault) return |
|
if (!e.preventDefault) return false |
|
e.preventDefault() |
|
e.stopPropagation() |
|
} |
|
|
|
function mouseup(e) { |
|
mouse.right = false |
|
mouse[map[e.button]] = false |
|
mouse.emit('up', e) |
|
|
|
if (!preventDefault) return |
|
if (!e.preventDefault) return |
|
e.preventDefault() |
|
e.stopPropagation() |
|
} |
|
} |
|
|
|
|
|
/***/ }), |
|
/* 14 */ |
|
/***/ (function(module, __webpack_exports__, __webpack_require__) { |
|
|
|
"use strict"; |
|
Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); |
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__gl_matrix_common__ = __webpack_require__(0); |
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__gl_matrix_mat2__ = __webpack_require__(15); |
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__gl_matrix_mat2d__ = __webpack_require__(16); |
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__gl_matrix_mat3__ = __webpack_require__(2); |
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__gl_matrix_mat4__ = __webpack_require__(17); |
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__gl_matrix_quat__ = __webpack_require__(18); |
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__gl_matrix_vec2__ = __webpack_require__(19); |
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__gl_matrix_vec3__ = __webpack_require__(3); |
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__gl_matrix_vec4__ = __webpack_require__(4); |
|
/* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "glMatrix", function() { return __WEBPACK_IMPORTED_MODULE_0__gl_matrix_common__; }); |
|
/* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "mat2", function() { return __WEBPACK_IMPORTED_MODULE_1__gl_matrix_mat2__; }); |
|
/* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "mat2d", function() { return __WEBPACK_IMPORTED_MODULE_2__gl_matrix_mat2d__; }); |
|
/* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "mat3", function() { return __WEBPACK_IMPORTED_MODULE_3__gl_matrix_mat3__; }); |
|
/* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "mat4", function() { return __WEBPACK_IMPORTED_MODULE_4__gl_matrix_mat4__; }); |
|
/* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "quat", function() { return __WEBPACK_IMPORTED_MODULE_5__gl_matrix_quat__; }); |
|
/* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "vec2", function() { return __WEBPACK_IMPORTED_MODULE_6__gl_matrix_vec2__; }); |
|
/* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "vec3", function() { return __WEBPACK_IMPORTED_MODULE_7__gl_matrix_vec3__; }); |
|
/* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "vec4", function() { return __WEBPACK_IMPORTED_MODULE_8__gl_matrix_vec4__; }); |
|
/** |
|
* @fileoverview gl-matrix - High performance matrix and vector operations |
|
* @author Brandon Jones |
|
* @author Colin MacKenzie IV |
|
* @version 2.4.0 |
|
*/ |
|
|
|
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. |
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
|
of this software and associated documentation files (the "Software"), to deal |
|
in the Software without restriction, including without limitation the rights |
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
copies of the Software, and to permit persons to whom the Software is |
|
furnished to do so, subject to the following conditions: |
|
|
|
The above copyright notice and this permission notice shall be included in |
|
all copies or substantial portions of the Software. |
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
THE SOFTWARE. */ |
|
// END HEADER |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***/ }), |
|
/* 15 */ |
|
/***/ (function(module, __webpack_exports__, __webpack_require__) { |
|
|
|
"use strict"; |
|
Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); |
|
/* harmony export (immutable) */ __webpack_exports__["create"] = create; |
|
/* harmony export (immutable) */ __webpack_exports__["clone"] = clone; |
|
/* harmony export (immutable) */ __webpack_exports__["copy"] = copy; |
|
/* harmony export (immutable) */ __webpack_exports__["identity"] = identity; |
|
/* harmony export (immutable) */ __webpack_exports__["fromValues"] = fromValues; |
|
/* harmony export (immutable) */ __webpack_exports__["set"] = set; |
|
/* harmony export (immutable) */ __webpack_exports__["transpose"] = transpose; |
|
/* harmony export (immutable) */ __webpack_exports__["invert"] = invert; |
|
/* harmony export (immutable) */ __webpack_exports__["adjoint"] = adjoint; |
|
/* harmony export (immutable) */ __webpack_exports__["determinant"] = determinant; |
|
/* harmony export (immutable) */ __webpack_exports__["multiply"] = multiply; |
|
/* harmony export (immutable) */ __webpack_exports__["rotate"] = rotate; |
|
/* harmony export (immutable) */ __webpack_exports__["scale"] = scale; |
|
/* harmony export (immutable) */ __webpack_exports__["fromRotation"] = fromRotation; |
|
/* harmony export (immutable) */ __webpack_exports__["fromScaling"] = fromScaling; |
|
/* harmony export (immutable) */ __webpack_exports__["str"] = str; |
|
/* harmony export (immutable) */ __webpack_exports__["frob"] = frob; |
|
/* harmony export (immutable) */ __webpack_exports__["LDU"] = LDU; |
|
/* harmony export (immutable) */ __webpack_exports__["add"] = add; |
|
/* harmony export (immutable) */ __webpack_exports__["subtract"] = subtract; |
|
/* harmony export (immutable) */ __webpack_exports__["exactEquals"] = exactEquals; |
|
/* harmony export (immutable) */ __webpack_exports__["equals"] = equals; |
|
/* harmony export (immutable) */ __webpack_exports__["multiplyScalar"] = multiplyScalar; |
|
/* harmony export (immutable) */ __webpack_exports__["multiplyScalarAndAdd"] = multiplyScalarAndAdd; |
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__common__ = __webpack_require__(0); |
|
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. |
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
|
of this software and associated documentation files (the "Software"), to deal |
|
in the Software without restriction, including without limitation the rights |
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
copies of the Software, and to permit persons to whom the Software is |
|
furnished to do so, subject to the following conditions: |
|
|
|
The above copyright notice and this permission notice shall be included in |
|
all copies or substantial portions of the Software. |
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
THE SOFTWARE. */ |
|
|
|
|
|
|
|
/** |
|
* 2x2 Matrix |
|
* @module mat2 |
|
*/ |
|
|
|
/** |
|
* Creates a new identity mat2 |
|
* |
|
* @returns {mat2} a new 2x2 matrix |
|
*/ |
|
function create() { |
|
let out = new __WEBPACK_IMPORTED_MODULE_0__common__["ARRAY_TYPE"](4); |
|
out[0] = 1; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 1; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a new mat2 initialized with values from an existing matrix |
|
* |
|
* @param {mat2} a matrix to clone |
|
* @returns {mat2} a new 2x2 matrix |
|
*/ |
|
function clone(a) { |
|
let out = new __WEBPACK_IMPORTED_MODULE_0__common__["ARRAY_TYPE"](4); |
|
out[0] = a[0]; |
|
out[1] = a[1]; |
|
out[2] = a[2]; |
|
out[3] = a[3]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Copy the values from one mat2 to another |
|
* |
|
* @param {mat2} out the receiving matrix |
|
* @param {mat2} a the source matrix |
|
* @returns {mat2} out |
|
*/ |
|
function copy(out, a) { |
|
out[0] = a[0]; |
|
out[1] = a[1]; |
|
out[2] = a[2]; |
|
out[3] = a[3]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Set a mat2 to the identity matrix |
|
* |
|
* @param {mat2} out the receiving matrix |
|
* @returns {mat2} out |
|
*/ |
|
function identity(out) { |
|
out[0] = 1; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 1; |
|
return out; |
|
} |
|
|
|
/** |
|
* Create a new mat2 with the given values |
|
* |
|
* @param {Number} m00 Component in column 0, row 0 position (index 0) |
|
* @param {Number} m01 Component in column 0, row 1 position (index 1) |
|
* @param {Number} m10 Component in column 1, row 0 position (index 2) |
|
* @param {Number} m11 Component in column 1, row 1 position (index 3) |
|
* @returns {mat2} out A new 2x2 matrix |
|
*/ |
|
function fromValues(m00, m01, m10, m11) { |
|
let out = new __WEBPACK_IMPORTED_MODULE_0__common__["ARRAY_TYPE"](4); |
|
out[0] = m00; |
|
out[1] = m01; |
|
out[2] = m10; |
|
out[3] = m11; |
|
return out; |
|
} |
|
|
|
/** |
|
* Set the components of a mat2 to the given values |
|
* |
|
* @param {mat2} out the receiving matrix |
|
* @param {Number} m00 Component in column 0, row 0 position (index 0) |
|
* @param {Number} m01 Component in column 0, row 1 position (index 1) |
|
* @param {Number} m10 Component in column 1, row 0 position (index 2) |
|
* @param {Number} m11 Component in column 1, row 1 position (index 3) |
|
* @returns {mat2} out |
|
*/ |
|
function set(out, m00, m01, m10, m11) { |
|
out[0] = m00; |
|
out[1] = m01; |
|
out[2] = m10; |
|
out[3] = m11; |
|
return out; |
|
} |
|
|
|
/** |
|
* Transpose the values of a mat2 |
|
* |
|
* @param {mat2} out the receiving matrix |
|
* @param {mat2} a the source matrix |
|
* @returns {mat2} out |
|
*/ |
|
function transpose(out, a) { |
|
// If we are transposing ourselves we can skip a few steps but have to cache |
|
// some values |
|
if (out === a) { |
|
let a1 = a[1]; |
|
out[1] = a[2]; |
|
out[2] = a1; |
|
} else { |
|
out[0] = a[0]; |
|
out[1] = a[2]; |
|
out[2] = a[1]; |
|
out[3] = a[3]; |
|
} |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Inverts a mat2 |
|
* |
|
* @param {mat2} out the receiving matrix |
|
* @param {mat2} a the source matrix |
|
* @returns {mat2} out |
|
*/ |
|
function invert(out, a) { |
|
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; |
|
|
|
// Calculate the determinant |
|
let det = a0 * a3 - a2 * a1; |
|
|
|
if (!det) { |
|
return null; |
|
} |
|
det = 1.0 / det; |
|
|
|
out[0] = a3 * det; |
|
out[1] = -a1 * det; |
|
out[2] = -a2 * det; |
|
out[3] = a0 * det; |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Calculates the adjugate of a mat2 |
|
* |
|
* @param {mat2} out the receiving matrix |
|
* @param {mat2} a the source matrix |
|
* @returns {mat2} out |
|
*/ |
|
function adjoint(out, a) { |
|
// Caching this value is nessecary if out == a |
|
let a0 = a[0]; |
|
out[0] = a[3]; |
|
out[1] = -a[1]; |
|
out[2] = -a[2]; |
|
out[3] = a0; |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Calculates the determinant of a mat2 |
|
* |
|
* @param {mat2} a the source matrix |
|
* @returns {Number} determinant of a |
|
*/ |
|
function determinant(a) { |
|
return a[0] * a[3] - a[2] * a[1]; |
|
} |
|
|
|
/** |
|
* Multiplies two mat2's |
|
* |
|
* @param {mat2} out the receiving matrix |
|
* @param {mat2} a the first operand |
|
* @param {mat2} b the second operand |
|
* @returns {mat2} out |
|
*/ |
|
function multiply(out, a, b) { |
|
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; |
|
let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; |
|
out[0] = a0 * b0 + a2 * b1; |
|
out[1] = a1 * b0 + a3 * b1; |
|
out[2] = a0 * b2 + a2 * b3; |
|
out[3] = a1 * b2 + a3 * b3; |
|
return out; |
|
} |
|
|
|
/** |
|
* Rotates a mat2 by the given angle |
|
* |
|
* @param {mat2} out the receiving matrix |
|
* @param {mat2} a the matrix to rotate |
|
* @param {Number} rad the angle to rotate the matrix by |
|
* @returns {mat2} out |
|
*/ |
|
function rotate(out, a, rad) { |
|
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; |
|
let s = Math.sin(rad); |
|
let c = Math.cos(rad); |
|
out[0] = a0 * c + a2 * s; |
|
out[1] = a1 * c + a3 * s; |
|
out[2] = a0 * -s + a2 * c; |
|
out[3] = a1 * -s + a3 * c; |
|
return out; |
|
} |
|
|
|
/** |
|
* Scales the mat2 by the dimensions in the given vec2 |
|
* |
|
* @param {mat2} out the receiving matrix |
|
* @param {mat2} a the matrix to rotate |
|
* @param {vec2} v the vec2 to scale the matrix by |
|
* @returns {mat2} out |
|
**/ |
|
function scale(out, a, v) { |
|
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; |
|
let v0 = v[0], v1 = v[1]; |
|
out[0] = a0 * v0; |
|
out[1] = a1 * v0; |
|
out[2] = a2 * v1; |
|
out[3] = a3 * v1; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a matrix from a given angle |
|
* This is equivalent to (but much faster than): |
|
* |
|
* mat2.identity(dest); |
|
* mat2.rotate(dest, dest, rad); |
|
* |
|
* @param {mat2} out mat2 receiving operation result |
|
* @param {Number} rad the angle to rotate the matrix by |
|
* @returns {mat2} out |
|
*/ |
|
function fromRotation(out, rad) { |
|
let s = Math.sin(rad); |
|
let c = Math.cos(rad); |
|
out[0] = c; |
|
out[1] = s; |
|
out[2] = -s; |
|
out[3] = c; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a matrix from a vector scaling |
|
* This is equivalent to (but much faster than): |
|
* |
|
* mat2.identity(dest); |
|
* mat2.scale(dest, dest, vec); |
|
* |
|
* @param {mat2} out mat2 receiving operation result |
|
* @param {vec2} v Scaling vector |
|
* @returns {mat2} out |
|
*/ |
|
function fromScaling(out, v) { |
|
out[0] = v[0]; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = v[1]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Returns a string representation of a mat2 |
|
* |
|
* @param {mat2} a matrix to represent as a string |
|
* @returns {String} string representation of the matrix |
|
*/ |
|
function str(a) { |
|
return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; |
|
} |
|
|
|
/** |
|
* Returns Frobenius norm of a mat2 |
|
* |
|
* @param {mat2} a the matrix to calculate Frobenius norm of |
|
* @returns {Number} Frobenius norm |
|
*/ |
|
function frob(a) { |
|
return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2))) |
|
} |
|
|
|
/** |
|
* Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix |
|
* @param {mat2} L the lower triangular matrix |
|
* @param {mat2} D the diagonal matrix |
|
* @param {mat2} U the upper triangular matrix |
|
* @param {mat2} a the input matrix to factorize |
|
*/ |
|
|
|
function LDU(L, D, U, a) { |
|
L[2] = a[2]/a[0]; |
|
U[0] = a[0]; |
|
U[1] = a[1]; |
|
U[3] = a[3] - L[2] * U[1]; |
|
return [L, D, U]; |
|
} |
|
|
|
/** |
|
* Adds two mat2's |
|
* |
|
* @param {mat2} out the receiving matrix |
|
* @param {mat2} a the first operand |
|
* @param {mat2} b the second operand |
|
* @returns {mat2} out |
|
*/ |
|
function add(out, a, b) { |
|
out[0] = a[0] + b[0]; |
|
out[1] = a[1] + b[1]; |
|
out[2] = a[2] + b[2]; |
|
out[3] = a[3] + b[3]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Subtracts matrix b from matrix a |
|
* |
|
* @param {mat2} out the receiving matrix |
|
* @param {mat2} a the first operand |
|
* @param {mat2} b the second operand |
|
* @returns {mat2} out |
|
*/ |
|
function subtract(out, a, b) { |
|
out[0] = a[0] - b[0]; |
|
out[1] = a[1] - b[1]; |
|
out[2] = a[2] - b[2]; |
|
out[3] = a[3] - b[3]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===) |
|
* |
|
* @param {mat2} a The first matrix. |
|
* @param {mat2} b The second matrix. |
|
* @returns {Boolean} True if the matrices are equal, false otherwise. |
|
*/ |
|
function exactEquals(a, b) { |
|
return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3]; |
|
} |
|
|
|
/** |
|
* Returns whether or not the matrices have approximately the same elements in the same position. |
|
* |
|
* @param {mat2} a The first matrix. |
|
* @param {mat2} b The second matrix. |
|
* @returns {Boolean} True if the matrices are equal, false otherwise. |
|
*/ |
|
function equals(a, b) { |
|
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; |
|
let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; |
|
return (Math.abs(a0 - b0) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a0), Math.abs(b0)) && |
|
Math.abs(a1 - b1) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a1), Math.abs(b1)) && |
|
Math.abs(a2 - b2) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a2), Math.abs(b2)) && |
|
Math.abs(a3 - b3) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a3), Math.abs(b3))); |
|
} |
|
|
|
/** |
|
* Multiply each element of the matrix by a scalar. |
|
* |
|
* @param {mat2} out the receiving matrix |
|
* @param {mat2} a the matrix to scale |
|
* @param {Number} b amount to scale the matrix's elements by |
|
* @returns {mat2} out |
|
*/ |
|
function multiplyScalar(out, a, b) { |
|
out[0] = a[0] * b; |
|
out[1] = a[1] * b; |
|
out[2] = a[2] * b; |
|
out[3] = a[3] * b; |
|
return out; |
|
} |
|
|
|
/** |
|
* Adds two mat2's after multiplying each element of the second operand by a scalar value. |
|
* |
|
* @param {mat2} out the receiving vector |
|
* @param {mat2} a the first operand |
|
* @param {mat2} b the second operand |
|
* @param {Number} scale the amount to scale b's elements by before adding |
|
* @returns {mat2} out |
|
*/ |
|
function multiplyScalarAndAdd(out, a, b, scale) { |
|
out[0] = a[0] + (b[0] * scale); |
|
out[1] = a[1] + (b[1] * scale); |
|
out[2] = a[2] + (b[2] * scale); |
|
out[3] = a[3] + (b[3] * scale); |
|
return out; |
|
} |
|
|
|
/** |
|
* Alias for {@link mat2.multiply} |
|
* @function |
|
*/ |
|
const mul = multiply; |
|
/* harmony export (immutable) */ __webpack_exports__["mul"] = mul; |
|
|
|
|
|
/** |
|
* Alias for {@link mat2.subtract} |
|
* @function |
|
*/ |
|
const sub = subtract; |
|
/* harmony export (immutable) */ __webpack_exports__["sub"] = sub; |
|
|
|
|
|
|
|
/***/ }), |
|
/* 16 */ |
|
/***/ (function(module, __webpack_exports__, __webpack_require__) { |
|
|
|
"use strict"; |
|
Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); |
|
/* harmony export (immutable) */ __webpack_exports__["create"] = create; |
|
/* harmony export (immutable) */ __webpack_exports__["clone"] = clone; |
|
/* harmony export (immutable) */ __webpack_exports__["copy"] = copy; |
|
/* harmony export (immutable) */ __webpack_exports__["identity"] = identity; |
|
/* harmony export (immutable) */ __webpack_exports__["fromValues"] = fromValues; |
|
/* harmony export (immutable) */ __webpack_exports__["set"] = set; |
|
/* harmony export (immutable) */ __webpack_exports__["invert"] = invert; |
|
/* harmony export (immutable) */ __webpack_exports__["determinant"] = determinant; |
|
/* harmony export (immutable) */ __webpack_exports__["multiply"] = multiply; |
|
/* harmony export (immutable) */ __webpack_exports__["rotate"] = rotate; |
|
/* harmony export (immutable) */ __webpack_exports__["scale"] = scale; |
|
/* harmony export (immutable) */ __webpack_exports__["translate"] = translate; |
|
/* harmony export (immutable) */ __webpack_exports__["fromRotation"] = fromRotation; |
|
/* harmony export (immutable) */ __webpack_exports__["fromScaling"] = fromScaling; |
|
/* harmony export (immutable) */ __webpack_exports__["fromTranslation"] = fromTranslation; |
|
/* harmony export (immutable) */ __webpack_exports__["str"] = str; |
|
/* harmony export (immutable) */ __webpack_exports__["frob"] = frob; |
|
/* harmony export (immutable) */ __webpack_exports__["add"] = add; |
|
/* harmony export (immutable) */ __webpack_exports__["subtract"] = subtract; |
|
/* harmony export (immutable) */ __webpack_exports__["multiplyScalar"] = multiplyScalar; |
|
/* harmony export (immutable) */ __webpack_exports__["multiplyScalarAndAdd"] = multiplyScalarAndAdd; |
|
/* harmony export (immutable) */ __webpack_exports__["exactEquals"] = exactEquals; |
|
/* harmony export (immutable) */ __webpack_exports__["equals"] = equals; |
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__common__ = __webpack_require__(0); |
|
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. |
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
|
of this software and associated documentation files (the "Software"), to deal |
|
in the Software without restriction, including without limitation the rights |
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
copies of the Software, and to permit persons to whom the Software is |
|
furnished to do so, subject to the following conditions: |
|
|
|
The above copyright notice and this permission notice shall be included in |
|
all copies or substantial portions of the Software. |
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
THE SOFTWARE. */ |
|
|
|
|
|
|
|
/** |
|
* 2x3 Matrix |
|
* @module mat2d |
|
* |
|
* @description |
|
* A mat2d contains six elements defined as: |
|
* <pre> |
|
* [a, c, tx, |
|
* b, d, ty] |
|
* </pre> |
|
* This is a short form for the 3x3 matrix: |
|
* <pre> |
|
* [a, c, tx, |
|
* b, d, ty, |
|
* 0, 0, 1] |
|
* </pre> |
|
* The last row is ignored so the array is shorter and operations are faster. |
|
*/ |
|
|
|
/** |
|
* Creates a new identity mat2d |
|
* |
|
* @returns {mat2d} a new 2x3 matrix |
|
*/ |
|
function create() { |
|
let out = new __WEBPACK_IMPORTED_MODULE_0__common__["ARRAY_TYPE"](6); |
|
out[0] = 1; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 1; |
|
out[4] = 0; |
|
out[5] = 0; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a new mat2d initialized with values from an existing matrix |
|
* |
|
* @param {mat2d} a matrix to clone |
|
* @returns {mat2d} a new 2x3 matrix |
|
*/ |
|
function clone(a) { |
|
let out = new __WEBPACK_IMPORTED_MODULE_0__common__["ARRAY_TYPE"](6); |
|
out[0] = a[0]; |
|
out[1] = a[1]; |
|
out[2] = a[2]; |
|
out[3] = a[3]; |
|
out[4] = a[4]; |
|
out[5] = a[5]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Copy the values from one mat2d to another |
|
* |
|
* @param {mat2d} out the receiving matrix |
|
* @param {mat2d} a the source matrix |
|
* @returns {mat2d} out |
|
*/ |
|
function copy(out, a) { |
|
out[0] = a[0]; |
|
out[1] = a[1]; |
|
out[2] = a[2]; |
|
out[3] = a[3]; |
|
out[4] = a[4]; |
|
out[5] = a[5]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Set a mat2d to the identity matrix |
|
* |
|
* @param {mat2d} out the receiving matrix |
|
* @returns {mat2d} out |
|
*/ |
|
function identity(out) { |
|
out[0] = 1; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 1; |
|
out[4] = 0; |
|
out[5] = 0; |
|
return out; |
|
} |
|
|
|
/** |
|
* Create a new mat2d with the given values |
|
* |
|
* @param {Number} a Component A (index 0) |
|
* @param {Number} b Component B (index 1) |
|
* @param {Number} c Component C (index 2) |
|
* @param {Number} d Component D (index 3) |
|
* @param {Number} tx Component TX (index 4) |
|
* @param {Number} ty Component TY (index 5) |
|
* @returns {mat2d} A new mat2d |
|
*/ |
|
function fromValues(a, b, c, d, tx, ty) { |
|
let out = new __WEBPACK_IMPORTED_MODULE_0__common__["ARRAY_TYPE"](6); |
|
out[0] = a; |
|
out[1] = b; |
|
out[2] = c; |
|
out[3] = d; |
|
out[4] = tx; |
|
out[5] = ty; |
|
return out; |
|
} |
|
|
|
/** |
|
* Set the components of a mat2d to the given values |
|
* |
|
* @param {mat2d} out the receiving matrix |
|
* @param {Number} a Component A (index 0) |
|
* @param {Number} b Component B (index 1) |
|
* @param {Number} c Component C (index 2) |
|
* @param {Number} d Component D (index 3) |
|
* @param {Number} tx Component TX (index 4) |
|
* @param {Number} ty Component TY (index 5) |
|
* @returns {mat2d} out |
|
*/ |
|
function set(out, a, b, c, d, tx, ty) { |
|
out[0] = a; |
|
out[1] = b; |
|
out[2] = c; |
|
out[3] = d; |
|
out[4] = tx; |
|
out[5] = ty; |
|
return out; |
|
} |
|
|
|
/** |
|
* Inverts a mat2d |
|
* |
|
* @param {mat2d} out the receiving matrix |
|
* @param {mat2d} a the source matrix |
|
* @returns {mat2d} out |
|
*/ |
|
function invert(out, a) { |
|
let aa = a[0], ab = a[1], ac = a[2], ad = a[3]; |
|
let atx = a[4], aty = a[5]; |
|
|
|
let det = aa * ad - ab * ac; |
|
if(!det){ |
|
return null; |
|
} |
|
det = 1.0 / det; |
|
|
|
out[0] = ad * det; |
|
out[1] = -ab * det; |
|
out[2] = -ac * det; |
|
out[3] = aa * det; |
|
out[4] = (ac * aty - ad * atx) * det; |
|
out[5] = (ab * atx - aa * aty) * det; |
|
return out; |
|
} |
|
|
|
/** |
|
* Calculates the determinant of a mat2d |
|
* |
|
* @param {mat2d} a the source matrix |
|
* @returns {Number} determinant of a |
|
*/ |
|
function determinant(a) { |
|
return a[0] * a[3] - a[1] * a[2]; |
|
} |
|
|
|
/** |
|
* Multiplies two mat2d's |
|
* |
|
* @param {mat2d} out the receiving matrix |
|
* @param {mat2d} a the first operand |
|
* @param {mat2d} b the second operand |
|
* @returns {mat2d} out |
|
*/ |
|
function multiply(out, a, b) { |
|
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5]; |
|
let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5]; |
|
out[0] = a0 * b0 + a2 * b1; |
|
out[1] = a1 * b0 + a3 * b1; |
|
out[2] = a0 * b2 + a2 * b3; |
|
out[3] = a1 * b2 + a3 * b3; |
|
out[4] = a0 * b4 + a2 * b5 + a4; |
|
out[5] = a1 * b4 + a3 * b5 + a5; |
|
return out; |
|
} |
|
|
|
/** |
|
* Rotates a mat2d by the given angle |
|
* |
|
* @param {mat2d} out the receiving matrix |
|
* @param {mat2d} a the matrix to rotate |
|
* @param {Number} rad the angle to rotate the matrix by |
|
* @returns {mat2d} out |
|
*/ |
|
function rotate(out, a, rad) { |
|
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5]; |
|
let s = Math.sin(rad); |
|
let c = Math.cos(rad); |
|
out[0] = a0 * c + a2 * s; |
|
out[1] = a1 * c + a3 * s; |
|
out[2] = a0 * -s + a2 * c; |
|
out[3] = a1 * -s + a3 * c; |
|
out[4] = a4; |
|
out[5] = a5; |
|
return out; |
|
} |
|
|
|
/** |
|
* Scales the mat2d by the dimensions in the given vec2 |
|
* |
|
* @param {mat2d} out the receiving matrix |
|
* @param {mat2d} a the matrix to translate |
|
* @param {vec2} v the vec2 to scale the matrix by |
|
* @returns {mat2d} out |
|
**/ |
|
function scale(out, a, v) { |
|
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5]; |
|
let v0 = v[0], v1 = v[1]; |
|
out[0] = a0 * v0; |
|
out[1] = a1 * v0; |
|
out[2] = a2 * v1; |
|
out[3] = a3 * v1; |
|
out[4] = a4; |
|
out[5] = a5; |
|
return out; |
|
} |
|
|
|
/** |
|
* Translates the mat2d by the dimensions in the given vec2 |
|
* |
|
* @param {mat2d} out the receiving matrix |
|
* @param {mat2d} a the matrix to translate |
|
* @param {vec2} v the vec2 to translate the matrix by |
|
* @returns {mat2d} out |
|
**/ |
|
function translate(out, a, v) { |
|
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5]; |
|
let v0 = v[0], v1 = v[1]; |
|
out[0] = a0; |
|
out[1] = a1; |
|
out[2] = a2; |
|
out[3] = a3; |
|
out[4] = a0 * v0 + a2 * v1 + a4; |
|
out[5] = a1 * v0 + a3 * v1 + a5; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a matrix from a given angle |
|
* This is equivalent to (but much faster than): |
|
* |
|
* mat2d.identity(dest); |
|
* mat2d.rotate(dest, dest, rad); |
|
* |
|
* @param {mat2d} out mat2d receiving operation result |
|
* @param {Number} rad the angle to rotate the matrix by |
|
* @returns {mat2d} out |
|
*/ |
|
function fromRotation(out, rad) { |
|
let s = Math.sin(rad), c = Math.cos(rad); |
|
out[0] = c; |
|
out[1] = s; |
|
out[2] = -s; |
|
out[3] = c; |
|
out[4] = 0; |
|
out[5] = 0; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a matrix from a vector scaling |
|
* This is equivalent to (but much faster than): |
|
* |
|
* mat2d.identity(dest); |
|
* mat2d.scale(dest, dest, vec); |
|
* |
|
* @param {mat2d} out mat2d receiving operation result |
|
* @param {vec2} v Scaling vector |
|
* @returns {mat2d} out |
|
*/ |
|
function fromScaling(out, v) { |
|
out[0] = v[0]; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = v[1]; |
|
out[4] = 0; |
|
out[5] = 0; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a matrix from a vector translation |
|
* This is equivalent to (but much faster than): |
|
* |
|
* mat2d.identity(dest); |
|
* mat2d.translate(dest, dest, vec); |
|
* |
|
* @param {mat2d} out mat2d receiving operation result |
|
* @param {vec2} v Translation vector |
|
* @returns {mat2d} out |
|
*/ |
|
function fromTranslation(out, v) { |
|
out[0] = 1; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 1; |
|
out[4] = v[0]; |
|
out[5] = v[1]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Returns a string representation of a mat2d |
|
* |
|
* @param {mat2d} a matrix to represent as a string |
|
* @returns {String} string representation of the matrix |
|
*/ |
|
function str(a) { |
|
return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + |
|
a[3] + ', ' + a[4] + ', ' + a[5] + ')'; |
|
} |
|
|
|
/** |
|
* Returns Frobenius norm of a mat2d |
|
* |
|
* @param {mat2d} a the matrix to calculate Frobenius norm of |
|
* @returns {Number} Frobenius norm |
|
*/ |
|
function frob(a) { |
|
return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + 1)) |
|
} |
|
|
|
/** |
|
* Adds two mat2d's |
|
* |
|
* @param {mat2d} out the receiving matrix |
|
* @param {mat2d} a the first operand |
|
* @param {mat2d} b the second operand |
|
* @returns {mat2d} out |
|
*/ |
|
function add(out, a, b) { |
|
out[0] = a[0] + b[0]; |
|
out[1] = a[1] + b[1]; |
|
out[2] = a[2] + b[2]; |
|
out[3] = a[3] + b[3]; |
|
out[4] = a[4] + b[4]; |
|
out[5] = a[5] + b[5]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Subtracts matrix b from matrix a |
|
* |
|
* @param {mat2d} out the receiving matrix |
|
* @param {mat2d} a the first operand |
|
* @param {mat2d} b the second operand |
|
* @returns {mat2d} out |
|
*/ |
|
function subtract(out, a, b) { |
|
out[0] = a[0] - b[0]; |
|
out[1] = a[1] - b[1]; |
|
out[2] = a[2] - b[2]; |
|
out[3] = a[3] - b[3]; |
|
out[4] = a[4] - b[4]; |
|
out[5] = a[5] - b[5]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Multiply each element of the matrix by a scalar. |
|
* |
|
* @param {mat2d} out the receiving matrix |
|
* @param {mat2d} a the matrix to scale |
|
* @param {Number} b amount to scale the matrix's elements by |
|
* @returns {mat2d} out |
|
*/ |
|
function multiplyScalar(out, a, b) { |
|
out[0] = a[0] * b; |
|
out[1] = a[1] * b; |
|
out[2] = a[2] * b; |
|
out[3] = a[3] * b; |
|
out[4] = a[4] * b; |
|
out[5] = a[5] * b; |
|
return out; |
|
} |
|
|
|
/** |
|
* Adds two mat2d's after multiplying each element of the second operand by a scalar value. |
|
* |
|
* @param {mat2d} out the receiving vector |
|
* @param {mat2d} a the first operand |
|
* @param {mat2d} b the second operand |
|
* @param {Number} scale the amount to scale b's elements by before adding |
|
* @returns {mat2d} out |
|
*/ |
|
function multiplyScalarAndAdd(out, a, b, scale) { |
|
out[0] = a[0] + (b[0] * scale); |
|
out[1] = a[1] + (b[1] * scale); |
|
out[2] = a[2] + (b[2] * scale); |
|
out[3] = a[3] + (b[3] * scale); |
|
out[4] = a[4] + (b[4] * scale); |
|
out[5] = a[5] + (b[5] * scale); |
|
return out; |
|
} |
|
|
|
/** |
|
* Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===) |
|
* |
|
* @param {mat2d} a The first matrix. |
|
* @param {mat2d} b The second matrix. |
|
* @returns {Boolean} True if the matrices are equal, false otherwise. |
|
*/ |
|
function exactEquals(a, b) { |
|
return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5]; |
|
} |
|
|
|
/** |
|
* Returns whether or not the matrices have approximately the same elements in the same position. |
|
* |
|
* @param {mat2d} a The first matrix. |
|
* @param {mat2d} b The second matrix. |
|
* @returns {Boolean} True if the matrices are equal, false otherwise. |
|
*/ |
|
function equals(a, b) { |
|
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5]; |
|
let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5]; |
|
return (Math.abs(a0 - b0) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a0), Math.abs(b0)) && |
|
Math.abs(a1 - b1) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a1), Math.abs(b1)) && |
|
Math.abs(a2 - b2) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a2), Math.abs(b2)) && |
|
Math.abs(a3 - b3) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a3), Math.abs(b3)) && |
|
Math.abs(a4 - b4) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a4), Math.abs(b4)) && |
|
Math.abs(a5 - b5) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a5), Math.abs(b5))); |
|
} |
|
|
|
/** |
|
* Alias for {@link mat2d.multiply} |
|
* @function |
|
*/ |
|
const mul = multiply; |
|
/* harmony export (immutable) */ __webpack_exports__["mul"] = mul; |
|
|
|
|
|
/** |
|
* Alias for {@link mat2d.subtract} |
|
* @function |
|
*/ |
|
const sub = subtract; |
|
/* harmony export (immutable) */ __webpack_exports__["sub"] = sub; |
|
|
|
|
|
|
|
/***/ }), |
|
/* 17 */ |
|
/***/ (function(module, __webpack_exports__, __webpack_require__) { |
|
|
|
"use strict"; |
|
Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); |
|
/* harmony export (immutable) */ __webpack_exports__["create"] = create; |
|
/* harmony export (immutable) */ __webpack_exports__["clone"] = clone; |
|
/* harmony export (immutable) */ __webpack_exports__["copy"] = copy; |
|
/* harmony export (immutable) */ __webpack_exports__["fromValues"] = fromValues; |
|
/* harmony export (immutable) */ __webpack_exports__["set"] = set; |
|
/* harmony export (immutable) */ __webpack_exports__["identity"] = identity; |
|
/* harmony export (immutable) */ __webpack_exports__["transpose"] = transpose; |
|
/* harmony export (immutable) */ __webpack_exports__["invert"] = invert; |
|
/* harmony export (immutable) */ __webpack_exports__["adjoint"] = adjoint; |
|
/* harmony export (immutable) */ __webpack_exports__["determinant"] = determinant; |
|
/* harmony export (immutable) */ __webpack_exports__["multiply"] = multiply; |
|
/* harmony export (immutable) */ __webpack_exports__["translate"] = translate; |
|
/* harmony export (immutable) */ __webpack_exports__["scale"] = scale; |
|
/* harmony export (immutable) */ __webpack_exports__["rotate"] = rotate; |
|
/* harmony export (immutable) */ __webpack_exports__["rotateX"] = rotateX; |
|
/* harmony export (immutable) */ __webpack_exports__["rotateY"] = rotateY; |
|
/* harmony export (immutable) */ __webpack_exports__["rotateZ"] = rotateZ; |
|
/* harmony export (immutable) */ __webpack_exports__["fromTranslation"] = fromTranslation; |
|
/* harmony export (immutable) */ __webpack_exports__["fromScaling"] = fromScaling; |
|
/* harmony export (immutable) */ __webpack_exports__["fromRotation"] = fromRotation; |
|
/* harmony export (immutable) */ __webpack_exports__["fromXRotation"] = fromXRotation; |
|
/* harmony export (immutable) */ __webpack_exports__["fromYRotation"] = fromYRotation; |
|
/* harmony export (immutable) */ __webpack_exports__["fromZRotation"] = fromZRotation; |
|
/* harmony export (immutable) */ __webpack_exports__["fromRotationTranslation"] = fromRotationTranslation; |
|
/* harmony export (immutable) */ __webpack_exports__["getTranslation"] = getTranslation; |
|
/* harmony export (immutable) */ __webpack_exports__["getScaling"] = getScaling; |
|
/* harmony export (immutable) */ __webpack_exports__["getRotation"] = getRotation; |
|
/* harmony export (immutable) */ __webpack_exports__["fromRotationTranslationScale"] = fromRotationTranslationScale; |
|
/* harmony export (immutable) */ __webpack_exports__["fromRotationTranslationScaleOrigin"] = fromRotationTranslationScaleOrigin; |
|
/* harmony export (immutable) */ __webpack_exports__["fromQuat"] = fromQuat; |
|
/* harmony export (immutable) */ __webpack_exports__["frustum"] = frustum; |
|
/* harmony export (immutable) */ __webpack_exports__["perspective"] = perspective; |
|
/* harmony export (immutable) */ __webpack_exports__["perspectiveFromFieldOfView"] = perspectiveFromFieldOfView; |
|
/* harmony export (immutable) */ __webpack_exports__["ortho"] = ortho; |
|
/* harmony export (immutable) */ __webpack_exports__["lookAt"] = lookAt; |
|
/* harmony export (immutable) */ __webpack_exports__["targetTo"] = targetTo; |
|
/* harmony export (immutable) */ __webpack_exports__["str"] = str; |
|
/* harmony export (immutable) */ __webpack_exports__["frob"] = frob; |
|
/* harmony export (immutable) */ __webpack_exports__["add"] = add; |
|
/* harmony export (immutable) */ __webpack_exports__["subtract"] = subtract; |
|
/* harmony export (immutable) */ __webpack_exports__["multiplyScalar"] = multiplyScalar; |
|
/* harmony export (immutable) */ __webpack_exports__["multiplyScalarAndAdd"] = multiplyScalarAndAdd; |
|
/* harmony export (immutable) */ __webpack_exports__["exactEquals"] = exactEquals; |
|
/* harmony export (immutable) */ __webpack_exports__["equals"] = equals; |
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__common__ = __webpack_require__(0); |
|
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. |
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
|
of this software and associated documentation files (the "Software"), to deal |
|
in the Software without restriction, including without limitation the rights |
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
copies of the Software, and to permit persons to whom the Software is |
|
furnished to do so, subject to the following conditions: |
|
|
|
The above copyright notice and this permission notice shall be included in |
|
all copies or substantial portions of the Software. |
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
THE SOFTWARE. */ |
|
|
|
|
|
|
|
/** |
|
* 4x4 Matrix |
|
* @module mat4 |
|
*/ |
|
|
|
/** |
|
* Creates a new identity mat4 |
|
* |
|
* @returns {mat4} a new 4x4 matrix |
|
*/ |
|
function create() { |
|
let out = new __WEBPACK_IMPORTED_MODULE_0__common__["ARRAY_TYPE"](16); |
|
out[0] = 1; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 0; |
|
out[4] = 0; |
|
out[5] = 1; |
|
out[6] = 0; |
|
out[7] = 0; |
|
out[8] = 0; |
|
out[9] = 0; |
|
out[10] = 1; |
|
out[11] = 0; |
|
out[12] = 0; |
|
out[13] = 0; |
|
out[14] = 0; |
|
out[15] = 1; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a new mat4 initialized with values from an existing matrix |
|
* |
|
* @param {mat4} a matrix to clone |
|
* @returns {mat4} a new 4x4 matrix |
|
*/ |
|
function clone(a) { |
|
let out = new __WEBPACK_IMPORTED_MODULE_0__common__["ARRAY_TYPE"](16); |
|
out[0] = a[0]; |
|
out[1] = a[1]; |
|
out[2] = a[2]; |
|
out[3] = a[3]; |
|
out[4] = a[4]; |
|
out[5] = a[5]; |
|
out[6] = a[6]; |
|
out[7] = a[7]; |
|
out[8] = a[8]; |
|
out[9] = a[9]; |
|
out[10] = a[10]; |
|
out[11] = a[11]; |
|
out[12] = a[12]; |
|
out[13] = a[13]; |
|
out[14] = a[14]; |
|
out[15] = a[15]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Copy the values from one mat4 to another |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the source matrix |
|
* @returns {mat4} out |
|
*/ |
|
function copy(out, a) { |
|
out[0] = a[0]; |
|
out[1] = a[1]; |
|
out[2] = a[2]; |
|
out[3] = a[3]; |
|
out[4] = a[4]; |
|
out[5] = a[5]; |
|
out[6] = a[6]; |
|
out[7] = a[7]; |
|
out[8] = a[8]; |
|
out[9] = a[9]; |
|
out[10] = a[10]; |
|
out[11] = a[11]; |
|
out[12] = a[12]; |
|
out[13] = a[13]; |
|
out[14] = a[14]; |
|
out[15] = a[15]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Create a new mat4 with the given values |
|
* |
|
* @param {Number} m00 Component in column 0, row 0 position (index 0) |
|
* @param {Number} m01 Component in column 0, row 1 position (index 1) |
|
* @param {Number} m02 Component in column 0, row 2 position (index 2) |
|
* @param {Number} m03 Component in column 0, row 3 position (index 3) |
|
* @param {Number} m10 Component in column 1, row 0 position (index 4) |
|
* @param {Number} m11 Component in column 1, row 1 position (index 5) |
|
* @param {Number} m12 Component in column 1, row 2 position (index 6) |
|
* @param {Number} m13 Component in column 1, row 3 position (index 7) |
|
* @param {Number} m20 Component in column 2, row 0 position (index 8) |
|
* @param {Number} m21 Component in column 2, row 1 position (index 9) |
|
* @param {Number} m22 Component in column 2, row 2 position (index 10) |
|
* @param {Number} m23 Component in column 2, row 3 position (index 11) |
|
* @param {Number} m30 Component in column 3, row 0 position (index 12) |
|
* @param {Number} m31 Component in column 3, row 1 position (index 13) |
|
* @param {Number} m32 Component in column 3, row 2 position (index 14) |
|
* @param {Number} m33 Component in column 3, row 3 position (index 15) |
|
* @returns {mat4} A new mat4 |
|
*/ |
|
function fromValues(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) { |
|
let out = new __WEBPACK_IMPORTED_MODULE_0__common__["ARRAY_TYPE"](16); |
|
out[0] = m00; |
|
out[1] = m01; |
|
out[2] = m02; |
|
out[3] = m03; |
|
out[4] = m10; |
|
out[5] = m11; |
|
out[6] = m12; |
|
out[7] = m13; |
|
out[8] = m20; |
|
out[9] = m21; |
|
out[10] = m22; |
|
out[11] = m23; |
|
out[12] = m30; |
|
out[13] = m31; |
|
out[14] = m32; |
|
out[15] = m33; |
|
return out; |
|
} |
|
|
|
/** |
|
* Set the components of a mat4 to the given values |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {Number} m00 Component in column 0, row 0 position (index 0) |
|
* @param {Number} m01 Component in column 0, row 1 position (index 1) |
|
* @param {Number} m02 Component in column 0, row 2 position (index 2) |
|
* @param {Number} m03 Component in column 0, row 3 position (index 3) |
|
* @param {Number} m10 Component in column 1, row 0 position (index 4) |
|
* @param {Number} m11 Component in column 1, row 1 position (index 5) |
|
* @param {Number} m12 Component in column 1, row 2 position (index 6) |
|
* @param {Number} m13 Component in column 1, row 3 position (index 7) |
|
* @param {Number} m20 Component in column 2, row 0 position (index 8) |
|
* @param {Number} m21 Component in column 2, row 1 position (index 9) |
|
* @param {Number} m22 Component in column 2, row 2 position (index 10) |
|
* @param {Number} m23 Component in column 2, row 3 position (index 11) |
|
* @param {Number} m30 Component in column 3, row 0 position (index 12) |
|
* @param {Number} m31 Component in column 3, row 1 position (index 13) |
|
* @param {Number} m32 Component in column 3, row 2 position (index 14) |
|
* @param {Number} m33 Component in column 3, row 3 position (index 15) |
|
* @returns {mat4} out |
|
*/ |
|
function set(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) { |
|
out[0] = m00; |
|
out[1] = m01; |
|
out[2] = m02; |
|
out[3] = m03; |
|
out[4] = m10; |
|
out[5] = m11; |
|
out[6] = m12; |
|
out[7] = m13; |
|
out[8] = m20; |
|
out[9] = m21; |
|
out[10] = m22; |
|
out[11] = m23; |
|
out[12] = m30; |
|
out[13] = m31; |
|
out[14] = m32; |
|
out[15] = m33; |
|
return out; |
|
} |
|
|
|
|
|
/** |
|
* Set a mat4 to the identity matrix |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @returns {mat4} out |
|
*/ |
|
function identity(out) { |
|
out[0] = 1; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 0; |
|
out[4] = 0; |
|
out[5] = 1; |
|
out[6] = 0; |
|
out[7] = 0; |
|
out[8] = 0; |
|
out[9] = 0; |
|
out[10] = 1; |
|
out[11] = 0; |
|
out[12] = 0; |
|
out[13] = 0; |
|
out[14] = 0; |
|
out[15] = 1; |
|
return out; |
|
} |
|
|
|
/** |
|
* Transpose the values of a mat4 |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the source matrix |
|
* @returns {mat4} out |
|
*/ |
|
function transpose(out, a) { |
|
// If we are transposing ourselves we can skip a few steps but have to cache some values |
|
if (out === a) { |
|
let a01 = a[1], a02 = a[2], a03 = a[3]; |
|
let a12 = a[6], a13 = a[7]; |
|
let a23 = a[11]; |
|
|
|
out[1] = a[4]; |
|
out[2] = a[8]; |
|
out[3] = a[12]; |
|
out[4] = a01; |
|
out[6] = a[9]; |
|
out[7] = a[13]; |
|
out[8] = a02; |
|
out[9] = a12; |
|
out[11] = a[14]; |
|
out[12] = a03; |
|
out[13] = a13; |
|
out[14] = a23; |
|
} else { |
|
out[0] = a[0]; |
|
out[1] = a[4]; |
|
out[2] = a[8]; |
|
out[3] = a[12]; |
|
out[4] = a[1]; |
|
out[5] = a[5]; |
|
out[6] = a[9]; |
|
out[7] = a[13]; |
|
out[8] = a[2]; |
|
out[9] = a[6]; |
|
out[10] = a[10]; |
|
out[11] = a[14]; |
|
out[12] = a[3]; |
|
out[13] = a[7]; |
|
out[14] = a[11]; |
|
out[15] = a[15]; |
|
} |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Inverts a mat4 |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the source matrix |
|
* @returns {mat4} out |
|
*/ |
|
function invert(out, a) { |
|
let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; |
|
let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; |
|
let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; |
|
let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; |
|
|
|
let b00 = a00 * a11 - a01 * a10; |
|
let b01 = a00 * a12 - a02 * a10; |
|
let b02 = a00 * a13 - a03 * a10; |
|
let b03 = a01 * a12 - a02 * a11; |
|
let b04 = a01 * a13 - a03 * a11; |
|
let b05 = a02 * a13 - a03 * a12; |
|
let b06 = a20 * a31 - a21 * a30; |
|
let b07 = a20 * a32 - a22 * a30; |
|
let b08 = a20 * a33 - a23 * a30; |
|
let b09 = a21 * a32 - a22 * a31; |
|
let b10 = a21 * a33 - a23 * a31; |
|
let b11 = a22 * a33 - a23 * a32; |
|
|
|
// Calculate the determinant |
|
let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; |
|
|
|
if (!det) { |
|
return null; |
|
} |
|
det = 1.0 / det; |
|
|
|
out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; |
|
out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; |
|
out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; |
|
out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; |
|
out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; |
|
out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; |
|
out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; |
|
out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; |
|
out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; |
|
out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; |
|
out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; |
|
out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; |
|
out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; |
|
out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; |
|
out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; |
|
out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Calculates the adjugate of a mat4 |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the source matrix |
|
* @returns {mat4} out |
|
*/ |
|
function adjoint(out, a) { |
|
let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; |
|
let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; |
|
let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; |
|
let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; |
|
|
|
out[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22)); |
|
out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22)); |
|
out[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12)); |
|
out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12)); |
|
out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22)); |
|
out[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22)); |
|
out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12)); |
|
out[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12)); |
|
out[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21)); |
|
out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21)); |
|
out[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11)); |
|
out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11)); |
|
out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21)); |
|
out[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21)); |
|
out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11)); |
|
out[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11)); |
|
return out; |
|
} |
|
|
|
/** |
|
* Calculates the determinant of a mat4 |
|
* |
|
* @param {mat4} a the source matrix |
|
* @returns {Number} determinant of a |
|
*/ |
|
function determinant(a) { |
|
let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; |
|
let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; |
|
let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; |
|
let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; |
|
|
|
let b00 = a00 * a11 - a01 * a10; |
|
let b01 = a00 * a12 - a02 * a10; |
|
let b02 = a00 * a13 - a03 * a10; |
|
let b03 = a01 * a12 - a02 * a11; |
|
let b04 = a01 * a13 - a03 * a11; |
|
let b05 = a02 * a13 - a03 * a12; |
|
let b06 = a20 * a31 - a21 * a30; |
|
let b07 = a20 * a32 - a22 * a30; |
|
let b08 = a20 * a33 - a23 * a30; |
|
let b09 = a21 * a32 - a22 * a31; |
|
let b10 = a21 * a33 - a23 * a31; |
|
let b11 = a22 * a33 - a23 * a32; |
|
|
|
// Calculate the determinant |
|
return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; |
|
} |
|
|
|
/** |
|
* Multiplies two mat4s |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the first operand |
|
* @param {mat4} b the second operand |
|
* @returns {mat4} out |
|
*/ |
|
function multiply(out, a, b) { |
|
let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; |
|
let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; |
|
let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; |
|
let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; |
|
|
|
// Cache only the current line of the second matrix |
|
let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; |
|
out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; |
|
out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; |
|
out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; |
|
out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; |
|
|
|
b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; |
|
out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; |
|
out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; |
|
out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; |
|
out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; |
|
|
|
b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; |
|
out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; |
|
out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; |
|
out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; |
|
out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; |
|
|
|
b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; |
|
out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; |
|
out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; |
|
out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; |
|
out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; |
|
return out; |
|
} |
|
|
|
/** |
|
* Translate a mat4 by the given vector |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the matrix to translate |
|
* @param {vec3} v vector to translate by |
|
* @returns {mat4} out |
|
*/ |
|
function translate(out, a, v) { |
|
let x = v[0], y = v[1], z = v[2]; |
|
let a00, a01, a02, a03; |
|
let a10, a11, a12, a13; |
|
let a20, a21, a22, a23; |
|
|
|
if (a === out) { |
|
out[12] = a[0] * x + a[4] * y + a[8] * z + a[12]; |
|
out[13] = a[1] * x + a[5] * y + a[9] * z + a[13]; |
|
out[14] = a[2] * x + a[6] * y + a[10] * z + a[14]; |
|
out[15] = a[3] * x + a[7] * y + a[11] * z + a[15]; |
|
} else { |
|
a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; |
|
a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; |
|
a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; |
|
|
|
out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a03; |
|
out[4] = a10; out[5] = a11; out[6] = a12; out[7] = a13; |
|
out[8] = a20; out[9] = a21; out[10] = a22; out[11] = a23; |
|
|
|
out[12] = a00 * x + a10 * y + a20 * z + a[12]; |
|
out[13] = a01 * x + a11 * y + a21 * z + a[13]; |
|
out[14] = a02 * x + a12 * y + a22 * z + a[14]; |
|
out[15] = a03 * x + a13 * y + a23 * z + a[15]; |
|
} |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Scales the mat4 by the dimensions in the given vec3 not using vectorization |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the matrix to scale |
|
* @param {vec3} v the vec3 to scale the matrix by |
|
* @returns {mat4} out |
|
**/ |
|
function scale(out, a, v) { |
|
let x = v[0], y = v[1], z = v[2]; |
|
|
|
out[0] = a[0] * x; |
|
out[1] = a[1] * x; |
|
out[2] = a[2] * x; |
|
out[3] = a[3] * x; |
|
out[4] = a[4] * y; |
|
out[5] = a[5] * y; |
|
out[6] = a[6] * y; |
|
out[7] = a[7] * y; |
|
out[8] = a[8] * z; |
|
out[9] = a[9] * z; |
|
out[10] = a[10] * z; |
|
out[11] = a[11] * z; |
|
out[12] = a[12]; |
|
out[13] = a[13]; |
|
out[14] = a[14]; |
|
out[15] = a[15]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Rotates a mat4 by the given angle around the given axis |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the matrix to rotate |
|
* @param {Number} rad the angle to rotate the matrix by |
|
* @param {vec3} axis the axis to rotate around |
|
* @returns {mat4} out |
|
*/ |
|
function rotate(out, a, rad, axis) { |
|
let x = axis[0], y = axis[1], z = axis[2]; |
|
let len = Math.sqrt(x * x + y * y + z * z); |
|
let s, c, t; |
|
let a00, a01, a02, a03; |
|
let a10, a11, a12, a13; |
|
let a20, a21, a22, a23; |
|
let b00, b01, b02; |
|
let b10, b11, b12; |
|
let b20, b21, b22; |
|
|
|
if (Math.abs(len) < __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]) { return null; } |
|
|
|
len = 1 / len; |
|
x *= len; |
|
y *= len; |
|
z *= len; |
|
|
|
s = Math.sin(rad); |
|
c = Math.cos(rad); |
|
t = 1 - c; |
|
|
|
a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; |
|
a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; |
|
a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; |
|
|
|
// Construct the elements of the rotation matrix |
|
b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s; |
|
b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s; |
|
b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c; |
|
|
|
// Perform rotation-specific matrix multiplication |
|
out[0] = a00 * b00 + a10 * b01 + a20 * b02; |
|
out[1] = a01 * b00 + a11 * b01 + a21 * b02; |
|
out[2] = a02 * b00 + a12 * b01 + a22 * b02; |
|
out[3] = a03 * b00 + a13 * b01 + a23 * b02; |
|
out[4] = a00 * b10 + a10 * b11 + a20 * b12; |
|
out[5] = a01 * b10 + a11 * b11 + a21 * b12; |
|
out[6] = a02 * b10 + a12 * b11 + a22 * b12; |
|
out[7] = a03 * b10 + a13 * b11 + a23 * b12; |
|
out[8] = a00 * b20 + a10 * b21 + a20 * b22; |
|
out[9] = a01 * b20 + a11 * b21 + a21 * b22; |
|
out[10] = a02 * b20 + a12 * b21 + a22 * b22; |
|
out[11] = a03 * b20 + a13 * b21 + a23 * b22; |
|
|
|
if (a !== out) { // If the source and destination differ, copy the unchanged last row |
|
out[12] = a[12]; |
|
out[13] = a[13]; |
|
out[14] = a[14]; |
|
out[15] = a[15]; |
|
} |
|
return out; |
|
} |
|
|
|
/** |
|
* Rotates a matrix by the given angle around the X axis |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the matrix to rotate |
|
* @param {Number} rad the angle to rotate the matrix by |
|
* @returns {mat4} out |
|
*/ |
|
function rotateX(out, a, rad) { |
|
let s = Math.sin(rad); |
|
let c = Math.cos(rad); |
|
let a10 = a[4]; |
|
let a11 = a[5]; |
|
let a12 = a[6]; |
|
let a13 = a[7]; |
|
let a20 = a[8]; |
|
let a21 = a[9]; |
|
let a22 = a[10]; |
|
let a23 = a[11]; |
|
|
|
if (a !== out) { // If the source and destination differ, copy the unchanged rows |
|
out[0] = a[0]; |
|
out[1] = a[1]; |
|
out[2] = a[2]; |
|
out[3] = a[3]; |
|
out[12] = a[12]; |
|
out[13] = a[13]; |
|
out[14] = a[14]; |
|
out[15] = a[15]; |
|
} |
|
|
|
// Perform axis-specific matrix multiplication |
|
out[4] = a10 * c + a20 * s; |
|
out[5] = a11 * c + a21 * s; |
|
out[6] = a12 * c + a22 * s; |
|
out[7] = a13 * c + a23 * s; |
|
out[8] = a20 * c - a10 * s; |
|
out[9] = a21 * c - a11 * s; |
|
out[10] = a22 * c - a12 * s; |
|
out[11] = a23 * c - a13 * s; |
|
return out; |
|
} |
|
|
|
/** |
|
* Rotates a matrix by the given angle around the Y axis |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the matrix to rotate |
|
* @param {Number} rad the angle to rotate the matrix by |
|
* @returns {mat4} out |
|
*/ |
|
function rotateY(out, a, rad) { |
|
let s = Math.sin(rad); |
|
let c = Math.cos(rad); |
|
let a00 = a[0]; |
|
let a01 = a[1]; |
|
let a02 = a[2]; |
|
let a03 = a[3]; |
|
let a20 = a[8]; |
|
let a21 = a[9]; |
|
let a22 = a[10]; |
|
let a23 = a[11]; |
|
|
|
if (a !== out) { // If the source and destination differ, copy the unchanged rows |
|
out[4] = a[4]; |
|
out[5] = a[5]; |
|
out[6] = a[6]; |
|
out[7] = a[7]; |
|
out[12] = a[12]; |
|
out[13] = a[13]; |
|
out[14] = a[14]; |
|
out[15] = a[15]; |
|
} |
|
|
|
// Perform axis-specific matrix multiplication |
|
out[0] = a00 * c - a20 * s; |
|
out[1] = a01 * c - a21 * s; |
|
out[2] = a02 * c - a22 * s; |
|
out[3] = a03 * c - a23 * s; |
|
out[8] = a00 * s + a20 * c; |
|
out[9] = a01 * s + a21 * c; |
|
out[10] = a02 * s + a22 * c; |
|
out[11] = a03 * s + a23 * c; |
|
return out; |
|
} |
|
|
|
/** |
|
* Rotates a matrix by the given angle around the Z axis |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the matrix to rotate |
|
* @param {Number} rad the angle to rotate the matrix by |
|
* @returns {mat4} out |
|
*/ |
|
function rotateZ(out, a, rad) { |
|
let s = Math.sin(rad); |
|
let c = Math.cos(rad); |
|
let a00 = a[0]; |
|
let a01 = a[1]; |
|
let a02 = a[2]; |
|
let a03 = a[3]; |
|
let a10 = a[4]; |
|
let a11 = a[5]; |
|
let a12 = a[6]; |
|
let a13 = a[7]; |
|
|
|
if (a !== out) { // If the source and destination differ, copy the unchanged last row |
|
out[8] = a[8]; |
|
out[9] = a[9]; |
|
out[10] = a[10]; |
|
out[11] = a[11]; |
|
out[12] = a[12]; |
|
out[13] = a[13]; |
|
out[14] = a[14]; |
|
out[15] = a[15]; |
|
} |
|
|
|
// Perform axis-specific matrix multiplication |
|
out[0] = a00 * c + a10 * s; |
|
out[1] = a01 * c + a11 * s; |
|
out[2] = a02 * c + a12 * s; |
|
out[3] = a03 * c + a13 * s; |
|
out[4] = a10 * c - a00 * s; |
|
out[5] = a11 * c - a01 * s; |
|
out[6] = a12 * c - a02 * s; |
|
out[7] = a13 * c - a03 * s; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a matrix from a vector translation |
|
* This is equivalent to (but much faster than): |
|
* |
|
* mat4.identity(dest); |
|
* mat4.translate(dest, dest, vec); |
|
* |
|
* @param {mat4} out mat4 receiving operation result |
|
* @param {vec3} v Translation vector |
|
* @returns {mat4} out |
|
*/ |
|
function fromTranslation(out, v) { |
|
out[0] = 1; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 0; |
|
out[4] = 0; |
|
out[5] = 1; |
|
out[6] = 0; |
|
out[7] = 0; |
|
out[8] = 0; |
|
out[9] = 0; |
|
out[10] = 1; |
|
out[11] = 0; |
|
out[12] = v[0]; |
|
out[13] = v[1]; |
|
out[14] = v[2]; |
|
out[15] = 1; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a matrix from a vector scaling |
|
* This is equivalent to (but much faster than): |
|
* |
|
* mat4.identity(dest); |
|
* mat4.scale(dest, dest, vec); |
|
* |
|
* @param {mat4} out mat4 receiving operation result |
|
* @param {vec3} v Scaling vector |
|
* @returns {mat4} out |
|
*/ |
|
function fromScaling(out, v) { |
|
out[0] = v[0]; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 0; |
|
out[4] = 0; |
|
out[5] = v[1]; |
|
out[6] = 0; |
|
out[7] = 0; |
|
out[8] = 0; |
|
out[9] = 0; |
|
out[10] = v[2]; |
|
out[11] = 0; |
|
out[12] = 0; |
|
out[13] = 0; |
|
out[14] = 0; |
|
out[15] = 1; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a matrix from a given angle around a given axis |
|
* This is equivalent to (but much faster than): |
|
* |
|
* mat4.identity(dest); |
|
* mat4.rotate(dest, dest, rad, axis); |
|
* |
|
* @param {mat4} out mat4 receiving operation result |
|
* @param {Number} rad the angle to rotate the matrix by |
|
* @param {vec3} axis the axis to rotate around |
|
* @returns {mat4} out |
|
*/ |
|
function fromRotation(out, rad, axis) { |
|
let x = axis[0], y = axis[1], z = axis[2]; |
|
let len = Math.sqrt(x * x + y * y + z * z); |
|
let s, c, t; |
|
|
|
if (Math.abs(len) < __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]) { return null; } |
|
|
|
len = 1 / len; |
|
x *= len; |
|
y *= len; |
|
z *= len; |
|
|
|
s = Math.sin(rad); |
|
c = Math.cos(rad); |
|
t = 1 - c; |
|
|
|
// Perform rotation-specific matrix multiplication |
|
out[0] = x * x * t + c; |
|
out[1] = y * x * t + z * s; |
|
out[2] = z * x * t - y * s; |
|
out[3] = 0; |
|
out[4] = x * y * t - z * s; |
|
out[5] = y * y * t + c; |
|
out[6] = z * y * t + x * s; |
|
out[7] = 0; |
|
out[8] = x * z * t + y * s; |
|
out[9] = y * z * t - x * s; |
|
out[10] = z * z * t + c; |
|
out[11] = 0; |
|
out[12] = 0; |
|
out[13] = 0; |
|
out[14] = 0; |
|
out[15] = 1; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a matrix from the given angle around the X axis |
|
* This is equivalent to (but much faster than): |
|
* |
|
* mat4.identity(dest); |
|
* mat4.rotateX(dest, dest, rad); |
|
* |
|
* @param {mat4} out mat4 receiving operation result |
|
* @param {Number} rad the angle to rotate the matrix by |
|
* @returns {mat4} out |
|
*/ |
|
function fromXRotation(out, rad) { |
|
let s = Math.sin(rad); |
|
let c = Math.cos(rad); |
|
|
|
// Perform axis-specific matrix multiplication |
|
out[0] = 1; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 0; |
|
out[4] = 0; |
|
out[5] = c; |
|
out[6] = s; |
|
out[7] = 0; |
|
out[8] = 0; |
|
out[9] = -s; |
|
out[10] = c; |
|
out[11] = 0; |
|
out[12] = 0; |
|
out[13] = 0; |
|
out[14] = 0; |
|
out[15] = 1; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a matrix from the given angle around the Y axis |
|
* This is equivalent to (but much faster than): |
|
* |
|
* mat4.identity(dest); |
|
* mat4.rotateY(dest, dest, rad); |
|
* |
|
* @param {mat4} out mat4 receiving operation result |
|
* @param {Number} rad the angle to rotate the matrix by |
|
* @returns {mat4} out |
|
*/ |
|
function fromYRotation(out, rad) { |
|
let s = Math.sin(rad); |
|
let c = Math.cos(rad); |
|
|
|
// Perform axis-specific matrix multiplication |
|
out[0] = c; |
|
out[1] = 0; |
|
out[2] = -s; |
|
out[3] = 0; |
|
out[4] = 0; |
|
out[5] = 1; |
|
out[6] = 0; |
|
out[7] = 0; |
|
out[8] = s; |
|
out[9] = 0; |
|
out[10] = c; |
|
out[11] = 0; |
|
out[12] = 0; |
|
out[13] = 0; |
|
out[14] = 0; |
|
out[15] = 1; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a matrix from the given angle around the Z axis |
|
* This is equivalent to (but much faster than): |
|
* |
|
* mat4.identity(dest); |
|
* mat4.rotateZ(dest, dest, rad); |
|
* |
|
* @param {mat4} out mat4 receiving operation result |
|
* @param {Number} rad the angle to rotate the matrix by |
|
* @returns {mat4} out |
|
*/ |
|
function fromZRotation(out, rad) { |
|
let s = Math.sin(rad); |
|
let c = Math.cos(rad); |
|
|
|
// Perform axis-specific matrix multiplication |
|
out[0] = c; |
|
out[1] = s; |
|
out[2] = 0; |
|
out[3] = 0; |
|
out[4] = -s; |
|
out[5] = c; |
|
out[6] = 0; |
|
out[7] = 0; |
|
out[8] = 0; |
|
out[9] = 0; |
|
out[10] = 1; |
|
out[11] = 0; |
|
out[12] = 0; |
|
out[13] = 0; |
|
out[14] = 0; |
|
out[15] = 1; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a matrix from a quaternion rotation and vector translation |
|
* This is equivalent to (but much faster than): |
|
* |
|
* mat4.identity(dest); |
|
* mat4.translate(dest, vec); |
|
* let quatMat = mat4.create(); |
|
* quat4.toMat4(quat, quatMat); |
|
* mat4.multiply(dest, quatMat); |
|
* |
|
* @param {mat4} out mat4 receiving operation result |
|
* @param {quat4} q Rotation quaternion |
|
* @param {vec3} v Translation vector |
|
* @returns {mat4} out |
|
*/ |
|
function fromRotationTranslation(out, q, v) { |
|
// Quaternion math |
|
let x = q[0], y = q[1], z = q[2], w = q[3]; |
|
let x2 = x + x; |
|
let y2 = y + y; |
|
let z2 = z + z; |
|
|
|
let xx = x * x2; |
|
let xy = x * y2; |
|
let xz = x * z2; |
|
let yy = y * y2; |
|
let yz = y * z2; |
|
let zz = z * z2; |
|
let wx = w * x2; |
|
let wy = w * y2; |
|
let wz = w * z2; |
|
|
|
out[0] = 1 - (yy + zz); |
|
out[1] = xy + wz; |
|
out[2] = xz - wy; |
|
out[3] = 0; |
|
out[4] = xy - wz; |
|
out[5] = 1 - (xx + zz); |
|
out[6] = yz + wx; |
|
out[7] = 0; |
|
out[8] = xz + wy; |
|
out[9] = yz - wx; |
|
out[10] = 1 - (xx + yy); |
|
out[11] = 0; |
|
out[12] = v[0]; |
|
out[13] = v[1]; |
|
out[14] = v[2]; |
|
out[15] = 1; |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Returns the translation vector component of a transformation |
|
* matrix. If a matrix is built with fromRotationTranslation, |
|
* the returned vector will be the same as the translation vector |
|
* originally supplied. |
|
* @param {vec3} out Vector to receive translation component |
|
* @param {mat4} mat Matrix to be decomposed (input) |
|
* @return {vec3} out |
|
*/ |
|
function getTranslation(out, mat) { |
|
out[0] = mat[12]; |
|
out[1] = mat[13]; |
|
out[2] = mat[14]; |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Returns the scaling factor component of a transformation |
|
* matrix. If a matrix is built with fromRotationTranslationScale |
|
* with a normalized Quaternion paramter, the returned vector will be |
|
* the same as the scaling vector |
|
* originally supplied. |
|
* @param {vec3} out Vector to receive scaling factor component |
|
* @param {mat4} mat Matrix to be decomposed (input) |
|
* @return {vec3} out |
|
*/ |
|
function getScaling(out, mat) { |
|
let m11 = mat[0]; |
|
let m12 = mat[1]; |
|
let m13 = mat[2]; |
|
let m21 = mat[4]; |
|
let m22 = mat[5]; |
|
let m23 = mat[6]; |
|
let m31 = mat[8]; |
|
let m32 = mat[9]; |
|
let m33 = mat[10]; |
|
|
|
out[0] = Math.sqrt(m11 * m11 + m12 * m12 + m13 * m13); |
|
out[1] = Math.sqrt(m21 * m21 + m22 * m22 + m23 * m23); |
|
out[2] = Math.sqrt(m31 * m31 + m32 * m32 + m33 * m33); |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Returns a quaternion representing the rotational component |
|
* of a transformation matrix. If a matrix is built with |
|
* fromRotationTranslation, the returned quaternion will be the |
|
* same as the quaternion originally supplied. |
|
* @param {quat} out Quaternion to receive the rotation component |
|
* @param {mat4} mat Matrix to be decomposed (input) |
|
* @return {quat} out |
|
*/ |
|
function getRotation(out, mat) { |
|
// Algorithm taken from http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm |
|
let trace = mat[0] + mat[5] + mat[10]; |
|
let S = 0; |
|
|
|
if (trace > 0) { |
|
S = Math.sqrt(trace + 1.0) * 2; |
|
out[3] = 0.25 * S; |
|
out[0] = (mat[6] - mat[9]) / S; |
|
out[1] = (mat[8] - mat[2]) / S; |
|
out[2] = (mat[1] - mat[4]) / S; |
|
} else if ((mat[0] > mat[5])&(mat[0] > mat[10])) { |
|
S = Math.sqrt(1.0 + mat[0] - mat[5] - mat[10]) * 2; |
|
out[3] = (mat[6] - mat[9]) / S; |
|
out[0] = 0.25 * S; |
|
out[1] = (mat[1] + mat[4]) / S; |
|
out[2] = (mat[8] + mat[2]) / S; |
|
} else if (mat[5] > mat[10]) { |
|
S = Math.sqrt(1.0 + mat[5] - mat[0] - mat[10]) * 2; |
|
out[3] = (mat[8] - mat[2]) / S; |
|
out[0] = (mat[1] + mat[4]) / S; |
|
out[1] = 0.25 * S; |
|
out[2] = (mat[6] + mat[9]) / S; |
|
} else { |
|
S = Math.sqrt(1.0 + mat[10] - mat[0] - mat[5]) * 2; |
|
out[3] = (mat[1] - mat[4]) / S; |
|
out[0] = (mat[8] + mat[2]) / S; |
|
out[1] = (mat[6] + mat[9]) / S; |
|
out[2] = 0.25 * S; |
|
} |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a matrix from a quaternion rotation, vector translation and vector scale |
|
* This is equivalent to (but much faster than): |
|
* |
|
* mat4.identity(dest); |
|
* mat4.translate(dest, vec); |
|
* let quatMat = mat4.create(); |
|
* quat4.toMat4(quat, quatMat); |
|
* mat4.multiply(dest, quatMat); |
|
* mat4.scale(dest, scale) |
|
* |
|
* @param {mat4} out mat4 receiving operation result |
|
* @param {quat4} q Rotation quaternion |
|
* @param {vec3} v Translation vector |
|
* @param {vec3} s Scaling vector |
|
* @returns {mat4} out |
|
*/ |
|
function fromRotationTranslationScale(out, q, v, s) { |
|
// Quaternion math |
|
let x = q[0], y = q[1], z = q[2], w = q[3]; |
|
let x2 = x + x; |
|
let y2 = y + y; |
|
let z2 = z + z; |
|
|
|
let xx = x * x2; |
|
let xy = x * y2; |
|
let xz = x * z2; |
|
let yy = y * y2; |
|
let yz = y * z2; |
|
let zz = z * z2; |
|
let wx = w * x2; |
|
let wy = w * y2; |
|
let wz = w * z2; |
|
let sx = s[0]; |
|
let sy = s[1]; |
|
let sz = s[2]; |
|
|
|
out[0] = (1 - (yy + zz)) * sx; |
|
out[1] = (xy + wz) * sx; |
|
out[2] = (xz - wy) * sx; |
|
out[3] = 0; |
|
out[4] = (xy - wz) * sy; |
|
out[5] = (1 - (xx + zz)) * sy; |
|
out[6] = (yz + wx) * sy; |
|
out[7] = 0; |
|
out[8] = (xz + wy) * sz; |
|
out[9] = (yz - wx) * sz; |
|
out[10] = (1 - (xx + yy)) * sz; |
|
out[11] = 0; |
|
out[12] = v[0]; |
|
out[13] = v[1]; |
|
out[14] = v[2]; |
|
out[15] = 1; |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin |
|
* This is equivalent to (but much faster than): |
|
* |
|
* mat4.identity(dest); |
|
* mat4.translate(dest, vec); |
|
* mat4.translate(dest, origin); |
|
* let quatMat = mat4.create(); |
|
* quat4.toMat4(quat, quatMat); |
|
* mat4.multiply(dest, quatMat); |
|
* mat4.scale(dest, scale) |
|
* mat4.translate(dest, negativeOrigin); |
|
* |
|
* @param {mat4} out mat4 receiving operation result |
|
* @param {quat4} q Rotation quaternion |
|
* @param {vec3} v Translation vector |
|
* @param {vec3} s Scaling vector |
|
* @param {vec3} o The origin vector around which to scale and rotate |
|
* @returns {mat4} out |
|
*/ |
|
function fromRotationTranslationScaleOrigin(out, q, v, s, o) { |
|
// Quaternion math |
|
let x = q[0], y = q[1], z = q[2], w = q[3]; |
|
let x2 = x + x; |
|
let y2 = y + y; |
|
let z2 = z + z; |
|
|
|
let xx = x * x2; |
|
let xy = x * y2; |
|
let xz = x * z2; |
|
let yy = y * y2; |
|
let yz = y * z2; |
|
let zz = z * z2; |
|
let wx = w * x2; |
|
let wy = w * y2; |
|
let wz = w * z2; |
|
|
|
let sx = s[0]; |
|
let sy = s[1]; |
|
let sz = s[2]; |
|
|
|
let ox = o[0]; |
|
let oy = o[1]; |
|
let oz = o[2]; |
|
|
|
out[0] = (1 - (yy + zz)) * sx; |
|
out[1] = (xy + wz) * sx; |
|
out[2] = (xz - wy) * sx; |
|
out[3] = 0; |
|
out[4] = (xy - wz) * sy; |
|
out[5] = (1 - (xx + zz)) * sy; |
|
out[6] = (yz + wx) * sy; |
|
out[7] = 0; |
|
out[8] = (xz + wy) * sz; |
|
out[9] = (yz - wx) * sz; |
|
out[10] = (1 - (xx + yy)) * sz; |
|
out[11] = 0; |
|
out[12] = v[0] + ox - (out[0] * ox + out[4] * oy + out[8] * oz); |
|
out[13] = v[1] + oy - (out[1] * ox + out[5] * oy + out[9] * oz); |
|
out[14] = v[2] + oz - (out[2] * ox + out[6] * oy + out[10] * oz); |
|
out[15] = 1; |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Calculates a 4x4 matrix from the given quaternion |
|
* |
|
* @param {mat4} out mat4 receiving operation result |
|
* @param {quat} q Quaternion to create matrix from |
|
* |
|
* @returns {mat4} out |
|
*/ |
|
function fromQuat(out, q) { |
|
let x = q[0], y = q[1], z = q[2], w = q[3]; |
|
let x2 = x + x; |
|
let y2 = y + y; |
|
let z2 = z + z; |
|
|
|
let xx = x * x2; |
|
let yx = y * x2; |
|
let yy = y * y2; |
|
let zx = z * x2; |
|
let zy = z * y2; |
|
let zz = z * z2; |
|
let wx = w * x2; |
|
let wy = w * y2; |
|
let wz = w * z2; |
|
|
|
out[0] = 1 - yy - zz; |
|
out[1] = yx + wz; |
|
out[2] = zx - wy; |
|
out[3] = 0; |
|
|
|
out[4] = yx - wz; |
|
out[5] = 1 - xx - zz; |
|
out[6] = zy + wx; |
|
out[7] = 0; |
|
|
|
out[8] = zx + wy; |
|
out[9] = zy - wx; |
|
out[10] = 1 - xx - yy; |
|
out[11] = 0; |
|
|
|
out[12] = 0; |
|
out[13] = 0; |
|
out[14] = 0; |
|
out[15] = 1; |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Generates a frustum matrix with the given bounds |
|
* |
|
* @param {mat4} out mat4 frustum matrix will be written into |
|
* @param {Number} left Left bound of the frustum |
|
* @param {Number} right Right bound of the frustum |
|
* @param {Number} bottom Bottom bound of the frustum |
|
* @param {Number} top Top bound of the frustum |
|
* @param {Number} near Near bound of the frustum |
|
* @param {Number} far Far bound of the frustum |
|
* @returns {mat4} out |
|
*/ |
|
function frustum(out, left, right, bottom, top, near, far) { |
|
let rl = 1 / (right - left); |
|
let tb = 1 / (top - bottom); |
|
let nf = 1 / (near - far); |
|
out[0] = (near * 2) * rl; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 0; |
|
out[4] = 0; |
|
out[5] = (near * 2) * tb; |
|
out[6] = 0; |
|
out[7] = 0; |
|
out[8] = (right + left) * rl; |
|
out[9] = (top + bottom) * tb; |
|
out[10] = (far + near) * nf; |
|
out[11] = -1; |
|
out[12] = 0; |
|
out[13] = 0; |
|
out[14] = (far * near * 2) * nf; |
|
out[15] = 0; |
|
return out; |
|
} |
|
|
|
/** |
|
* Generates a perspective projection matrix with the given bounds |
|
* |
|
* @param {mat4} out mat4 frustum matrix will be written into |
|
* @param {number} fovy Vertical field of view in radians |
|
* @param {number} aspect Aspect ratio. typically viewport width/height |
|
* @param {number} near Near bound of the frustum |
|
* @param {number} far Far bound of the frustum |
|
* @returns {mat4} out |
|
*/ |
|
function perspective(out, fovy, aspect, near, far) { |
|
let f = 1.0 / Math.tan(fovy / 2); |
|
let nf = 1 / (near - far); |
|
out[0] = f / aspect; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 0; |
|
out[4] = 0; |
|
out[5] = f; |
|
out[6] = 0; |
|
out[7] = 0; |
|
out[8] = 0; |
|
out[9] = 0; |
|
out[10] = (far + near) * nf; |
|
out[11] = -1; |
|
out[12] = 0; |
|
out[13] = 0; |
|
out[14] = (2 * far * near) * nf; |
|
out[15] = 0; |
|
return out; |
|
} |
|
|
|
/** |
|
* Generates a perspective projection matrix with the given field of view. |
|
* This is primarily useful for generating projection matrices to be used |
|
* with the still experiemental WebVR API. |
|
* |
|
* @param {mat4} out mat4 frustum matrix will be written into |
|
* @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees |
|
* @param {number} near Near bound of the frustum |
|
* @param {number} far Far bound of the frustum |
|
* @returns {mat4} out |
|
*/ |
|
function perspectiveFromFieldOfView(out, fov, near, far) { |
|
let upTan = Math.tan(fov.upDegrees * Math.PI/180.0); |
|
let downTan = Math.tan(fov.downDegrees * Math.PI/180.0); |
|
let leftTan = Math.tan(fov.leftDegrees * Math.PI/180.0); |
|
let rightTan = Math.tan(fov.rightDegrees * Math.PI/180.0); |
|
let xScale = 2.0 / (leftTan + rightTan); |
|
let yScale = 2.0 / (upTan + downTan); |
|
|
|
out[0] = xScale; |
|
out[1] = 0.0; |
|
out[2] = 0.0; |
|
out[3] = 0.0; |
|
out[4] = 0.0; |
|
out[5] = yScale; |
|
out[6] = 0.0; |
|
out[7] = 0.0; |
|
out[8] = -((leftTan - rightTan) * xScale * 0.5); |
|
out[9] = ((upTan - downTan) * yScale * 0.5); |
|
out[10] = far / (near - far); |
|
out[11] = -1.0; |
|
out[12] = 0.0; |
|
out[13] = 0.0; |
|
out[14] = (far * near) / (near - far); |
|
out[15] = 0.0; |
|
return out; |
|
} |
|
|
|
/** |
|
* Generates a orthogonal projection matrix with the given bounds |
|
* |
|
* @param {mat4} out mat4 frustum matrix will be written into |
|
* @param {number} left Left bound of the frustum |
|
* @param {number} right Right bound of the frustum |
|
* @param {number} bottom Bottom bound of the frustum |
|
* @param {number} top Top bound of the frustum |
|
* @param {number} near Near bound of the frustum |
|
* @param {number} far Far bound of the frustum |
|
* @returns {mat4} out |
|
*/ |
|
function ortho(out, left, right, bottom, top, near, far) { |
|
let lr = 1 / (left - right); |
|
let bt = 1 / (bottom - top); |
|
let nf = 1 / (near - far); |
|
out[0] = -2 * lr; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 0; |
|
out[4] = 0; |
|
out[5] = -2 * bt; |
|
out[6] = 0; |
|
out[7] = 0; |
|
out[8] = 0; |
|
out[9] = 0; |
|
out[10] = 2 * nf; |
|
out[11] = 0; |
|
out[12] = (left + right) * lr; |
|
out[13] = (top + bottom) * bt; |
|
out[14] = (far + near) * nf; |
|
out[15] = 1; |
|
return out; |
|
} |
|
|
|
/** |
|
* Generates a look-at matrix with the given eye position, focal point, and up axis |
|
* |
|
* @param {mat4} out mat4 frustum matrix will be written into |
|
* @param {vec3} eye Position of the viewer |
|
* @param {vec3} center Point the viewer is looking at |
|
* @param {vec3} up vec3 pointing up |
|
* @returns {mat4} out |
|
*/ |
|
function lookAt(out, eye, center, up) { |
|
let x0, x1, x2, y0, y1, y2, z0, z1, z2, len; |
|
let eyex = eye[0]; |
|
let eyey = eye[1]; |
|
let eyez = eye[2]; |
|
let upx = up[0]; |
|
let upy = up[1]; |
|
let upz = up[2]; |
|
let centerx = center[0]; |
|
let centery = center[1]; |
|
let centerz = center[2]; |
|
|
|
if (Math.abs(eyex - centerx) < __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"] && |
|
Math.abs(eyey - centery) < __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"] && |
|
Math.abs(eyez - centerz) < __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]) { |
|
return mat4.identity(out); |
|
} |
|
|
|
z0 = eyex - centerx; |
|
z1 = eyey - centery; |
|
z2 = eyez - centerz; |
|
|
|
len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2); |
|
z0 *= len; |
|
z1 *= len; |
|
z2 *= len; |
|
|
|
x0 = upy * z2 - upz * z1; |
|
x1 = upz * z0 - upx * z2; |
|
x2 = upx * z1 - upy * z0; |
|
len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2); |
|
if (!len) { |
|
x0 = 0; |
|
x1 = 0; |
|
x2 = 0; |
|
} else { |
|
len = 1 / len; |
|
x0 *= len; |
|
x1 *= len; |
|
x2 *= len; |
|
} |
|
|
|
y0 = z1 * x2 - z2 * x1; |
|
y1 = z2 * x0 - z0 * x2; |
|
y2 = z0 * x1 - z1 * x0; |
|
|
|
len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2); |
|
if (!len) { |
|
y0 = 0; |
|
y1 = 0; |
|
y2 = 0; |
|
} else { |
|
len = 1 / len; |
|
y0 *= len; |
|
y1 *= len; |
|
y2 *= len; |
|
} |
|
|
|
out[0] = x0; |
|
out[1] = y0; |
|
out[2] = z0; |
|
out[3] = 0; |
|
out[4] = x1; |
|
out[5] = y1; |
|
out[6] = z1; |
|
out[7] = 0; |
|
out[8] = x2; |
|
out[9] = y2; |
|
out[10] = z2; |
|
out[11] = 0; |
|
out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez); |
|
out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez); |
|
out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez); |
|
out[15] = 1; |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Generates a matrix that makes something look at something else. |
|
* |
|
* @param {mat4} out mat4 frustum matrix will be written into |
|
* @param {vec3} eye Position of the viewer |
|
* @param {vec3} center Point the viewer is looking at |
|
* @param {vec3} up vec3 pointing up |
|
* @returns {mat4} out |
|
*/ |
|
function targetTo(out, eye, target, up) { |
|
let eyex = eye[0], |
|
eyey = eye[1], |
|
eyez = eye[2], |
|
upx = up[0], |
|
upy = up[1], |
|
upz = up[2]; |
|
|
|
let z0 = eyex - target[0], |
|
z1 = eyey - target[1], |
|
z2 = eyez - target[2]; |
|
|
|
let len = z0*z0 + z1*z1 + z2*z2; |
|
if (len > 0) { |
|
len = 1 / Math.sqrt(len); |
|
z0 *= len; |
|
z1 *= len; |
|
z2 *= len; |
|
} |
|
|
|
let x0 = upy * z2 - upz * z1, |
|
x1 = upz * z0 - upx * z2, |
|
x2 = upx * z1 - upy * z0; |
|
|
|
out[0] = x0; |
|
out[1] = x1; |
|
out[2] = x2; |
|
out[3] = 0; |
|
out[4] = z1 * x2 - z2 * x1; |
|
out[5] = z2 * x0 - z0 * x2; |
|
out[6] = z0 * x1 - z1 * x0; |
|
out[7] = 0; |
|
out[8] = z0; |
|
out[9] = z1; |
|
out[10] = z2; |
|
out[11] = 0; |
|
out[12] = eyex; |
|
out[13] = eyey; |
|
out[14] = eyez; |
|
out[15] = 1; |
|
return out; |
|
}; |
|
|
|
/** |
|
* Returns a string representation of a mat4 |
|
* |
|
* @param {mat4} a matrix to represent as a string |
|
* @returns {String} string representation of the matrix |
|
*/ |
|
function str(a) { |
|
return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + |
|
a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + |
|
a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' + |
|
a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')'; |
|
} |
|
|
|
/** |
|
* Returns Frobenius norm of a mat4 |
|
* |
|
* @param {mat4} a the matrix to calculate Frobenius norm of |
|
* @returns {Number} Frobenius norm |
|
*/ |
|
function frob(a) { |
|
return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2) + Math.pow(a[9], 2) + Math.pow(a[10], 2) + Math.pow(a[11], 2) + Math.pow(a[12], 2) + Math.pow(a[13], 2) + Math.pow(a[14], 2) + Math.pow(a[15], 2) )) |
|
} |
|
|
|
/** |
|
* Adds two mat4's |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the first operand |
|
* @param {mat4} b the second operand |
|
* @returns {mat4} out |
|
*/ |
|
function add(out, a, b) { |
|
out[0] = a[0] + b[0]; |
|
out[1] = a[1] + b[1]; |
|
out[2] = a[2] + b[2]; |
|
out[3] = a[3] + b[3]; |
|
out[4] = a[4] + b[4]; |
|
out[5] = a[5] + b[5]; |
|
out[6] = a[6] + b[6]; |
|
out[7] = a[7] + b[7]; |
|
out[8] = a[8] + b[8]; |
|
out[9] = a[9] + b[9]; |
|
out[10] = a[10] + b[10]; |
|
out[11] = a[11] + b[11]; |
|
out[12] = a[12] + b[12]; |
|
out[13] = a[13] + b[13]; |
|
out[14] = a[14] + b[14]; |
|
out[15] = a[15] + b[15]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Subtracts matrix b from matrix a |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the first operand |
|
* @param {mat4} b the second operand |
|
* @returns {mat4} out |
|
*/ |
|
function subtract(out, a, b) { |
|
out[0] = a[0] - b[0]; |
|
out[1] = a[1] - b[1]; |
|
out[2] = a[2] - b[2]; |
|
out[3] = a[3] - b[3]; |
|
out[4] = a[4] - b[4]; |
|
out[5] = a[5] - b[5]; |
|
out[6] = a[6] - b[6]; |
|
out[7] = a[7] - b[7]; |
|
out[8] = a[8] - b[8]; |
|
out[9] = a[9] - b[9]; |
|
out[10] = a[10] - b[10]; |
|
out[11] = a[11] - b[11]; |
|
out[12] = a[12] - b[12]; |
|
out[13] = a[13] - b[13]; |
|
out[14] = a[14] - b[14]; |
|
out[15] = a[15] - b[15]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Multiply each element of the matrix by a scalar. |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the matrix to scale |
|
* @param {Number} b amount to scale the matrix's elements by |
|
* @returns {mat4} out |
|
*/ |
|
function multiplyScalar(out, a, b) { |
|
out[0] = a[0] * b; |
|
out[1] = a[1] * b; |
|
out[2] = a[2] * b; |
|
out[3] = a[3] * b; |
|
out[4] = a[4] * b; |
|
out[5] = a[5] * b; |
|
out[6] = a[6] * b; |
|
out[7] = a[7] * b; |
|
out[8] = a[8] * b; |
|
out[9] = a[9] * b; |
|
out[10] = a[10] * b; |
|
out[11] = a[11] * b; |
|
out[12] = a[12] * b; |
|
out[13] = a[13] * b; |
|
out[14] = a[14] * b; |
|
out[15] = a[15] * b; |
|
return out; |
|
} |
|
|
|
/** |
|
* Adds two mat4's after multiplying each element of the second operand by a scalar value. |
|
* |
|
* @param {mat4} out the receiving vector |
|
* @param {mat4} a the first operand |
|
* @param {mat4} b the second operand |
|
* @param {Number} scale the amount to scale b's elements by before adding |
|
* @returns {mat4} out |
|
*/ |
|
function multiplyScalarAndAdd(out, a, b, scale) { |
|
out[0] = a[0] + (b[0] * scale); |
|
out[1] = a[1] + (b[1] * scale); |
|
out[2] = a[2] + (b[2] * scale); |
|
out[3] = a[3] + (b[3] * scale); |
|
out[4] = a[4] + (b[4] * scale); |
|
out[5] = a[5] + (b[5] * scale); |
|
out[6] = a[6] + (b[6] * scale); |
|
out[7] = a[7] + (b[7] * scale); |
|
out[8] = a[8] + (b[8] * scale); |
|
out[9] = a[9] + (b[9] * scale); |
|
out[10] = a[10] + (b[10] * scale); |
|
out[11] = a[11] + (b[11] * scale); |
|
out[12] = a[12] + (b[12] * scale); |
|
out[13] = a[13] + (b[13] * scale); |
|
out[14] = a[14] + (b[14] * scale); |
|
out[15] = a[15] + (b[15] * scale); |
|
return out; |
|
} |
|
|
|
/** |
|
* Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===) |
|
* |
|
* @param {mat4} a The first matrix. |
|
* @param {mat4} b The second matrix. |
|
* @returns {Boolean} True if the matrices are equal, false otherwise. |
|
*/ |
|
function exactEquals(a, b) { |
|
return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && |
|
a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && |
|
a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && |
|
a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15]; |
|
} |
|
|
|
/** |
|
* Returns whether or not the matrices have approximately the same elements in the same position. |
|
* |
|
* @param {mat4} a The first matrix. |
|
* @param {mat4} b The second matrix. |
|
* @returns {Boolean} True if the matrices are equal, false otherwise. |
|
*/ |
|
function equals(a, b) { |
|
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; |
|
let a4 = a[4], a5 = a[5], a6 = a[6], a7 = a[7]; |
|
let a8 = a[8], a9 = a[9], a10 = a[10], a11 = a[11]; |
|
let a12 = a[12], a13 = a[13], a14 = a[14], a15 = a[15]; |
|
|
|
let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; |
|
let b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7]; |
|
let b8 = b[8], b9 = b[9], b10 = b[10], b11 = b[11]; |
|
let b12 = b[12], b13 = b[13], b14 = b[14], b15 = b[15]; |
|
|
|
return (Math.abs(a0 - b0) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a0), Math.abs(b0)) && |
|
Math.abs(a1 - b1) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a1), Math.abs(b1)) && |
|
Math.abs(a2 - b2) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a2), Math.abs(b2)) && |
|
Math.abs(a3 - b3) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a3), Math.abs(b3)) && |
|
Math.abs(a4 - b4) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a4), Math.abs(b4)) && |
|
Math.abs(a5 - b5) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a5), Math.abs(b5)) && |
|
Math.abs(a6 - b6) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a6), Math.abs(b6)) && |
|
Math.abs(a7 - b7) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a7), Math.abs(b7)) && |
|
Math.abs(a8 - b8) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a8), Math.abs(b8)) && |
|
Math.abs(a9 - b9) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a9), Math.abs(b9)) && |
|
Math.abs(a10 - b10) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a10), Math.abs(b10)) && |
|
Math.abs(a11 - b11) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a11), Math.abs(b11)) && |
|
Math.abs(a12 - b12) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a12), Math.abs(b12)) && |
|
Math.abs(a13 - b13) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a13), Math.abs(b13)) && |
|
Math.abs(a14 - b14) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a14), Math.abs(b14)) && |
|
Math.abs(a15 - b15) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a15), Math.abs(b15))); |
|
} |
|
|
|
/** |
|
* Alias for {@link mat4.multiply} |
|
* @function |
|
*/ |
|
const mul = multiply; |
|
/* harmony export (immutable) */ __webpack_exports__["mul"] = mul; |
|
|
|
|
|
/** |
|
* Alias for {@link mat4.subtract} |
|
* @function |
|
*/ |
|
const sub = subtract; |
|
/* harmony export (immutable) */ __webpack_exports__["sub"] = sub; |
|
|
|
|
|
|
|
/***/ }), |
|
/* 18 */ |
|
/***/ (function(module, __webpack_exports__, __webpack_require__) { |
|
|
|
"use strict"; |
|
Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); |
|
/* harmony export (immutable) */ __webpack_exports__["create"] = create; |
|
/* harmony export (immutable) */ __webpack_exports__["identity"] = identity; |
|
/* harmony export (immutable) */ __webpack_exports__["setAxisAngle"] = setAxisAngle; |
|
/* harmony export (immutable) */ __webpack_exports__["getAxisAngle"] = getAxisAngle; |
|
/* harmony export (immutable) */ __webpack_exports__["multiply"] = multiply; |
|
/* harmony export (immutable) */ __webpack_exports__["rotateX"] = rotateX; |
|
/* harmony export (immutable) */ __webpack_exports__["rotateY"] = rotateY; |
|
/* harmony export (immutable) */ __webpack_exports__["rotateZ"] = rotateZ; |
|
/* harmony export (immutable) */ __webpack_exports__["calculateW"] = calculateW; |
|
/* harmony export (immutable) */ __webpack_exports__["slerp"] = slerp; |
|
/* harmony export (immutable) */ __webpack_exports__["invert"] = invert; |
|
/* harmony export (immutable) */ __webpack_exports__["conjugate"] = conjugate; |
|
/* harmony export (immutable) */ __webpack_exports__["fromMat3"] = fromMat3; |
|
/* harmony export (immutable) */ __webpack_exports__["fromEuler"] = fromEuler; |
|
/* harmony export (immutable) */ __webpack_exports__["str"] = str; |
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__common__ = __webpack_require__(0); |
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__mat3__ = __webpack_require__(2); |
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__vec3__ = __webpack_require__(3); |
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__vec4__ = __webpack_require__(4); |
|
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. |
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
|
of this software and associated documentation files (the "Software"), to deal |
|
in the Software without restriction, including without limitation the rights |
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
copies of the Software, and to permit persons to whom the Software is |
|
furnished to do so, subject to the following conditions: |
|
|
|
The above copyright notice and this permission notice shall be included in |
|
all copies or substantial portions of the Software. |
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
THE SOFTWARE. */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
* Quaternion |
|
* @module quat |
|
*/ |
|
|
|
/** |
|
* Creates a new identity quat |
|
* |
|
* @returns {quat} a new quaternion |
|
*/ |
|
function create() { |
|
let out = new __WEBPACK_IMPORTED_MODULE_0__common__["ARRAY_TYPE"](4); |
|
out[0] = 0; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 1; |
|
return out; |
|
} |
|
|
|
/** |
|
* Set a quat to the identity quaternion |
|
* |
|
* @param {quat} out the receiving quaternion |
|
* @returns {quat} out |
|
*/ |
|
function identity(out) { |
|
out[0] = 0; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 1; |
|
return out; |
|
} |
|
|
|
/** |
|
* Sets a quat from the given angle and rotation axis, |
|
* then returns it. |
|
* |
|
* @param {quat} out the receiving quaternion |
|
* @param {vec3} axis the axis around which to rotate |
|
* @param {Number} rad the angle in radians |
|
* @returns {quat} out |
|
**/ |
|
function setAxisAngle(out, axis, rad) { |
|
rad = rad * 0.5; |
|
let s = Math.sin(rad); |
|
out[0] = s * axis[0]; |
|
out[1] = s * axis[1]; |
|
out[2] = s * axis[2]; |
|
out[3] = Math.cos(rad); |
|
return out; |
|
} |
|
|
|
/** |
|
* Gets the rotation axis and angle for a given |
|
* quaternion. If a quaternion is created with |
|
* setAxisAngle, this method will return the same |
|
* values as providied in the original parameter list |
|
* OR functionally equivalent values. |
|
* Example: The quaternion formed by axis [0, 0, 1] and |
|
* angle -90 is the same as the quaternion formed by |
|
* [0, 0, 1] and 270. This method favors the latter. |
|
* @param {vec3} out_axis Vector receiving the axis of rotation |
|
* @param {quat} q Quaternion to be decomposed |
|
* @return {Number} Angle, in radians, of the rotation |
|
*/ |
|
function getAxisAngle(out_axis, q) { |
|
let rad = Math.acos(q[3]) * 2.0; |
|
let s = Math.sin(rad / 2.0); |
|
if (s != 0.0) { |
|
out_axis[0] = q[0] / s; |
|
out_axis[1] = q[1] / s; |
|
out_axis[2] = q[2] / s; |
|
} else { |
|
// If s is zero, return any axis (no rotation - axis does not matter) |
|
out_axis[0] = 1; |
|
out_axis[1] = 0; |
|
out_axis[2] = 0; |
|
} |
|
return rad; |
|
} |
|
|
|
/** |
|
* Multiplies two quat's |
|
* |
|
* @param {quat} out the receiving quaternion |
|
* @param {quat} a the first operand |
|
* @param {quat} b the second operand |
|
* @returns {quat} out |
|
*/ |
|
function multiply(out, a, b) { |
|
let ax = a[0], ay = a[1], az = a[2], aw = a[3]; |
|
let bx = b[0], by = b[1], bz = b[2], bw = b[3]; |
|
|
|
out[0] = ax * bw + aw * bx + ay * bz - az * by; |
|
out[1] = ay * bw + aw * by + az * bx - ax * bz; |
|
out[2] = az * bw + aw * bz + ax * by - ay * bx; |
|
out[3] = aw * bw - ax * bx - ay * by - az * bz; |
|
return out; |
|
} |
|
|
|
/** |
|
* Rotates a quaternion by the given angle about the X axis |
|
* |
|
* @param {quat} out quat receiving operation result |
|
* @param {quat} a quat to rotate |
|
* @param {number} rad angle (in radians) to rotate |
|
* @returns {quat} out |
|
*/ |
|
function rotateX(out, a, rad) { |
|
rad *= 0.5; |
|
|
|
let ax = a[0], ay = a[1], az = a[2], aw = a[3]; |
|
let bx = Math.sin(rad), bw = Math.cos(rad); |
|
|
|
out[0] = ax * bw + aw * bx; |
|
out[1] = ay * bw + az * bx; |
|
out[2] = az * bw - ay * bx; |
|
out[3] = aw * bw - ax * bx; |
|
return out; |
|
} |
|
|
|
/** |
|
* Rotates a quaternion by the given angle about the Y axis |
|
* |
|
* @param {quat} out quat receiving operation result |
|
* @param {quat} a quat to rotate |
|
* @param {number} rad angle (in radians) to rotate |
|
* @returns {quat} out |
|
*/ |
|
function rotateY(out, a, rad) { |
|
rad *= 0.5; |
|
|
|
let ax = a[0], ay = a[1], az = a[2], aw = a[3]; |
|
let by = Math.sin(rad), bw = Math.cos(rad); |
|
|
|
out[0] = ax * bw - az * by; |
|
out[1] = ay * bw + aw * by; |
|
out[2] = az * bw + ax * by; |
|
out[3] = aw * bw - ay * by; |
|
return out; |
|
} |
|
|
|
/** |
|
* Rotates a quaternion by the given angle about the Z axis |
|
* |
|
* @param {quat} out quat receiving operation result |
|
* @param {quat} a quat to rotate |
|
* @param {number} rad angle (in radians) to rotate |
|
* @returns {quat} out |
|
*/ |
|
function rotateZ(out, a, rad) { |
|
rad *= 0.5; |
|
|
|
let ax = a[0], ay = a[1], az = a[2], aw = a[3]; |
|
let bz = Math.sin(rad), bw = Math.cos(rad); |
|
|
|
out[0] = ax * bw + ay * bz; |
|
out[1] = ay * bw - ax * bz; |
|
out[2] = az * bw + aw * bz; |
|
out[3] = aw * bw - az * bz; |
|
return out; |
|
} |
|
|
|
/** |
|
* Calculates the W component of a quat from the X, Y, and Z components. |
|
* Assumes that quaternion is 1 unit in length. |
|
* Any existing W component will be ignored. |
|
* |
|
* @param {quat} out the receiving quaternion |
|
* @param {quat} a quat to calculate W component of |
|
* @returns {quat} out |
|
*/ |
|
function calculateW(out, a) { |
|
let x = a[0], y = a[1], z = a[2]; |
|
|
|
out[0] = x; |
|
out[1] = y; |
|
out[2] = z; |
|
out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); |
|
return out; |
|
} |
|
|
|
/** |
|
* Performs a spherical linear interpolation between two quat |
|
* |
|
* @param {quat} out the receiving quaternion |
|
* @param {quat} a the first operand |
|
* @param {quat} b the second operand |
|
* @param {Number} t interpolation amount between the two inputs |
|
* @returns {quat} out |
|
*/ |
|
function slerp(out, a, b, t) { |
|
// benchmarks: |
|
// http://jsperf.com/quaternion-slerp-implementations |
|
let ax = a[0], ay = a[1], az = a[2], aw = a[3]; |
|
let bx = b[0], by = b[1], bz = b[2], bw = b[3]; |
|
|
|
let omega, cosom, sinom, scale0, scale1; |
|
|
|
// calc cosine |
|
cosom = ax * bx + ay * by + az * bz + aw * bw; |
|
// adjust signs (if necessary) |
|
if ( cosom < 0.0 ) { |
|
cosom = -cosom; |
|
bx = - bx; |
|
by = - by; |
|
bz = - bz; |
|
bw = - bw; |
|
} |
|
// calculate coefficients |
|
if ( (1.0 - cosom) > 0.000001 ) { |
|
// standard case (slerp) |
|
omega = Math.acos(cosom); |
|
sinom = Math.sin(omega); |
|
scale0 = Math.sin((1.0 - t) * omega) / sinom; |
|
scale1 = Math.sin(t * omega) / sinom; |
|
} else { |
|
// "from" and "to" quaternions are very close |
|
// ... so we can do a linear interpolation |
|
scale0 = 1.0 - t; |
|
scale1 = t; |
|
} |
|
// calculate final values |
|
out[0] = scale0 * ax + scale1 * bx; |
|
out[1] = scale0 * ay + scale1 * by; |
|
out[2] = scale0 * az + scale1 * bz; |
|
out[3] = scale0 * aw + scale1 * bw; |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Calculates the inverse of a quat |
|
* |
|
* @param {quat} out the receiving quaternion |
|
* @param {quat} a quat to calculate inverse of |
|
* @returns {quat} out |
|
*/ |
|
function invert(out, a) { |
|
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; |
|
let dot = a0*a0 + a1*a1 + a2*a2 + a3*a3; |
|
let invDot = dot ? 1.0/dot : 0; |
|
|
|
// TODO: Would be faster to return [0,0,0,0] immediately if dot == 0 |
|
|
|
out[0] = -a0*invDot; |
|
out[1] = -a1*invDot; |
|
out[2] = -a2*invDot; |
|
out[3] = a3*invDot; |
|
return out; |
|
} |
|
|
|
/** |
|
* Calculates the conjugate of a quat |
|
* If the quaternion is normalized, this function is faster than quat.inverse and produces the same result. |
|
* |
|
* @param {quat} out the receiving quaternion |
|
* @param {quat} a quat to calculate conjugate of |
|
* @returns {quat} out |
|
*/ |
|
function conjugate(out, a) { |
|
out[0] = -a[0]; |
|
out[1] = -a[1]; |
|
out[2] = -a[2]; |
|
out[3] = a[3]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a quaternion from the given 3x3 rotation matrix. |
|
* |
|
* NOTE: The resultant quaternion is not normalized, so you should be sure |
|
* to renormalize the quaternion yourself where necessary. |
|
* |
|
* @param {quat} out the receiving quaternion |
|
* @param {mat3} m rotation matrix |
|
* @returns {quat} out |
|
* @function |
|
*/ |
|
function fromMat3(out, m) { |
|
// Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes |
|
// article "Quaternion Calculus and Fast Animation". |
|
let fTrace = m[0] + m[4] + m[8]; |
|
let fRoot; |
|
|
|
if ( fTrace > 0.0 ) { |
|
// |w| > 1/2, may as well choose w > 1/2 |
|
fRoot = Math.sqrt(fTrace + 1.0); // 2w |
|
out[3] = 0.5 * fRoot; |
|
fRoot = 0.5/fRoot; // 1/(4w) |
|
out[0] = (m[5]-m[7])*fRoot; |
|
out[1] = (m[6]-m[2])*fRoot; |
|
out[2] = (m[1]-m[3])*fRoot; |
|
} else { |
|
// |w| <= 1/2 |
|
let i = 0; |
|
if ( m[4] > m[0] ) |
|
i = 1; |
|
if ( m[8] > m[i*3+i] ) |
|
i = 2; |
|
let j = (i+1)%3; |
|
let k = (i+2)%3; |
|
|
|
fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0); |
|
out[i] = 0.5 * fRoot; |
|
fRoot = 0.5 / fRoot; |
|
out[3] = (m[j*3+k] - m[k*3+j]) * fRoot; |
|
out[j] = (m[j*3+i] + m[i*3+j]) * fRoot; |
|
out[k] = (m[k*3+i] + m[i*3+k]) * fRoot; |
|
} |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a quaternion from the given euler angle x, y, z. |
|
* |
|
* @param {quat} out the receiving quaternion |
|
* @param {x} Angle to rotate around X axis in degrees. |
|
* @param {y} Angle to rotate around Y axis in degrees. |
|
* @param {z} Angle to rotate around Z axis in degrees. |
|
* @returns {quat} out |
|
* @function |
|
*/ |
|
function fromEuler(out, x, y, z) { |
|
let halfToRad = 0.5 * Math.PI / 180.0; |
|
x *= halfToRad; |
|
y *= halfToRad; |
|
z *= halfToRad; |
|
|
|
let sx = Math.sin(x); |
|
let cx = Math.cos(x); |
|
let sy = Math.sin(y); |
|
let cy = Math.cos(y); |
|
let sz = Math.sin(z); |
|
let cz = Math.cos(z); |
|
|
|
out[0] = sx * cy * cz - cx * sy * sz; |
|
out[1] = cx * sy * cz + sx * cy * sz; |
|
out[2] = cx * cy * sz - sx * sy * cz; |
|
out[3] = cx * cy * cz + sx * sy * sz; |
|
|
|
return out; |
|
} |
|
|
|
/** |
|
* Returns a string representation of a quatenion |
|
* |
|
* @param {quat} a vector to represent as a string |
|
* @returns {String} string representation of the vector |
|
*/ |
|
function str(a) { |
|
return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; |
|
} |
|
|
|
/** |
|
* Creates a new quat initialized with values from an existing quaternion |
|
* |
|
* @param {quat} a quaternion to clone |
|
* @returns {quat} a new quaternion |
|
* @function |
|
*/ |
|
const clone = __WEBPACK_IMPORTED_MODULE_3__vec4__["clone"]; |
|
/* harmony export (immutable) */ __webpack_exports__["clone"] = clone; |
|
|
|
|
|
/** |
|
* Creates a new quat initialized with the given values |
|
* |
|
* @param {Number} x X component |
|
* @param {Number} y Y component |
|
* @param {Number} z Z component |
|
* @param {Number} w W component |
|
* @returns {quat} a new quaternion |
|
* @function |
|
*/ |
|
const fromValues = __WEBPACK_IMPORTED_MODULE_3__vec4__["fromValues"]; |
|
/* harmony export (immutable) */ __webpack_exports__["fromValues"] = fromValues; |
|
|
|
|
|
/** |
|
* Copy the values from one quat to another |
|
* |
|
* @param {quat} out the receiving quaternion |
|
* @param {quat} a the source quaternion |
|
* @returns {quat} out |
|
* @function |
|
*/ |
|
const copy = __WEBPACK_IMPORTED_MODULE_3__vec4__["copy"]; |
|
/* harmony export (immutable) */ __webpack_exports__["copy"] = copy; |
|
|
|
|
|
/** |
|
* Set the components of a quat to the given values |
|
* |
|
* @param {quat} out the receiving quaternion |
|
* @param {Number} x X component |
|
* @param {Number} y Y component |
|
* @param {Number} z Z component |
|
* @param {Number} w W component |
|
* @returns {quat} out |
|
* @function |
|
*/ |
|
const set = __WEBPACK_IMPORTED_MODULE_3__vec4__["set"]; |
|
/* harmony export (immutable) */ __webpack_exports__["set"] = set; |
|
|
|
|
|
/** |
|
* Adds two quat's |
|
* |
|
* @param {quat} out the receiving quaternion |
|
* @param {quat} a the first operand |
|
* @param {quat} b the second operand |
|
* @returns {quat} out |
|
* @function |
|
*/ |
|
const add = __WEBPACK_IMPORTED_MODULE_3__vec4__["add"]; |
|
/* harmony export (immutable) */ __webpack_exports__["add"] = add; |
|
|
|
|
|
/** |
|
* Alias for {@link quat.multiply} |
|
* @function |
|
*/ |
|
const mul = multiply; |
|
/* harmony export (immutable) */ __webpack_exports__["mul"] = mul; |
|
|
|
|
|
/** |
|
* Scales a quat by a scalar number |
|
* |
|
* @param {quat} out the receiving vector |
|
* @param {quat} a the vector to scale |
|
* @param {Number} b amount to scale the vector by |
|
* @returns {quat} out |
|
* @function |
|
*/ |
|
const scale = __WEBPACK_IMPORTED_MODULE_3__vec4__["scale"]; |
|
/* harmony export (immutable) */ __webpack_exports__["scale"] = scale; |
|
|
|
|
|
/** |
|
* Calculates the dot product of two quat's |
|
* |
|
* @param {quat} a the first operand |
|
* @param {quat} b the second operand |
|
* @returns {Number} dot product of a and b |
|
* @function |
|
*/ |
|
const dot = __WEBPACK_IMPORTED_MODULE_3__vec4__["dot"]; |
|
/* harmony export (immutable) */ __webpack_exports__["dot"] = dot; |
|
|
|
|
|
/** |
|
* Performs a linear interpolation between two quat's |
|
* |
|
* @param {quat} out the receiving quaternion |
|
* @param {quat} a the first operand |
|
* @param {quat} b the second operand |
|
* @param {Number} t interpolation amount between the two inputs |
|
* @returns {quat} out |
|
* @function |
|
*/ |
|
const lerp = __WEBPACK_IMPORTED_MODULE_3__vec4__["lerp"]; |
|
/* harmony export (immutable) */ __webpack_exports__["lerp"] = lerp; |
|
|
|
|
|
/** |
|
* Calculates the length of a quat |
|
* |
|
* @param {quat} a vector to calculate length of |
|
* @returns {Number} length of a |
|
*/ |
|
const length = __WEBPACK_IMPORTED_MODULE_3__vec4__["length"]; |
|
/* harmony export (immutable) */ __webpack_exports__["length"] = length; |
|
|
|
|
|
/** |
|
* Alias for {@link quat.length} |
|
* @function |
|
*/ |
|
const len = length; |
|
/* harmony export (immutable) */ __webpack_exports__["len"] = len; |
|
|
|
|
|
/** |
|
* Calculates the squared length of a quat |
|
* |
|
* @param {quat} a vector to calculate squared length of |
|
* @returns {Number} squared length of a |
|
* @function |
|
*/ |
|
const squaredLength = __WEBPACK_IMPORTED_MODULE_3__vec4__["squaredLength"]; |
|
/* harmony export (immutable) */ __webpack_exports__["squaredLength"] = squaredLength; |
|
|
|
|
|
/** |
|
* Alias for {@link quat.squaredLength} |
|
* @function |
|
*/ |
|
const sqrLen = squaredLength; |
|
/* harmony export (immutable) */ __webpack_exports__["sqrLen"] = sqrLen; |
|
|
|
|
|
/** |
|
* Normalize a quat |
|
* |
|
* @param {quat} out the receiving quaternion |
|
* @param {quat} a quaternion to normalize |
|
* @returns {quat} out |
|
* @function |
|
*/ |
|
const normalize = __WEBPACK_IMPORTED_MODULE_3__vec4__["normalize"]; |
|
/* harmony export (immutable) */ __webpack_exports__["normalize"] = normalize; |
|
|
|
|
|
/** |
|
* Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===) |
|
* |
|
* @param {quat} a The first quaternion. |
|
* @param {quat} b The second quaternion. |
|
* @returns {Boolean} True if the vectors are equal, false otherwise. |
|
*/ |
|
const exactEquals = __WEBPACK_IMPORTED_MODULE_3__vec4__["exactEquals"]; |
|
/* harmony export (immutable) */ __webpack_exports__["exactEquals"] = exactEquals; |
|
|
|
|
|
/** |
|
* Returns whether or not the quaternions have approximately the same elements in the same position. |
|
* |
|
* @param {quat} a The first vector. |
|
* @param {quat} b The second vector. |
|
* @returns {Boolean} True if the vectors are equal, false otherwise. |
|
*/ |
|
const equals = __WEBPACK_IMPORTED_MODULE_3__vec4__["equals"]; |
|
/* harmony export (immutable) */ __webpack_exports__["equals"] = equals; |
|
|
|
|
|
/** |
|
* Sets a quaternion to represent the shortest rotation from one |
|
* vector to another. |
|
* |
|
* Both vectors are assumed to be unit length. |
|
* |
|
* @param {quat} out the receiving quaternion. |
|
* @param {vec3} a the initial vector |
|
* @param {vec3} b the destination vector |
|
* @returns {quat} out |
|
*/ |
|
const rotationTo = (function() { |
|
let tmpvec3 = __WEBPACK_IMPORTED_MODULE_2__vec3__["create"](); |
|
let xUnitVec3 = __WEBPACK_IMPORTED_MODULE_2__vec3__["fromValues"](1,0,0); |
|
let yUnitVec3 = __WEBPACK_IMPORTED_MODULE_2__vec3__["fromValues"](0,1,0); |
|
|
|
return function(out, a, b) { |
|
let dot = __WEBPACK_IMPORTED_MODULE_2__vec3__["dot"](a, b); |
|
if (dot < -0.999999) { |
|
__WEBPACK_IMPORTED_MODULE_2__vec3__["cross"](tmpvec3, xUnitVec3, a); |
|
if (__WEBPACK_IMPORTED_MODULE_2__vec3__["len"](tmpvec3) < 0.000001) |
|
__WEBPACK_IMPORTED_MODULE_2__vec3__["cross"](tmpvec3, yUnitVec3, a); |
|
__WEBPACK_IMPORTED_MODULE_2__vec3__["normalize"](tmpvec3, tmpvec3); |
|
setAxisAngle(out, tmpvec3, Math.PI); |
|
return out; |
|
} else if (dot > 0.999999) { |
|
out[0] = 0; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 1; |
|
return out; |
|
} else { |
|
__WEBPACK_IMPORTED_MODULE_2__vec3__["cross"](tmpvec3, a, b); |
|
out[0] = tmpvec3[0]; |
|
out[1] = tmpvec3[1]; |
|
out[2] = tmpvec3[2]; |
|
out[3] = 1 + dot; |
|
return normalize(out, out); |
|
} |
|
}; |
|
})(); |
|
/* harmony export (immutable) */ __webpack_exports__["rotationTo"] = rotationTo; |
|
|
|
|
|
/** |
|
* Performs a spherical linear interpolation with two control points |
|
* |
|
* @param {quat} out the receiving quaternion |
|
* @param {quat} a the first operand |
|
* @param {quat} b the second operand |
|
* @param {quat} c the third operand |
|
* @param {quat} d the fourth operand |
|
* @param {Number} t interpolation amount |
|
* @returns {quat} out |
|
*/ |
|
const sqlerp = (function () { |
|
let temp1 = create(); |
|
let temp2 = create(); |
|
|
|
return function (out, a, b, c, d, t) { |
|
slerp(temp1, a, d, t); |
|
slerp(temp2, b, c, t); |
|
slerp(out, temp1, temp2, 2 * t * (1 - t)); |
|
|
|
return out; |
|
}; |
|
}()); |
|
/* harmony export (immutable) */ __webpack_exports__["sqlerp"] = sqlerp; |
|
|
|
|
|
/** |
|
* Sets the specified quaternion with values corresponding to the given |
|
* axes. Each axis is a vec3 and is expected to be unit length and |
|
* perpendicular to all other specified axes. |
|
* |
|
* @param {vec3} view the vector representing the viewing direction |
|
* @param {vec3} right the vector representing the local "right" direction |
|
* @param {vec3} up the vector representing the local "up" direction |
|
* @returns {quat} out |
|
*/ |
|
const setAxes = (function() { |
|
let matr = __WEBPACK_IMPORTED_MODULE_1__mat3__["create"](); |
|
|
|
return function(out, view, right, up) { |
|
matr[0] = right[0]; |
|
matr[3] = right[1]; |
|
matr[6] = right[2]; |
|
|
|
matr[1] = up[0]; |
|
matr[4] = up[1]; |
|
matr[7] = up[2]; |
|
|
|
matr[2] = -view[0]; |
|
matr[5] = -view[1]; |
|
matr[8] = -view[2]; |
|
|
|
return normalize(out, fromMat3(out, matr)); |
|
}; |
|
})(); |
|
/* harmony export (immutable) */ __webpack_exports__["setAxes"] = setAxes; |
|
|
|
|
|
|
|
/***/ }), |
|
/* 19 */ |
|
/***/ (function(module, __webpack_exports__, __webpack_require__) { |
|
|
|
"use strict"; |
|
Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); |
|
/* harmony export (immutable) */ __webpack_exports__["create"] = create; |
|
/* harmony export (immutable) */ __webpack_exports__["clone"] = clone; |
|
/* harmony export (immutable) */ __webpack_exports__["fromValues"] = fromValues; |
|
/* harmony export (immutable) */ __webpack_exports__["copy"] = copy; |
|
/* harmony export (immutable) */ __webpack_exports__["set"] = set; |
|
/* harmony export (immutable) */ __webpack_exports__["add"] = add; |
|
/* harmony export (immutable) */ __webpack_exports__["subtract"] = subtract; |
|
/* harmony export (immutable) */ __webpack_exports__["multiply"] = multiply; |
|
/* harmony export (immutable) */ __webpack_exports__["divide"] = divide; |
|
/* harmony export (immutable) */ __webpack_exports__["ceil"] = ceil; |
|
/* harmony export (immutable) */ __webpack_exports__["floor"] = floor; |
|
/* harmony export (immutable) */ __webpack_exports__["min"] = min; |
|
/* harmony export (immutable) */ __webpack_exports__["max"] = max; |
|
/* harmony export (immutable) */ __webpack_exports__["round"] = round; |
|
/* harmony export (immutable) */ __webpack_exports__["scale"] = scale; |
|
/* harmony export (immutable) */ __webpack_exports__["scaleAndAdd"] = scaleAndAdd; |
|
/* harmony export (immutable) */ __webpack_exports__["distance"] = distance; |
|
/* harmony export (immutable) */ __webpack_exports__["squaredDistance"] = squaredDistance; |
|
/* harmony export (immutable) */ __webpack_exports__["length"] = length; |
|
/* harmony export (immutable) */ __webpack_exports__["squaredLength"] = squaredLength; |
|
/* harmony export (immutable) */ __webpack_exports__["negate"] = negate; |
|
/* harmony export (immutable) */ __webpack_exports__["inverse"] = inverse; |
|
/* harmony export (immutable) */ __webpack_exports__["normalize"] = normalize; |
|
/* harmony export (immutable) */ __webpack_exports__["dot"] = dot; |
|
/* harmony export (immutable) */ __webpack_exports__["cross"] = cross; |
|
/* harmony export (immutable) */ __webpack_exports__["lerp"] = lerp; |
|
/* harmony export (immutable) */ __webpack_exports__["random"] = random; |
|
/* harmony export (immutable) */ __webpack_exports__["transformMat2"] = transformMat2; |
|
/* harmony export (immutable) */ __webpack_exports__["transformMat2d"] = transformMat2d; |
|
/* harmony export (immutable) */ __webpack_exports__["transformMat3"] = transformMat3; |
|
/* harmony export (immutable) */ __webpack_exports__["transformMat4"] = transformMat4; |
|
/* harmony export (immutable) */ __webpack_exports__["str"] = str; |
|
/* harmony export (immutable) */ __webpack_exports__["exactEquals"] = exactEquals; |
|
/* harmony export (immutable) */ __webpack_exports__["equals"] = equals; |
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__common__ = __webpack_require__(0); |
|
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. |
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
|
of this software and associated documentation files (the "Software"), to deal |
|
in the Software without restriction, including without limitation the rights |
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
copies of the Software, and to permit persons to whom the Software is |
|
furnished to do so, subject to the following conditions: |
|
|
|
The above copyright notice and this permission notice shall be included in |
|
all copies or substantial portions of the Software. |
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
THE SOFTWARE. */ |
|
|
|
|
|
|
|
/** |
|
* 2 Dimensional Vector |
|
* @module vec2 |
|
*/ |
|
|
|
/** |
|
* Creates a new, empty vec2 |
|
* |
|
* @returns {vec2} a new 2D vector |
|
*/ |
|
function create() { |
|
let out = new __WEBPACK_IMPORTED_MODULE_0__common__["ARRAY_TYPE"](2); |
|
out[0] = 0; |
|
out[1] = 0; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a new vec2 initialized with values from an existing vector |
|
* |
|
* @param {vec2} a vector to clone |
|
* @returns {vec2} a new 2D vector |
|
*/ |
|
function clone(a) { |
|
let out = new __WEBPACK_IMPORTED_MODULE_0__common__["ARRAY_TYPE"](2); |
|
out[0] = a[0]; |
|
out[1] = a[1]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Creates a new vec2 initialized with the given values |
|
* |
|
* @param {Number} x X component |
|
* @param {Number} y Y component |
|
* @returns {vec2} a new 2D vector |
|
*/ |
|
function fromValues(x, y) { |
|
let out = new __WEBPACK_IMPORTED_MODULE_0__common__["ARRAY_TYPE"](2); |
|
out[0] = x; |
|
out[1] = y; |
|
return out; |
|
} |
|
|
|
/** |
|
* Copy the values from one vec2 to another |
|
* |
|
* @param {vec2} out the receiving vector |
|
* @param {vec2} a the source vector |
|
* @returns {vec2} out |
|
*/ |
|
function copy(out, a) { |
|
out[0] = a[0]; |
|
out[1] = a[1]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Set the components of a vec2 to the given values |
|
* |
|
* @param {vec2} out the receiving vector |
|
* @param {Number} x X component |
|
* @param {Number} y Y component |
|
* @returns {vec2} out |
|
*/ |
|
function set(out, x, y) { |
|
out[0] = x; |
|
out[1] = y; |
|
return out; |
|
} |
|
|
|
/** |
|
* Adds two vec2's |
|
* |
|
* @param {vec2} out the receiving vector |
|
* @param {vec2} a the first operand |
|
* @param {vec2} b the second operand |
|
* @returns {vec2} out |
|
*/ |
|
function add(out, a, b) { |
|
out[0] = a[0] + b[0]; |
|
out[1] = a[1] + b[1]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Subtracts vector b from vector a |
|
* |
|
* @param {vec2} out the receiving vector |
|
* @param {vec2} a the first operand |
|
* @param {vec2} b the second operand |
|
* @returns {vec2} out |
|
*/ |
|
function subtract(out, a, b) { |
|
out[0] = a[0] - b[0]; |
|
out[1] = a[1] - b[1]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Multiplies two vec2's |
|
* |
|
* @param {vec2} out the receiving vector |
|
* @param {vec2} a the first operand |
|
* @param {vec2} b the second operand |
|
* @returns {vec2} out |
|
*/ |
|
function multiply(out, a, b) { |
|
out[0] = a[0] * b[0]; |
|
out[1] = a[1] * b[1]; |
|
return out; |
|
}; |
|
|
|
/** |
|
* Divides two vec2's |
|
* |
|
* @param {vec2} out the receiving vector |
|
* @param {vec2} a the first operand |
|
* @param {vec2} b the second operand |
|
* @returns {vec2} out |
|
*/ |
|
function divide(out, a, b) { |
|
out[0] = a[0] / b[0]; |
|
out[1] = a[1] / b[1]; |
|
return out; |
|
}; |
|
|
|
/** |
|
* Math.ceil the components of a vec2 |
|
* |
|
* @param {vec2} out the receiving vector |
|
* @param {vec2} a vector to ceil |
|
* @returns {vec2} out |
|
*/ |
|
function ceil(out, a) { |
|
out[0] = Math.ceil(a[0]); |
|
out[1] = Math.ceil(a[1]); |
|
return out; |
|
}; |
|
|
|
/** |
|
* Math.floor the components of a vec2 |
|
* |
|
* @param {vec2} out the receiving vector |
|
* @param {vec2} a vector to floor |
|
* @returns {vec2} out |
|
*/ |
|
function floor(out, a) { |
|
out[0] = Math.floor(a[0]); |
|
out[1] = Math.floor(a[1]); |
|
return out; |
|
}; |
|
|
|
/** |
|
* Returns the minimum of two vec2's |
|
* |
|
* @param {vec2} out the receiving vector |
|
* @param {vec2} a the first operand |
|
* @param {vec2} b the second operand |
|
* @returns {vec2} out |
|
*/ |
|
function min(out, a, b) { |
|
out[0] = Math.min(a[0], b[0]); |
|
out[1] = Math.min(a[1], b[1]); |
|
return out; |
|
}; |
|
|
|
/** |
|
* Returns the maximum of two vec2's |
|
* |
|
* @param {vec2} out the receiving vector |
|
* @param {vec2} a the first operand |
|
* @param {vec2} b the second operand |
|
* @returns {vec2} out |
|
*/ |
|
function max(out, a, b) { |
|
out[0] = Math.max(a[0], b[0]); |
|
out[1] = Math.max(a[1], b[1]); |
|
return out; |
|
}; |
|
|
|
/** |
|
* Math.round the components of a vec2 |
|
* |
|
* @param {vec2} out the receiving vector |
|
* @param {vec2} a vector to round |
|
* @returns {vec2} out |
|
*/ |
|
function round (out, a) { |
|
out[0] = Math.round(a[0]); |
|
out[1] = Math.round(a[1]); |
|
return out; |
|
}; |
|
|
|
/** |
|
* Scales a vec2 by a scalar number |
|
* |
|
* @param {vec2} out the receiving vector |
|
* @param {vec2} a the vector to scale |
|
* @param {Number} b amount to scale the vector by |
|
* @returns {vec2} out |
|
*/ |
|
function scale(out, a, b) { |
|
out[0] = a[0] * b; |
|
out[1] = a[1] * b; |
|
return out; |
|
}; |
|
|
|
/** |
|
* Adds two vec2's after scaling the second operand by a scalar value |
|
* |
|
* @param {vec2} out the receiving vector |
|
* @param {vec2} a the first operand |
|
* @param {vec2} b the second operand |
|
* @param {Number} scale the amount to scale b by before adding |
|
* @returns {vec2} out |
|
*/ |
|
function scaleAndAdd(out, a, b, scale) { |
|
out[0] = a[0] + (b[0] * scale); |
|
out[1] = a[1] + (b[1] * scale); |
|
return out; |
|
}; |
|
|
|
/** |
|
* Calculates the euclidian distance between two vec2's |
|
* |
|
* @param {vec2} a the first operand |
|
* @param {vec2} b the second operand |
|
* @returns {Number} distance between a and b |
|
*/ |
|
function distance(a, b) { |
|
var x = b[0] - a[0], |
|
y = b[1] - a[1]; |
|
return Math.sqrt(x*x + y*y); |
|
}; |
|
|
|
/** |
|
* Calculates the squared euclidian distance between two vec2's |
|
* |
|
* @param {vec2} a the first operand |
|
* @param {vec2} b the second operand |
|
* @returns {Number} squared distance between a and b |
|
*/ |
|
function squaredDistance(a, b) { |
|
var x = b[0] - a[0], |
|
y = b[1] - a[1]; |
|
return x*x + y*y; |
|
}; |
|
|
|
/** |
|
* Calculates the length of a vec2 |
|
* |
|
* @param {vec2} a vector to calculate length of |
|
* @returns {Number} length of a |
|
*/ |
|
function length(a) { |
|
var x = a[0], |
|
y = a[1]; |
|
return Math.sqrt(x*x + y*y); |
|
}; |
|
|
|
/** |
|
* Calculates the squared length of a vec2 |
|
* |
|
* @param {vec2} a vector to calculate squared length of |
|
* @returns {Number} squared length of a |
|
*/ |
|
function squaredLength (a) { |
|
var x = a[0], |
|
y = a[1]; |
|
return x*x + y*y; |
|
}; |
|
|
|
/** |
|
* Negates the components of a vec2 |
|
* |
|
* @param {vec2} out the receiving vector |
|
* @param {vec2} a vector to negate |
|
* @returns {vec2} out |
|
*/ |
|
function negate(out, a) { |
|
out[0] = -a[0]; |
|
out[1] = -a[1]; |
|
return out; |
|
}; |
|
|
|
/** |
|
* Returns the inverse of the components of a vec2 |
|
* |
|
* @param {vec2} out the receiving vector |
|
* @param {vec2} a vector to invert |
|
* @returns {vec2} out |
|
*/ |
|
function inverse(out, a) { |
|
out[0] = 1.0 / a[0]; |
|
out[1] = 1.0 / a[1]; |
|
return out; |
|
}; |
|
|
|
/** |
|
* Normalize a vec2 |
|
* |
|
* @param {vec2} out the receiving vector |
|
* @param {vec2} a vector to normalize |
|
* @returns {vec2} out |
|
*/ |
|
function normalize(out, a) { |
|
var x = a[0], |
|
y = a[1]; |
|
var len = x*x + y*y; |
|
if (len > 0) { |
|
//TODO: evaluate use of glm_invsqrt here? |
|
len = 1 / Math.sqrt(len); |
|
out[0] = a[0] * len; |
|
out[1] = a[1] * len; |
|
} |
|
return out; |
|
}; |
|
|
|
/** |
|
* Calculates the dot product of two vec2's |
|
* |
|
* @param {vec2} a the first operand |
|
* @param {vec2} b the second operand |
|
* @returns {Number} dot product of a and b |
|
*/ |
|
function dot(a, b) { |
|
return a[0] * b[0] + a[1] * b[1]; |
|
}; |
|
|
|
/** |
|
* Computes the cross product of two vec2's |
|
* Note that the cross product must by definition produce a 3D vector |
|
* |
|
* @param {vec3} out the receiving vector |
|
* @param {vec2} a the first operand |
|
* @param {vec2} b the second operand |
|
* @returns {vec3} out |
|
*/ |
|
function cross(out, a, b) { |
|
var z = a[0] * b[1] - a[1] * b[0]; |
|
out[0] = out[1] = 0; |
|
out[2] = z; |
|
return out; |
|
}; |
|
|
|
/** |
|
* Performs a linear interpolation between two vec2's |
|
* |
|
* @param {vec2} out the receiving vector |
|
* @param {vec2} a the first operand |
|
* @param {vec2} b the second operand |
|
* @param {Number} t interpolation amount between the two inputs |
|
* @returns {vec2} out |
|
*/ |
|
function lerp(out, a, b, t) { |
|
var ax = a[0], |
|
ay = a[1]; |
|
out[0] = ax + t * (b[0] - ax); |
|
out[1] = ay + t * (b[1] - ay); |
|
return out; |
|
}; |
|
|
|
/** |
|
* Generates a random vector with the given scale |
|
* |
|
* @param {vec2} out the receiving vector |
|
* @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned |
|
* @returns {vec2} out |
|
*/ |
|
function random(out, scale) { |
|
scale = scale || 1.0; |
|
var r = __WEBPACK_IMPORTED_MODULE_0__common__["RANDOM"]() * 2.0 * Math.PI; |
|
out[0] = Math.cos(r) * scale; |
|
out[1] = Math.sin(r) * scale; |
|
return out; |
|
}; |
|
|
|
/** |
|
* Transforms the vec2 with a mat2 |
|
* |
|
* @param {vec2} out the receiving vector |
|
* @param {vec2} a the vector to transform |
|
* @param {mat2} m matrix to transform with |
|
* @returns {vec2} out |
|
*/ |
|
function transformMat2(out, a, m) { |
|
var x = a[0], |
|
y = a[1]; |
|
out[0] = m[0] * x + m[2] * y; |
|
out[1] = m[1] * x + m[3] * y; |
|
return out; |
|
}; |
|
|
|
/** |
|
* Transforms the vec2 with a mat2d |
|
* |
|
* @param {vec2} out the receiving vector |
|
* @param {vec2} a the vector to transform |
|
* @param {mat2d} m matrix to transform with |
|
* @returns {vec2} out |
|
*/ |
|
function transformMat2d(out, a, m) { |
|
var x = a[0], |
|
y = a[1]; |
|
out[0] = m[0] * x + m[2] * y + m[4]; |
|
out[1] = m[1] * x + m[3] * y + m[5]; |
|
return out; |
|
}; |
|
|
|
/** |
|
* Transforms the vec2 with a mat3 |
|
* 3rd vector component is implicitly '1' |
|
* |
|
* @param {vec2} out the receiving vector |
|
* @param {vec2} a the vector to transform |
|
* @param {mat3} m matrix to transform with |
|
* @returns {vec2} out |
|
*/ |
|
function transformMat3(out, a, m) { |
|
var x = a[0], |
|
y = a[1]; |
|
out[0] = m[0] * x + m[3] * y + m[6]; |
|
out[1] = m[1] * x + m[4] * y + m[7]; |
|
return out; |
|
}; |
|
|
|
/** |
|
* Transforms the vec2 with a mat4 |
|
* 3rd vector component is implicitly '0' |
|
* 4th vector component is implicitly '1' |
|
* |
|
* @param {vec2} out the receiving vector |
|
* @param {vec2} a the vector to transform |
|
* @param {mat4} m matrix to transform with |
|
* @returns {vec2} out |
|
*/ |
|
function transformMat4(out, a, m) { |
|
let x = a[0]; |
|
let y = a[1]; |
|
out[0] = m[0] * x + m[4] * y + m[12]; |
|
out[1] = m[1] * x + m[5] * y + m[13]; |
|
return out; |
|
} |
|
|
|
/** |
|
* Returns a string representation of a vector |
|
* |
|
* @param {vec2} a vector to represent as a string |
|
* @returns {String} string representation of the vector |
|
*/ |
|
function str(a) { |
|
return 'vec2(' + a[0] + ', ' + a[1] + ')'; |
|
} |
|
|
|
/** |
|
* Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===) |
|
* |
|
* @param {vec2} a The first vector. |
|
* @param {vec2} b The second vector. |
|
* @returns {Boolean} True if the vectors are equal, false otherwise. |
|
*/ |
|
function exactEquals(a, b) { |
|
return a[0] === b[0] && a[1] === b[1]; |
|
} |
|
|
|
/** |
|
* Returns whether or not the vectors have approximately the same elements in the same position. |
|
* |
|
* @param {vec2} a The first vector. |
|
* @param {vec2} b The second vector. |
|
* @returns {Boolean} True if the vectors are equal, false otherwise. |
|
*/ |
|
function equals(a, b) { |
|
let a0 = a[0], a1 = a[1]; |
|
let b0 = b[0], b1 = b[1]; |
|
return (Math.abs(a0 - b0) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a0), Math.abs(b0)) && |
|
Math.abs(a1 - b1) <= __WEBPACK_IMPORTED_MODULE_0__common__["EPSILON"]*Math.max(1.0, Math.abs(a1), Math.abs(b1))); |
|
} |
|
|
|
/** |
|
* Alias for {@link vec2.length} |
|
* @function |
|
*/ |
|
const len = length; |
|
/* harmony export (immutable) */ __webpack_exports__["len"] = len; |
|
|
|
|
|
/** |
|
* Alias for {@link vec2.subtract} |
|
* @function |
|
*/ |
|
const sub = subtract; |
|
/* harmony export (immutable) */ __webpack_exports__["sub"] = sub; |
|
|
|
|
|
/** |
|
* Alias for {@link vec2.multiply} |
|
* @function |
|
*/ |
|
const mul = multiply; |
|
/* harmony export (immutable) */ __webpack_exports__["mul"] = mul; |
|
|
|
|
|
/** |
|
* Alias for {@link vec2.divide} |
|
* @function |
|
*/ |
|
const div = divide; |
|
/* harmony export (immutable) */ __webpack_exports__["div"] = div; |
|
|
|
|
|
/** |
|
* Alias for {@link vec2.distance} |
|
* @function |
|
*/ |
|
const dist = distance; |
|
/* harmony export (immutable) */ __webpack_exports__["dist"] = dist; |
|
|
|
|
|
/** |
|
* Alias for {@link vec2.squaredDistance} |
|
* @function |
|
*/ |
|
const sqrDist = squaredDistance; |
|
/* harmony export (immutable) */ __webpack_exports__["sqrDist"] = sqrDist; |
|
|
|
|
|
/** |
|
* Alias for {@link vec2.squaredLength} |
|
* @function |
|
*/ |
|
const sqrLen = squaredLength; |
|
/* harmony export (immutable) */ __webpack_exports__["sqrLen"] = sqrLen; |
|
|
|
|
|
/** |
|
* Perform some operation over an array of vec2s. |
|
* |
|
* @param {Array} a the array of vectors to iterate over |
|
* @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed |
|
* @param {Number} offset Number of elements to skip at the beginning of the array |
|
* @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array |
|
* @param {Function} fn Function to call for each vector in the array |
|
* @param {Object} [arg] additional argument to pass to fn |
|
* @returns {Array} a |
|
* @function |
|
*/ |
|
const forEach = (function() { |
|
let vec = create(); |
|
|
|
return function(a, stride, offset, count, fn, arg) { |
|
let i, l; |
|
if(!stride) { |
|
stride = 2; |
|
} |
|
|
|
if(!offset) { |
|
offset = 0; |
|
} |
|
|
|
if(count) { |
|
l = Math.min((count * stride) + offset, a.length); |
|
} else { |
|
l = a.length; |
|
} |
|
|
|
for(i = offset; i < l; i += stride) { |
|
vec[0] = a[i]; vec[1] = a[i+1]; |
|
fn(vec, vec, arg); |
|
a[i] = vec[0]; a[i+1] = vec[1]; |
|
} |
|
|
|
return a; |
|
}; |
|
})(); |
|
/* harmony export (immutable) */ __webpack_exports__["forEach"] = forEach; |
|
|
|
|
|
|
|
/***/ }), |
|
/* 20 */ |
|
/***/ (function(module, exports, __webpack_require__) { |
|
|
|
"use strict"; |
|
|
|
|
|
var glm = __webpack_require__(14) |
|
var vec3 = glm.vec3 |
|
var mat3 = glm.mat3 |
|
var mat4 = glm.mat4 |
|
var quat = glm.quat |
|
|
|
//Scratch variables |
|
var scratch0 = new Float32Array(16) |
|
var scratch1 = new Float32Array(16) |
|
|
|
function OrbitCamera(rotation, center, distance) { |
|
this.rotation = rotation |
|
this.center = center |
|
this.distance = distance |
|
} |
|
|
|
var proto = OrbitCamera.prototype |
|
|
|
proto.view = function(out) { |
|
if(!out) { |
|
out = mat4.create() |
|
} |
|
scratch1[0] = scratch1[1] = 0.0 |
|
scratch1[2] = -this.distance |
|
mat4.fromRotationTranslation(out, |
|
quat.conjugate(scratch0, this.rotation), |
|
scratch1) |
|
mat4.translate(out, out, vec3.negate(scratch0, this.center)) |
|
return out |
|
} |
|
|
|
proto.lookAt = function(eye, center, up) { |
|
mat4.lookAt(scratch0, eye, center, up) |
|
mat3.fromMat4(scratch0, scratch0) |
|
quat.fromMat3(this.rotation, scratch0) |
|
vec3.copy(this.center, center) |
|
this.distance = vec3.distance(eye, center) |
|
} |
|
|
|
proto.pan = function(dpan) { |
|
var d = this.distance |
|
scratch0[0] = -d*(dpan[0]||0) |
|
scratch0[1] = d*(dpan[1]||0) |
|
scratch0[2] = d*(dpan[2]||0) |
|
vec3.transformQuat(scratch0, scratch0, this.rotation) |
|
vec3.add(this.center, this.center, scratch0) |
|
} |
|
|
|
proto.zoom = function(d) { |
|
this.distance += d |
|
if(this.distance < 0.0) { |
|
this.distance = 0.0 |
|
} |
|
} |
|
|
|
function quatFromVec(out, da) { |
|
var x = da[0] |
|
var y = da[1] |
|
var z = da[2] |
|
var s = x*x + y*y |
|
if(s > 1.0) { |
|
s = 1.0 |
|
} |
|
out[0] = -da[0] |
|
out[1] = da[1] |
|
out[2] = da[2] || Math.sqrt(1.0 - s) |
|
out[3] = 0.0 |
|
} |
|
|
|
proto.rotate = function(da, db) { |
|
quatFromVec(scratch0, da) |
|
quatFromVec(scratch1, db) |
|
quat.invert(scratch1, scratch1) |
|
quat.multiply(scratch0, scratch0, scratch1) |
|
if(quat.length(scratch0) < 1e-6) { |
|
return |
|
} |
|
quat.multiply(this.rotation, this.rotation, scratch0) |
|
quat.normalize(this.rotation, this.rotation) |
|
} |
|
|
|
function createOrbitCamera(eye, target, up) { |
|
eye = eye || [0,0,-1] |
|
target = target || [0,0,0] |
|
up = up || [0,1,0] |
|
var camera = new OrbitCamera(quat.create(), vec3.create(), 1.0) |
|
camera.lookAt(eye, target, up) |
|
return camera |
|
} |
|
|
|
module.exports = createOrbitCamera |
|
|
|
|
|
/***/ }), |
|
/* 21 */ |
|
/***/ (function(module, exports, __webpack_require__) { |
|
|
|
var Emitter = __webpack_require__(1) |
|
var wheel = __webpack_require__(22) |
|
|
|
module.exports = getScroller |
|
|
|
function getScroller(element, preventDefault) { |
|
var scroll = new Emitter |
|
|
|
scroll.flush = flush |
|
flush() |
|
|
|
if (typeof window === 'undefined') { |
|
return scroll |
|
} |
|
|
|
element = element || window |
|
wheel(element, onscroll, false) |
|
|
|
return scroll |
|
|
|
function flush() { |
|
scroll[0] = |
|
scroll[1] = |
|
scroll[2] = 0 |
|
} |
|
|
|
function onscroll(e) { |
|
// Normal/Line scrolling |
|
var scale = e.deltaMode === 1 ? 12 : 1 |
|
|
|
scroll[0] += scale * (e.deltaX || 0) |
|
scroll[1] += scale * (e.deltaY || 0) |
|
scroll[2] += scale * (e.deltaZ || 0) |
|
scroll.emit('scroll', scroll) |
|
|
|
if (!preventDefault) return |
|
if (!e.preventDefault) return |
|
|
|
e.preventDefault() |
|
if (e.stopPropagation) e.stopPropagation() |
|
} |
|
} |
|
|
|
|
|
/***/ }), |
|
/* 22 */ |
|
/***/ (function(module, exports) { |
|
|
|
/** |
|
* This module unifies handling of mouse whee event accross different browsers |
|
* |
|
* See https://developer.mozilla.org/en-US/docs/Web/Reference/Events/wheel?redirectlocale=en-US&redirectslug=DOM%2FMozilla_event_reference%2Fwheel |
|
* for more details |
|
* |
|
* Usage: |
|
* var addWheelListener = require('wheel'); |
|
* addWheelListener(domElement, function (e) { |
|
* // mouse wheel event |
|
* }); |
|
*/ |
|
module.exports = addWheelListener; |
|
|
|
var prefix = "", _addEventListener, onwheel, support; |
|
|
|
// detect event model |
|
if ( window.addEventListener ) { |
|
_addEventListener = "addEventListener"; |
|
} else { |
|
_addEventListener = "attachEvent"; |
|
prefix = "on"; |
|
} |
|
|
|
// detect available wheel event |
|
support = "onwheel" in document.createElement("div") ? "wheel" : // Modern browsers support "wheel" |
|
document.onmousewheel !== undefined ? "mousewheel" : // Webkit and IE support at least "mousewheel" |
|
"DOMMouseScroll"; // let's assume that remaining browsers are older Firefox |
|
|
|
function addWheelListener( elem, callback, useCapture ) { |
|
_addWheelListener( elem, support, callback, useCapture ); |
|
|
|
// handle MozMousePixelScroll in older Firefox |
|
if( support == "DOMMouseScroll" ) { |
|
_addWheelListener( elem, "MozMousePixelScroll", callback, useCapture ); |
|
} |
|
}; |
|
|
|
function _addWheelListener( elem, eventName, callback, useCapture ) { |
|
elem[ _addEventListener ]( prefix + eventName, support == "wheel" ? callback : function( originalEvent ) { |
|
!originalEvent && ( originalEvent = window.event ); |
|
|
|
// create a normalized event object |
|
var event = { |
|
// keep a ref to the original event object |
|
originalEvent: originalEvent, |
|
target: originalEvent.target || originalEvent.srcElement, |
|
type: "wheel", |
|
deltaMode: originalEvent.type == "MozMousePixelScroll" ? 0 : 1, |
|
deltaX: 0, |
|
delatZ: 0, |
|
preventDefault: function() { |
|
originalEvent.preventDefault ? |
|
originalEvent.preventDefault() : |
|
originalEvent.returnValue = false; |
|
} |
|
}; |
|
|
|
// calculate deltaY (and deltaX) according to the event |
|
if ( support == "mousewheel" ) { |
|
event.deltaY = - 1/40 * originalEvent.wheelDelta; |
|
// Webkit also support wheelDeltaX |
|
originalEvent.wheelDeltaX && ( event.deltaX = - 1/40 * originalEvent.wheelDeltaX ); |
|
} else { |
|
event.deltaY = originalEvent.detail; |
|
} |
|
|
|
// it's time to fire the callback |
|
return callback( event ); |
|
|
|
}, useCapture || false ); |
|
} |
|
|
|
|
|
/***/ }), |
|
/* 23 */ |
|
/***/ (function(module, exports) { |
|
|
|
module.exports = adjoint; |
|
|
|
/** |
|
* Calculates the adjugate of a mat4 |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the source matrix |
|
* @returns {mat4} out |
|
*/ |
|
function adjoint(out, a) { |
|
var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], |
|
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], |
|
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], |
|
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; |
|
|
|
out[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22)); |
|
out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22)); |
|
out[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12)); |
|
out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12)); |
|
out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22)); |
|
out[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22)); |
|
out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12)); |
|
out[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12)); |
|
out[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21)); |
|
out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21)); |
|
out[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11)); |
|
out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11)); |
|
out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21)); |
|
out[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21)); |
|
out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11)); |
|
out[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11)); |
|
return out; |
|
}; |
|
|
|
/***/ }), |
|
/* 24 */ |
|
/***/ (function(module, exports) { |
|
|
|
module.exports = clone; |
|
|
|
/** |
|
* Creates a new mat4 initialized with values from an existing matrix |
|
* |
|
* @param {mat4} a matrix to clone |
|
* @returns {mat4} a new 4x4 matrix |
|
*/ |
|
function clone(a) { |
|
var out = new Float32Array(16); |
|
out[0] = a[0]; |
|
out[1] = a[1]; |
|
out[2] = a[2]; |
|
out[3] = a[3]; |
|
out[4] = a[4]; |
|
out[5] = a[5]; |
|
out[6] = a[6]; |
|
out[7] = a[7]; |
|
out[8] = a[8]; |
|
out[9] = a[9]; |
|
out[10] = a[10]; |
|
out[11] = a[11]; |
|
out[12] = a[12]; |
|
out[13] = a[13]; |
|
out[14] = a[14]; |
|
out[15] = a[15]; |
|
return out; |
|
}; |
|
|
|
/***/ }), |
|
/* 25 */ |
|
/***/ (function(module, exports) { |
|
|
|
module.exports = copy; |
|
|
|
/** |
|
* Copy the values from one mat4 to another |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the source matrix |
|
* @returns {mat4} out |
|
*/ |
|
function copy(out, a) { |
|
out[0] = a[0]; |
|
out[1] = a[1]; |
|
out[2] = a[2]; |
|
out[3] = a[3]; |
|
out[4] = a[4]; |
|
out[5] = a[5]; |
|
out[6] = a[6]; |
|
out[7] = a[7]; |
|
out[8] = a[8]; |
|
out[9] = a[9]; |
|
out[10] = a[10]; |
|
out[11] = a[11]; |
|
out[12] = a[12]; |
|
out[13] = a[13]; |
|
out[14] = a[14]; |
|
out[15] = a[15]; |
|
return out; |
|
}; |
|
|
|
/***/ }), |
|
/* 26 */ |
|
/***/ (function(module, exports) { |
|
|
|
module.exports = create; |
|
|
|
/** |
|
* Creates a new identity mat4 |
|
* |
|
* @returns {mat4} a new 4x4 matrix |
|
*/ |
|
function create() { |
|
var out = new Float32Array(16); |
|
out[0] = 1; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 0; |
|
out[4] = 0; |
|
out[5] = 1; |
|
out[6] = 0; |
|
out[7] = 0; |
|
out[8] = 0; |
|
out[9] = 0; |
|
out[10] = 1; |
|
out[11] = 0; |
|
out[12] = 0; |
|
out[13] = 0; |
|
out[14] = 0; |
|
out[15] = 1; |
|
return out; |
|
}; |
|
|
|
/***/ }), |
|
/* 27 */ |
|
/***/ (function(module, exports) { |
|
|
|
module.exports = determinant; |
|
|
|
/** |
|
* Calculates the determinant of a mat4 |
|
* |
|
* @param {mat4} a the source matrix |
|
* @returns {Number} determinant of a |
|
*/ |
|
function determinant(a) { |
|
var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], |
|
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], |
|
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], |
|
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], |
|
|
|
b00 = a00 * a11 - a01 * a10, |
|
b01 = a00 * a12 - a02 * a10, |
|
b02 = a00 * a13 - a03 * a10, |
|
b03 = a01 * a12 - a02 * a11, |
|
b04 = a01 * a13 - a03 * a11, |
|
b05 = a02 * a13 - a03 * a12, |
|
b06 = a20 * a31 - a21 * a30, |
|
b07 = a20 * a32 - a22 * a30, |
|
b08 = a20 * a33 - a23 * a30, |
|
b09 = a21 * a32 - a22 * a31, |
|
b10 = a21 * a33 - a23 * a31, |
|
b11 = a22 * a33 - a23 * a32; |
|
|
|
// Calculate the determinant |
|
return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; |
|
}; |
|
|
|
/***/ }), |
|
/* 28 */ |
|
/***/ (function(module, exports) { |
|
|
|
module.exports = fromQuat; |
|
|
|
/** |
|
* Creates a matrix from a quaternion rotation. |
|
* |
|
* @param {mat4} out mat4 receiving operation result |
|
* @param {quat4} q Rotation quaternion |
|
* @returns {mat4} out |
|
*/ |
|
function fromQuat(out, q) { |
|
var x = q[0], y = q[1], z = q[2], w = q[3], |
|
x2 = x + x, |
|
y2 = y + y, |
|
z2 = z + z, |
|
|
|
xx = x * x2, |
|
yx = y * x2, |
|
yy = y * y2, |
|
zx = z * x2, |
|
zy = z * y2, |
|
zz = z * z2, |
|
wx = w * x2, |
|
wy = w * y2, |
|
wz = w * z2; |
|
|
|
out[0] = 1 - yy - zz; |
|
out[1] = yx + wz; |
|
out[2] = zx - wy; |
|
out[3] = 0; |
|
|
|
out[4] = yx - wz; |
|
out[5] = 1 - xx - zz; |
|
out[6] = zy + wx; |
|
out[7] = 0; |
|
|
|
out[8] = zx + wy; |
|
out[9] = zy - wx; |
|
out[10] = 1 - xx - yy; |
|
out[11] = 0; |
|
|
|
out[12] = 0; |
|
out[13] = 0; |
|
out[14] = 0; |
|
out[15] = 1; |
|
|
|
return out; |
|
}; |
|
|
|
/***/ }), |
|
/* 29 */ |
|
/***/ (function(module, exports) { |
|
|
|
module.exports = fromRotationTranslation; |
|
|
|
/** |
|
* Creates a matrix from a quaternion rotation and vector translation |
|
* This is equivalent to (but much faster than): |
|
* |
|
* mat4.identity(dest); |
|
* mat4.translate(dest, vec); |
|
* var quatMat = mat4.create(); |
|
* quat4.toMat4(quat, quatMat); |
|
* mat4.multiply(dest, quatMat); |
|
* |
|
* @param {mat4} out mat4 receiving operation result |
|
* @param {quat4} q Rotation quaternion |
|
* @param {vec3} v Translation vector |
|
* @returns {mat4} out |
|
*/ |
|
function fromRotationTranslation(out, q, v) { |
|
// Quaternion math |
|
var x = q[0], y = q[1], z = q[2], w = q[3], |
|
x2 = x + x, |
|
y2 = y + y, |
|
z2 = z + z, |
|
|
|
xx = x * x2, |
|
xy = x * y2, |
|
xz = x * z2, |
|
yy = y * y2, |
|
yz = y * z2, |
|
zz = z * z2, |
|
wx = w * x2, |
|
wy = w * y2, |
|
wz = w * z2; |
|
|
|
out[0] = 1 - (yy + zz); |
|
out[1] = xy + wz; |
|
out[2] = xz - wy; |
|
out[3] = 0; |
|
out[4] = xy - wz; |
|
out[5] = 1 - (xx + zz); |
|
out[6] = yz + wx; |
|
out[7] = 0; |
|
out[8] = xz + wy; |
|
out[9] = yz - wx; |
|
out[10] = 1 - (xx + yy); |
|
out[11] = 0; |
|
out[12] = v[0]; |
|
out[13] = v[1]; |
|
out[14] = v[2]; |
|
out[15] = 1; |
|
|
|
return out; |
|
}; |
|
|
|
/***/ }), |
|
/* 30 */ |
|
/***/ (function(module, exports) { |
|
|
|
module.exports = frustum; |
|
|
|
/** |
|
* Generates a frustum matrix with the given bounds |
|
* |
|
* @param {mat4} out mat4 frustum matrix will be written into |
|
* @param {Number} left Left bound of the frustum |
|
* @param {Number} right Right bound of the frustum |
|
* @param {Number} bottom Bottom bound of the frustum |
|
* @param {Number} top Top bound of the frustum |
|
* @param {Number} near Near bound of the frustum |
|
* @param {Number} far Far bound of the frustum |
|
* @returns {mat4} out |
|
*/ |
|
function frustum(out, left, right, bottom, top, near, far) { |
|
var rl = 1 / (right - left), |
|
tb = 1 / (top - bottom), |
|
nf = 1 / (near - far); |
|
out[0] = (near * 2) * rl; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 0; |
|
out[4] = 0; |
|
out[5] = (near * 2) * tb; |
|
out[6] = 0; |
|
out[7] = 0; |
|
out[8] = (right + left) * rl; |
|
out[9] = (top + bottom) * tb; |
|
out[10] = (far + near) * nf; |
|
out[11] = -1; |
|
out[12] = 0; |
|
out[13] = 0; |
|
out[14] = (far * near * 2) * nf; |
|
out[15] = 0; |
|
return out; |
|
}; |
|
|
|
/***/ }), |
|
/* 31 */ |
|
/***/ (function(module, exports, __webpack_require__) { |
|
|
|
module.exports = { |
|
create: __webpack_require__(26) |
|
, clone: __webpack_require__(24) |
|
, copy: __webpack_require__(25) |
|
, identity: __webpack_require__(5) |
|
, transpose: __webpack_require__(45) |
|
, invert: __webpack_require__(32) |
|
, adjoint: __webpack_require__(23) |
|
, determinant: __webpack_require__(27) |
|
, multiply: __webpack_require__(34) |
|
, translate: __webpack_require__(44) |
|
, scale: __webpack_require__(42) |
|
, rotate: __webpack_require__(38) |
|
, rotateX: __webpack_require__(39) |
|
, rotateY: __webpack_require__(40) |
|
, rotateZ: __webpack_require__(41) |
|
, fromRotationTranslation: __webpack_require__(29) |
|
, fromQuat: __webpack_require__(28) |
|
, frustum: __webpack_require__(30) |
|
, perspective: __webpack_require__(36) |
|
, perspectiveFromFieldOfView: __webpack_require__(37) |
|
, ortho: __webpack_require__(35) |
|
, lookAt: __webpack_require__(33) |
|
, str: __webpack_require__(43) |
|
} |
|
|
|
/***/ }), |
|
/* 32 */ |
|
/***/ (function(module, exports) { |
|
|
|
module.exports = invert; |
|
|
|
/** |
|
* Inverts a mat4 |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the source matrix |
|
* @returns {mat4} out |
|
*/ |
|
function invert(out, a) { |
|
var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], |
|
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], |
|
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], |
|
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], |
|
|
|
b00 = a00 * a11 - a01 * a10, |
|
b01 = a00 * a12 - a02 * a10, |
|
b02 = a00 * a13 - a03 * a10, |
|
b03 = a01 * a12 - a02 * a11, |
|
b04 = a01 * a13 - a03 * a11, |
|
b05 = a02 * a13 - a03 * a12, |
|
b06 = a20 * a31 - a21 * a30, |
|
b07 = a20 * a32 - a22 * a30, |
|
b08 = a20 * a33 - a23 * a30, |
|
b09 = a21 * a32 - a22 * a31, |
|
b10 = a21 * a33 - a23 * a31, |
|
b11 = a22 * a33 - a23 * a32, |
|
|
|
// Calculate the determinant |
|
det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; |
|
|
|
if (!det) { |
|
return null; |
|
} |
|
det = 1.0 / det; |
|
|
|
out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; |
|
out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; |
|
out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; |
|
out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; |
|
out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; |
|
out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; |
|
out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; |
|
out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; |
|
out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; |
|
out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; |
|
out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; |
|
out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; |
|
out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; |
|
out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; |
|
out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; |
|
out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; |
|
|
|
return out; |
|
}; |
|
|
|
/***/ }), |
|
/* 33 */ |
|
/***/ (function(module, exports, __webpack_require__) { |
|
|
|
var identity = __webpack_require__(5); |
|
|
|
module.exports = lookAt; |
|
|
|
/** |
|
* Generates a look-at matrix with the given eye position, focal point, and up axis |
|
* |
|
* @param {mat4} out mat4 frustum matrix will be written into |
|
* @param {vec3} eye Position of the viewer |
|
* @param {vec3} center Point the viewer is looking at |
|
* @param {vec3} up vec3 pointing up |
|
* @returns {mat4} out |
|
*/ |
|
function lookAt(out, eye, center, up) { |
|
var x0, x1, x2, y0, y1, y2, z0, z1, z2, len, |
|
eyex = eye[0], |
|
eyey = eye[1], |
|
eyez = eye[2], |
|
upx = up[0], |
|
upy = up[1], |
|
upz = up[2], |
|
centerx = center[0], |
|
centery = center[1], |
|
centerz = center[2]; |
|
|
|
if (Math.abs(eyex - centerx) < 0.000001 && |
|
Math.abs(eyey - centery) < 0.000001 && |
|
Math.abs(eyez - centerz) < 0.000001) { |
|
return identity(out); |
|
} |
|
|
|
z0 = eyex - centerx; |
|
z1 = eyey - centery; |
|
z2 = eyez - centerz; |
|
|
|
len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2); |
|
z0 *= len; |
|
z1 *= len; |
|
z2 *= len; |
|
|
|
x0 = upy * z2 - upz * z1; |
|
x1 = upz * z0 - upx * z2; |
|
x2 = upx * z1 - upy * z0; |
|
len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2); |
|
if (!len) { |
|
x0 = 0; |
|
x1 = 0; |
|
x2 = 0; |
|
} else { |
|
len = 1 / len; |
|
x0 *= len; |
|
x1 *= len; |
|
x2 *= len; |
|
} |
|
|
|
y0 = z1 * x2 - z2 * x1; |
|
y1 = z2 * x0 - z0 * x2; |
|
y2 = z0 * x1 - z1 * x0; |
|
|
|
len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2); |
|
if (!len) { |
|
y0 = 0; |
|
y1 = 0; |
|
y2 = 0; |
|
} else { |
|
len = 1 / len; |
|
y0 *= len; |
|
y1 *= len; |
|
y2 *= len; |
|
} |
|
|
|
out[0] = x0; |
|
out[1] = y0; |
|
out[2] = z0; |
|
out[3] = 0; |
|
out[4] = x1; |
|
out[5] = y1; |
|
out[6] = z1; |
|
out[7] = 0; |
|
out[8] = x2; |
|
out[9] = y2; |
|
out[10] = z2; |
|
out[11] = 0; |
|
out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez); |
|
out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez); |
|
out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez); |
|
out[15] = 1; |
|
|
|
return out; |
|
}; |
|
|
|
/***/ }), |
|
/* 34 */ |
|
/***/ (function(module, exports) { |
|
|
|
module.exports = multiply; |
|
|
|
/** |
|
* Multiplies two mat4's |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the first operand |
|
* @param {mat4} b the second operand |
|
* @returns {mat4} out |
|
*/ |
|
function multiply(out, a, b) { |
|
var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], |
|
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], |
|
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], |
|
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; |
|
|
|
// Cache only the current line of the second matrix |
|
var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; |
|
out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; |
|
out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; |
|
out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; |
|
out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; |
|
|
|
b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; |
|
out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; |
|
out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; |
|
out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; |
|
out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; |
|
|
|
b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; |
|
out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; |
|
out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; |
|
out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; |
|
out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; |
|
|
|
b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; |
|
out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; |
|
out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; |
|
out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; |
|
out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; |
|
return out; |
|
}; |
|
|
|
/***/ }), |
|
/* 35 */ |
|
/***/ (function(module, exports) { |
|
|
|
module.exports = ortho; |
|
|
|
/** |
|
* Generates a orthogonal projection matrix with the given bounds |
|
* |
|
* @param {mat4} out mat4 frustum matrix will be written into |
|
* @param {number} left Left bound of the frustum |
|
* @param {number} right Right bound of the frustum |
|
* @param {number} bottom Bottom bound of the frustum |
|
* @param {number} top Top bound of the frustum |
|
* @param {number} near Near bound of the frustum |
|
* @param {number} far Far bound of the frustum |
|
* @returns {mat4} out |
|
*/ |
|
function ortho(out, left, right, bottom, top, near, far) { |
|
var lr = 1 / (left - right), |
|
bt = 1 / (bottom - top), |
|
nf = 1 / (near - far); |
|
out[0] = -2 * lr; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 0; |
|
out[4] = 0; |
|
out[5] = -2 * bt; |
|
out[6] = 0; |
|
out[7] = 0; |
|
out[8] = 0; |
|
out[9] = 0; |
|
out[10] = 2 * nf; |
|
out[11] = 0; |
|
out[12] = (left + right) * lr; |
|
out[13] = (top + bottom) * bt; |
|
out[14] = (far + near) * nf; |
|
out[15] = 1; |
|
return out; |
|
}; |
|
|
|
/***/ }), |
|
/* 36 */ |
|
/***/ (function(module, exports) { |
|
|
|
module.exports = perspective; |
|
|
|
/** |
|
* Generates a perspective projection matrix with the given bounds |
|
* |
|
* @param {mat4} out mat4 frustum matrix will be written into |
|
* @param {number} fovy Vertical field of view in radians |
|
* @param {number} aspect Aspect ratio. typically viewport width/height |
|
* @param {number} near Near bound of the frustum |
|
* @param {number} far Far bound of the frustum |
|
* @returns {mat4} out |
|
*/ |
|
function perspective(out, fovy, aspect, near, far) { |
|
var f = 1.0 / Math.tan(fovy / 2), |
|
nf = 1 / (near - far); |
|
out[0] = f / aspect; |
|
out[1] = 0; |
|
out[2] = 0; |
|
out[3] = 0; |
|
out[4] = 0; |
|
out[5] = f; |
|
out[6] = 0; |
|
out[7] = 0; |
|
out[8] = 0; |
|
out[9] = 0; |
|
out[10] = (far + near) * nf; |
|
out[11] = -1; |
|
out[12] = 0; |
|
out[13] = 0; |
|
out[14] = (2 * far * near) * nf; |
|
out[15] = 0; |
|
return out; |
|
}; |
|
|
|
/***/ }), |
|
/* 37 */ |
|
/***/ (function(module, exports) { |
|
|
|
module.exports = perspectiveFromFieldOfView; |
|
|
|
/** |
|
* Generates a perspective projection matrix with the given field of view. |
|
* This is primarily useful for generating projection matrices to be used |
|
* with the still experiemental WebVR API. |
|
* |
|
* @param {mat4} out mat4 frustum matrix will be written into |
|
* @param {number} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees |
|
* @param {number} near Near bound of the frustum |
|
* @param {number} far Far bound of the frustum |
|
* @returns {mat4} out |
|
*/ |
|
function perspectiveFromFieldOfView(out, fov, near, far) { |
|
var upTan = Math.tan(fov.upDegrees * Math.PI/180.0), |
|
downTan = Math.tan(fov.downDegrees * Math.PI/180.0), |
|
leftTan = Math.tan(fov.leftDegrees * Math.PI/180.0), |
|
rightTan = Math.tan(fov.rightDegrees * Math.PI/180.0), |
|
xScale = 2.0 / (leftTan + rightTan), |
|
yScale = 2.0 / (upTan + downTan); |
|
|
|
out[0] = xScale; |
|
out[1] = 0.0; |
|
out[2] = 0.0; |
|
out[3] = 0.0; |
|
out[4] = 0.0; |
|
out[5] = yScale; |
|
out[6] = 0.0; |
|
out[7] = 0.0; |
|
out[8] = -((leftTan - rightTan) * xScale * 0.5); |
|
out[9] = ((upTan - downTan) * yScale * 0.5); |
|
out[10] = far / (near - far); |
|
out[11] = -1.0; |
|
out[12] = 0.0; |
|
out[13] = 0.0; |
|
out[14] = (far * near) / (near - far); |
|
out[15] = 0.0; |
|
return out; |
|
} |
|
|
|
|
|
|
|
/***/ }), |
|
/* 38 */ |
|
/***/ (function(module, exports) { |
|
|
|
module.exports = rotate; |
|
|
|
/** |
|
* Rotates a mat4 by the given angle |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the matrix to rotate |
|
* @param {Number} rad the angle to rotate the matrix by |
|
* @param {vec3} axis the axis to rotate around |
|
* @returns {mat4} out |
|
*/ |
|
function rotate(out, a, rad, axis) { |
|
var x = axis[0], y = axis[1], z = axis[2], |
|
len = Math.sqrt(x * x + y * y + z * z), |
|
s, c, t, |
|
a00, a01, a02, a03, |
|
a10, a11, a12, a13, |
|
a20, a21, a22, a23, |
|
b00, b01, b02, |
|
b10, b11, b12, |
|
b20, b21, b22; |
|
|
|
if (Math.abs(len) < 0.000001) { return null; } |
|
|
|
len = 1 / len; |
|
x *= len; |
|
y *= len; |
|
z *= len; |
|
|
|
s = Math.sin(rad); |
|
c = Math.cos(rad); |
|
t = 1 - c; |
|
|
|
a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; |
|
a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; |
|
a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; |
|
|
|
// Construct the elements of the rotation matrix |
|
b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s; |
|
b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s; |
|
b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c; |
|
|
|
// Perform rotation-specific matrix multiplication |
|
out[0] = a00 * b00 + a10 * b01 + a20 * b02; |
|
out[1] = a01 * b00 + a11 * b01 + a21 * b02; |
|
out[2] = a02 * b00 + a12 * b01 + a22 * b02; |
|
out[3] = a03 * b00 + a13 * b01 + a23 * b02; |
|
out[4] = a00 * b10 + a10 * b11 + a20 * b12; |
|
out[5] = a01 * b10 + a11 * b11 + a21 * b12; |
|
out[6] = a02 * b10 + a12 * b11 + a22 * b12; |
|
out[7] = a03 * b10 + a13 * b11 + a23 * b12; |
|
out[8] = a00 * b20 + a10 * b21 + a20 * b22; |
|
out[9] = a01 * b20 + a11 * b21 + a21 * b22; |
|
out[10] = a02 * b20 + a12 * b21 + a22 * b22; |
|
out[11] = a03 * b20 + a13 * b21 + a23 * b22; |
|
|
|
if (a !== out) { // If the source and destination differ, copy the unchanged last row |
|
out[12] = a[12]; |
|
out[13] = a[13]; |
|
out[14] = a[14]; |
|
out[15] = a[15]; |
|
} |
|
return out; |
|
}; |
|
|
|
/***/ }), |
|
/* 39 */ |
|
/***/ (function(module, exports) { |
|
|
|
module.exports = rotateX; |
|
|
|
/** |
|
* Rotates a matrix by the given angle around the X axis |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the matrix to rotate |
|
* @param {Number} rad the angle to rotate the matrix by |
|
* @returns {mat4} out |
|
*/ |
|
function rotateX(out, a, rad) { |
|
var s = Math.sin(rad), |
|
c = Math.cos(rad), |
|
a10 = a[4], |
|
a11 = a[5], |
|
a12 = a[6], |
|
a13 = a[7], |
|
a20 = a[8], |
|
a21 = a[9], |
|
a22 = a[10], |
|
a23 = a[11]; |
|
|
|
if (a !== out) { // If the source and destination differ, copy the unchanged rows |
|
out[0] = a[0]; |
|
out[1] = a[1]; |
|
out[2] = a[2]; |
|
out[3] = a[3]; |
|
out[12] = a[12]; |
|
out[13] = a[13]; |
|
out[14] = a[14]; |
|
out[15] = a[15]; |
|
} |
|
|
|
// Perform axis-specific matrix multiplication |
|
out[4] = a10 * c + a20 * s; |
|
out[5] = a11 * c + a21 * s; |
|
out[6] = a12 * c + a22 * s; |
|
out[7] = a13 * c + a23 * s; |
|
out[8] = a20 * c - a10 * s; |
|
out[9] = a21 * c - a11 * s; |
|
out[10] = a22 * c - a12 * s; |
|
out[11] = a23 * c - a13 * s; |
|
return out; |
|
}; |
|
|
|
/***/ }), |
|
/* 40 */ |
|
/***/ (function(module, exports) { |
|
|
|
module.exports = rotateY; |
|
|
|
/** |
|
* Rotates a matrix by the given angle around the Y axis |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the matrix to rotate |
|
* @param {Number} rad the angle to rotate the matrix by |
|
* @returns {mat4} out |
|
*/ |
|
function rotateY(out, a, rad) { |
|
var s = Math.sin(rad), |
|
c = Math.cos(rad), |
|
a00 = a[0], |
|
a01 = a[1], |
|
a02 = a[2], |
|
a03 = a[3], |
|
a20 = a[8], |
|
a21 = a[9], |
|
a22 = a[10], |
|
a23 = a[11]; |
|
|
|
if (a !== out) { // If the source and destination differ, copy the unchanged rows |
|
out[4] = a[4]; |
|
out[5] = a[5]; |
|
out[6] = a[6]; |
|
out[7] = a[7]; |
|
out[12] = a[12]; |
|
out[13] = a[13]; |
|
out[14] = a[14]; |
|
out[15] = a[15]; |
|
} |
|
|
|
// Perform axis-specific matrix multiplication |
|
out[0] = a00 * c - a20 * s; |
|
out[1] = a01 * c - a21 * s; |
|
out[2] = a02 * c - a22 * s; |
|
out[3] = a03 * c - a23 * s; |
|
out[8] = a00 * s + a20 * c; |
|
out[9] = a01 * s + a21 * c; |
|
out[10] = a02 * s + a22 * c; |
|
out[11] = a03 * s + a23 * c; |
|
return out; |
|
}; |
|
|
|
/***/ }), |
|
/* 41 */ |
|
/***/ (function(module, exports) { |
|
|
|
module.exports = rotateZ; |
|
|
|
/** |
|
* Rotates a matrix by the given angle around the Z axis |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the matrix to rotate |
|
* @param {Number} rad the angle to rotate the matrix by |
|
* @returns {mat4} out |
|
*/ |
|
function rotateZ(out, a, rad) { |
|
var s = Math.sin(rad), |
|
c = Math.cos(rad), |
|
a00 = a[0], |
|
a01 = a[1], |
|
a02 = a[2], |
|
a03 = a[3], |
|
a10 = a[4], |
|
a11 = a[5], |
|
a12 = a[6], |
|
a13 = a[7]; |
|
|
|
if (a !== out) { // If the source and destination differ, copy the unchanged last row |
|
out[8] = a[8]; |
|
out[9] = a[9]; |
|
out[10] = a[10]; |
|
out[11] = a[11]; |
|
out[12] = a[12]; |
|
out[13] = a[13]; |
|
out[14] = a[14]; |
|
out[15] = a[15]; |
|
} |
|
|
|
// Perform axis-specific matrix multiplication |
|
out[0] = a00 * c + a10 * s; |
|
out[1] = a01 * c + a11 * s; |
|
out[2] = a02 * c + a12 * s; |
|
out[3] = a03 * c + a13 * s; |
|
out[4] = a10 * c - a00 * s; |
|
out[5] = a11 * c - a01 * s; |
|
out[6] = a12 * c - a02 * s; |
|
out[7] = a13 * c - a03 * s; |
|
return out; |
|
}; |
|
|
|
/***/ }), |
|
/* 42 */ |
|
/***/ (function(module, exports) { |
|
|
|
module.exports = scale; |
|
|
|
/** |
|
* Scales the mat4 by the dimensions in the given vec3 |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the matrix to scale |
|
* @param {vec3} v the vec3 to scale the matrix by |
|
* @returns {mat4} out |
|
**/ |
|
function scale(out, a, v) { |
|
var x = v[0], y = v[1], z = v[2]; |
|
|
|
out[0] = a[0] * x; |
|
out[1] = a[1] * x; |
|
out[2] = a[2] * x; |
|
out[3] = a[3] * x; |
|
out[4] = a[4] * y; |
|
out[5] = a[5] * y; |
|
out[6] = a[6] * y; |
|
out[7] = a[7] * y; |
|
out[8] = a[8] * z; |
|
out[9] = a[9] * z; |
|
out[10] = a[10] * z; |
|
out[11] = a[11] * z; |
|
out[12] = a[12]; |
|
out[13] = a[13]; |
|
out[14] = a[14]; |
|
out[15] = a[15]; |
|
return out; |
|
}; |
|
|
|
/***/ }), |
|
/* 43 */ |
|
/***/ (function(module, exports) { |
|
|
|
module.exports = str; |
|
|
|
/** |
|
* Returns a string representation of a mat4 |
|
* |
|
* @param {mat4} mat matrix to represent as a string |
|
* @returns {String} string representation of the matrix |
|
*/ |
|
function str(a) { |
|
return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + |
|
a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + |
|
a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' + |
|
a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')'; |
|
}; |
|
|
|
/***/ }), |
|
/* 44 */ |
|
/***/ (function(module, exports) { |
|
|
|
module.exports = translate; |
|
|
|
/** |
|
* Translate a mat4 by the given vector |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the matrix to translate |
|
* @param {vec3} v vector to translate by |
|
* @returns {mat4} out |
|
*/ |
|
function translate(out, a, v) { |
|
var x = v[0], y = v[1], z = v[2], |
|
a00, a01, a02, a03, |
|
a10, a11, a12, a13, |
|
a20, a21, a22, a23; |
|
|
|
if (a === out) { |
|
out[12] = a[0] * x + a[4] * y + a[8] * z + a[12]; |
|
out[13] = a[1] * x + a[5] * y + a[9] * z + a[13]; |
|
out[14] = a[2] * x + a[6] * y + a[10] * z + a[14]; |
|
out[15] = a[3] * x + a[7] * y + a[11] * z + a[15]; |
|
} else { |
|
a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; |
|
a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; |
|
a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; |
|
|
|
out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a03; |
|
out[4] = a10; out[5] = a11; out[6] = a12; out[7] = a13; |
|
out[8] = a20; out[9] = a21; out[10] = a22; out[11] = a23; |
|
|
|
out[12] = a00 * x + a10 * y + a20 * z + a[12]; |
|
out[13] = a01 * x + a11 * y + a21 * z + a[13]; |
|
out[14] = a02 * x + a12 * y + a22 * z + a[14]; |
|
out[15] = a03 * x + a13 * y + a23 * z + a[15]; |
|
} |
|
|
|
return out; |
|
}; |
|
|
|
/***/ }), |
|
/* 45 */ |
|
/***/ (function(module, exports) { |
|
|
|
module.exports = transpose; |
|
|
|
/** |
|
* Transpose the values of a mat4 |
|
* |
|
* @param {mat4} out the receiving matrix |
|
* @param {mat4} a the source matrix |
|
* @returns {mat4} out |
|
*/ |
|
function transpose(out, a) { |
|
// If we are transposing ourselves we can skip a few steps but have to cache some values |
|
if (out === a) { |
|
var a01 = a[1], a02 = a[2], a03 = a[3], |
|
a12 = a[6], a13 = a[7], |
|
a23 = a[11]; |
|
|
|
out[1] = a[4]; |
|
out[2] = a[8]; |
|
out[3] = a[12]; |
|
out[4] = a01; |
|
out[6] = a[9]; |
|
out[7] = a[13]; |
|
out[8] = a02; |
|
out[9] = a12; |
|
out[11] = a[14]; |
|
out[12] = a03; |
|
out[13] = a13; |
|
out[14] = a23; |
|
} else { |
|
out[0] = a[0]; |
|
out[1] = a[4]; |
|
out[2] = a[8]; |
|
out[3] = a[12]; |
|
out[4] = a[1]; |
|
out[5] = a[5]; |
|
out[6] = a[9]; |
|
out[7] = a[13]; |
|
out[8] = a[2]; |
|
out[9] = a[6]; |
|
out[10] = a[10]; |
|
out[11] = a[14]; |
|
out[12] = a[3]; |
|
out[13] = a[7]; |
|
out[14] = a[11]; |
|
out[15] = a[15]; |
|
} |
|
|
|
return out; |
|
}; |
|
|
|
/***/ }), |
|
/* 46 */ |
|
/***/ (function(module, exports, __webpack_require__) { |
|
|
|
(function (global, factory) { |
|
true ? module.exports = factory() : |
|
typeof define === 'function' && define.amd ? define(factory) : |
|
(global.createREGL = factory()); |
|
}(this, (function () { 'use strict'; |
|
|
|
var arrayTypes = { |
|
"[object Int8Array]": 5120, |
|
"[object Int16Array]": 5122, |
|
"[object Int32Array]": 5124, |
|
"[object Uint8Array]": 5121, |
|
"[object Uint8ClampedArray]": 5121, |
|
"[object Uint16Array]": 5123, |
|
"[object Uint32Array]": 5125, |
|
"[object Float32Array]": 5126, |
|
"[object Float64Array]": 5121, |
|
"[object ArrayBuffer]": 5121 |
|
}; |
|
|
|
var isTypedArray = function (x) { |
|
return Object.prototype.toString.call(x) in arrayTypes |
|
}; |
|
|
|
var extend = function (base, opts) { |
|
var keys = Object.keys(opts); |
|
for (var i = 0; i < keys.length; ++i) { |
|
base[keys[i]] = opts[keys[i]]; |
|
} |
|
return base |
|
}; |
|
|
|
// Error checking and parameter validation. |
|
// |
|
// Statements for the form `check.someProcedure(...)` get removed by |
|
// a browserify transform for optimized/minified bundles. |
|
// |
|
/* globals btoa */ |
|
// only used for extracting shader names. if btoa not present, then errors |
|
// will be slightly crappier |
|
function decodeB64 (str) { |
|
if (typeof btoa !== 'undefined') { |
|
return btoa(str) |
|
} |
|
return 'base64:' + str |
|
} |
|
|
|
function raise (message) { |
|
var error = new Error('(regl) ' + message); |
|
console.error(error); |
|
throw error |
|
} |
|
|
|
function check (pred, message) { |
|
if (!pred) { |
|
raise(message); |
|
} |
|
} |
|
|
|
function encolon (message) { |
|
if (message) { |
|
return ': ' + message |
|
} |
|
return '' |
|
} |
|
|
|
function checkParameter (param, possibilities, message) { |
|
if (!(param in possibilities)) { |
|
raise('unknown parameter (' + param + ')' + encolon(message) + |
|
'. possible values: ' + Object.keys(possibilities).join()); |
|
} |
|
} |
|
|
|
function checkIsTypedArray (data, message) { |
|
if (!isTypedArray(data)) { |
|
raise( |
|
'invalid parameter type' + encolon(message) + |
|
'. must be a typed array'); |
|
} |
|
} |
|
|
|
function checkTypeOf (value, type, message) { |
|
if (typeof value !== type) { |
|
raise( |
|
'invalid parameter type' + encolon(message) + |
|
'. expected ' + type + ', got ' + (typeof value)); |
|
} |
|
} |
|
|
|
function checkNonNegativeInt (value, message) { |
|
if (!((value >= 0) && |
|
((value | 0) === value))) { |
|
raise('invalid parameter type, (' + value + ')' + encolon(message) + |
|
'. must be a nonnegative integer'); |
|
} |
|
} |
|
|
|
function checkOneOf (value, list, message) { |
|
if (list.indexOf(value) < 0) { |
|
raise('invalid value' + encolon(message) + '. must be one of: ' + list); |
|
} |
|
} |
|
|
|
var constructorKeys = [ |
|
'gl', |
|
'canvas', |
|
'container', |
|
'attributes', |
|
'pixelRatio', |
|
'extensions', |
|
'optionalExtensions', |
|
'profile', |
|
'onDone' |
|
]; |
|
|
|
function checkConstructor (obj) { |
|
Object.keys(obj).forEach(function (key) { |
|
if (constructorKeys.indexOf(key) < 0) { |
|
raise('invalid regl constructor argument "' + key + '". must be one of ' + constructorKeys); |
|
} |
|
}); |
|
} |
|
|
|
function leftPad (str, n) { |
|
str = str + ''; |
|
while (str.length < n) { |
|
str = ' ' + str; |
|
} |
|
return str |
|
} |
|
|
|
function ShaderFile () { |
|
this.name = 'unknown'; |
|
this.lines = []; |
|
this.index = {}; |
|
this.hasErrors = false; |
|
} |
|
|
|
function ShaderLine (number, line) { |
|
this.number = number; |
|
this.line = line; |
|
this.errors = []; |
|
} |
|
|
|
function ShaderError (fileNumber, lineNumber, message) { |
|
this.file = fileNumber; |
|
this.line = lineNumber; |
|
this.message = message; |
|
} |
|
|
|
function guessCommand () { |
|
var error = new Error(); |
|
var stack = (error.stack || error).toString(); |
|
var pat = /compileProcedure.*\n\s*at.*\((.*)\)/.exec(stack); |
|
if (pat) { |
|
return pat[1] |
|
} |
|
var pat2 = /compileProcedure.*\n\s*at\s+(.*)(\n|$)/.exec(stack); |
|
if (pat2) { |
|
return pat2[1] |
|
} |
|
return 'unknown' |
|
} |
|
|
|
function guessCallSite () { |
|
var error = new Error(); |
|
var stack = (error.stack || error).toString(); |
|
var pat = /at REGLCommand.*\n\s+at.*\((.*)\)/.exec(stack); |
|
if (pat) { |
|
return pat[1] |
|
} |
|
var pat2 = /at REGLCommand.*\n\s+at\s+(.*)\n/.exec(stack); |
|
if (pat2) { |
|
return pat2[1] |
|
} |
|
return 'unknown' |
|
} |
|
|
|
function parseSource (source, command) { |
|
var lines = source.split('\n'); |
|
var lineNumber = 1; |
|
var fileNumber = 0; |
|
var files = { |
|
unknown: new ShaderFile(), |
|
0: new ShaderFile() |
|
}; |
|
files.unknown.name = files[0].name = command || guessCommand(); |
|
files.unknown.lines.push(new ShaderLine(0, '')); |
|
for (var i = 0; i < lines.length; ++i) { |
|
var line = lines[i]; |
|
var parts = /^\s*\#\s*(\w+)\s+(.+)\s*$/.exec(line); |
|
if (parts) { |
|
switch (parts[1]) { |
|
case 'line': |
|
var lineNumberInfo = /(\d+)(\s+\d+)?/.exec(parts[2]); |
|
if (lineNumberInfo) { |
|
lineNumber = lineNumberInfo[1] | 0; |
|
if (lineNumberInfo[2]) { |
|
fileNumber = lineNumberInfo[2] | 0; |
|
if (!(fileNumber in files)) { |
|
files[fileNumber] = new ShaderFile(); |
|
} |
|
} |
|
} |
|
break |
|
case 'define': |
|
var nameInfo = /SHADER_NAME(_B64)?\s+(.*)$/.exec(parts[2]); |
|
if (nameInfo) { |
|
files[fileNumber].name = (nameInfo[1] |
|
? decodeB64(nameInfo[2]) |
|
: nameInfo[2]); |
|
} |
|
break |
|
} |
|
} |
|
files[fileNumber].lines.push(new ShaderLine(lineNumber++, line)); |
|
} |
|
Object.keys(files).forEach(function (fileNumber) { |
|
var file = files[fileNumber]; |
|
file.lines.forEach(function (line) { |
|
file.index[line.number] = line; |
|
}); |
|
}); |
|
return files |
|
} |
|
|
|
function parseErrorLog (errLog) { |
|
var result = []; |
|
errLog.split('\n').forEach(function (errMsg) { |
|
if (errMsg.length < 5) { |
|
return |
|
} |
|
var parts = /^ERROR\:\s+(\d+)\:(\d+)\:\s*(.*)$/.exec(errMsg); |
|
if (parts) { |
|
result.push(new ShaderError( |
|
parts[1] | 0, |
|
parts[2] | 0, |
|
parts[3].trim())); |
|
} else if (errMsg.length > 0) { |
|
result.push(new ShaderError('unknown', 0, errMsg)); |
|
} |
|
}); |
|
return result |
|
} |
|
|
|
function annotateFiles (files, errors) { |
|
errors.forEach(function (error) { |
|
var file = files[error.file]; |
|
if (file) { |
|
var line = file.index[error.line]; |
|
if (line) { |
|
line.errors.push(error); |
|
file.hasErrors = true; |
|
return |
|
} |
|
} |
|
files.unknown.hasErrors = true; |
|
files.unknown.lines[0].errors.push(error); |
|
}); |
|
} |
|
|
|
function checkShaderError (gl, shader, source, type, command) { |
|
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { |
|
var errLog = gl.getShaderInfoLog(shader); |
|
var typeName = type === gl.FRAGMENT_SHADER ? 'fragment' : 'vertex'; |
|
checkCommandType(source, 'string', typeName + ' shader source must be a string', command); |
|
var files = parseSource(source, command); |
|
var errors = parseErrorLog(errLog); |
|
annotateFiles(files, errors); |
|
|
|
Object.keys(files).forEach(function (fileNumber) { |
|
var file = files[fileNumber]; |
|
if (!file.hasErrors) { |
|
return |
|
} |
|
|
|
var strings = ['']; |
|
var styles = ['']; |
|
|
|
function push (str, style) { |
|
strings.push(str); |
|
styles.push(style || ''); |
|
} |
|
|
|
push('file number ' + fileNumber + ': ' + file.name + '\n', 'color:red;text-decoration:underline;font-weight:bold'); |
|
|
|
file.lines.forEach(function (line) { |
|
if (line.errors.length > 0) { |
|
push(leftPad(line.number, 4) + '| ', 'background-color:yellow; font-weight:bold'); |
|
push(line.line + '\n', 'color:red; background-color:yellow; font-weight:bold'); |
|
|
|
// try to guess token |
|
var offset = 0; |
|
line.errors.forEach(function (error) { |
|
var message = error.message; |
|
var token = /^\s*\'(.*)\'\s*\:\s*(.*)$/.exec(message); |
|
if (token) { |
|
var tokenPat = token[1]; |
|
message = token[2]; |
|
switch (tokenPat) { |
|
case 'assign': |
|
tokenPat = '='; |
|
break |
|
} |
|
offset = Math.max(line.line.indexOf(tokenPat, offset), 0); |
|
} else { |
|
offset = 0; |
|
} |
|
|
|
push(leftPad('| ', 6)); |
|
push(leftPad('^^^', offset + 3) + '\n', 'font-weight:bold'); |
|
push(leftPad('| ', 6)); |
|
push(message + '\n', 'font-weight:bold'); |
|
}); |
|
push(leftPad('| ', 6) + '\n'); |
|
} else { |
|
push(leftPad(line.number, 4) + '| '); |
|
push(line.line + '\n', 'color:red'); |
|
} |
|
}); |
|
if (typeof document !== 'undefined') { |
|
styles[0] = strings.join('%c'); |
|
console.log.apply(console, styles); |
|
} else { |
|
console.log(strings.join('')); |
|
} |
|
}); |
|
|
|
check.raise('Error compiling ' + typeName + ' shader, ' + files[0].name); |
|
} |
|
} |
|
|
|
function checkLinkError (gl, program, fragShader, vertShader, command) { |
|
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { |
|
var errLog = gl.getProgramInfoLog(program); |
|
var fragParse = parseSource(fragShader, command); |
|
var vertParse = parseSource(vertShader, command); |
|
|
|
var header = 'Error linking program with vertex shader, "' + |
|
vertParse[0].name + '", and fragment shader "' + fragParse[0].name + '"'; |
|
|
|
if (typeof document !== 'undefined') { |
|
console.log('%c' + header + '\n%c' + errLog, |
|
'color:red;text-decoration:underline;font-weight:bold', |
|
'color:red'); |
|
} else { |
|
console.log(header + '\n' + errLog); |
|
} |
|
check.raise(header); |
|
} |
|
} |
|
|
|
function saveCommandRef (object) { |
|
object._commandRef = guessCommand(); |
|
} |
|
|
|
function saveDrawCommandInfo (opts, uniforms, attributes, stringStore) { |
|
saveCommandRef(opts); |
|
|
|
function id (str) { |
|
if (str) { |
|
return stringStore.id(str) |
|
} |
|
return 0 |
|
} |
|
opts._fragId = id(opts.static.frag); |
|
opts._vertId = id(opts.static.vert); |
|
|
|
function addProps (dict, set) { |
|
Object.keys(set).forEach(function (u) { |
|
dict[stringStore.id(u)] = true; |
|
}); |
|
} |
|
|
|
var uniformSet = opts._uniformSet = {}; |
|
addProps(uniformSet, uniforms.static); |
|
addProps(uniformSet, uniforms.dynamic); |
|
|
|
var attributeSet = opts._attributeSet = {}; |
|
addProps(attributeSet, attributes.static); |
|
addProps(attributeSet, attributes.dynamic); |
|
|
|
opts._hasCount = ( |
|
'count' in opts.static || |
|
'count' in opts.dynamic || |
|
'elements' in opts.static || |
|
'elements' in opts.dynamic); |
|
} |
|
|
|
function commandRaise (message, command) { |
|
var callSite = guessCallSite(); |
|
raise(message + |
|
' in command ' + (command || guessCommand()) + |
|
(callSite === 'unknown' ? '' : ' called from ' + callSite)); |
|
} |
|
|
|
function checkCommand (pred, message, command) { |
|
if (!pred) { |
|
commandRaise(message, command || guessCommand()); |
|
} |
|
} |
|
|
|
function checkParameterCommand (param, possibilities, message, command) { |
|
if (!(param in possibilities)) { |
|
commandRaise( |
|
'unknown parameter (' + param + ')' + encolon(message) + |
|
'. possible values: ' + Object.keys(possibilities).join(), |
|
command || guessCommand()); |
|
} |
|
} |
|
|
|
function checkCommandType (value, type, message, command) { |
|
if (typeof value !== type) { |
|
commandRaise( |
|
'invalid parameter type' + encolon(message) + |
|
'. expected ' + type + ', got ' + (typeof value), |
|
command || guessCommand()); |
|
} |
|
} |
|
|
|
function checkOptional (block) { |
|
block(); |
|
} |
|
|
|
function checkFramebufferFormat (attachment, texFormats, rbFormats) { |
|
if (attachment.texture) { |
|
checkOneOf( |
|
attachment.texture._texture.internalformat, |
|
texFormats, |
|
'unsupported texture format for attachment'); |
|
} else { |
|
checkOneOf( |
|
attachment.renderbuffer._renderbuffer.format, |
|
rbFormats, |
|
'unsupported renderbuffer format for attachment'); |
|
} |
|
} |
|
|
|
var GL_CLAMP_TO_EDGE = 0x812F; |
|
|
|
var GL_NEAREST = 0x2600; |
|
var GL_NEAREST_MIPMAP_NEAREST = 0x2700; |
|
var GL_LINEAR_MIPMAP_NEAREST = 0x2701; |
|
var GL_NEAREST_MIPMAP_LINEAR = 0x2702; |
|
var GL_LINEAR_MIPMAP_LINEAR = 0x2703; |
|
|
|
var GL_BYTE = 5120; |
|
var GL_UNSIGNED_BYTE = 5121; |
|
var GL_SHORT = 5122; |
|
var GL_UNSIGNED_SHORT = 5123; |
|
var GL_INT = 5124; |
|
var GL_UNSIGNED_INT = 5125; |
|
var GL_FLOAT = 5126; |
|
|
|
var GL_UNSIGNED_SHORT_4_4_4_4 = 0x8033; |
|
var GL_UNSIGNED_SHORT_5_5_5_1 = 0x8034; |
|
var GL_UNSIGNED_SHORT_5_6_5 = 0x8363; |
|
var GL_UNSIGNED_INT_24_8_WEBGL = 0x84FA; |
|
|
|
var GL_HALF_FLOAT_OES = 0x8D61; |
|
|
|
var TYPE_SIZE = {}; |
|
|
|
TYPE_SIZE[GL_BYTE] = |
|
TYPE_SIZE[GL_UNSIGNED_BYTE] = 1; |
|
|
|
TYPE_SIZE[GL_SHORT] = |
|
TYPE_SIZE[GL_UNSIGNED_SHORT] = |
|
TYPE_SIZE[GL_HALF_FLOAT_OES] = |
|
TYPE_SIZE[GL_UNSIGNED_SHORT_5_6_5] = |
|
TYPE_SIZE[GL_UNSIGNED_SHORT_4_4_4_4] = |
|
TYPE_SIZE[GL_UNSIGNED_SHORT_5_5_5_1] = 2; |
|
|
|
TYPE_SIZE[GL_INT] = |
|
TYPE_SIZE[GL_UNSIGNED_INT] = |
|
TYPE_SIZE[GL_FLOAT] = |
|
TYPE_SIZE[GL_UNSIGNED_INT_24_8_WEBGL] = 4; |
|
|
|
function pixelSize (type, channels) { |
|
if (type === GL_UNSIGNED_SHORT_5_5_5_1 || |
|
type === GL_UNSIGNED_SHORT_4_4_4_4 || |
|
type === GL_UNSIGNED_SHORT_5_6_5) { |
|
return 2 |
|
} else if (type === GL_UNSIGNED_INT_24_8_WEBGL) { |
|
return 4 |
|
} else { |
|
return TYPE_SIZE[type] * channels |
|
} |
|
} |
|
|
|
function isPow2 (v) { |
|
return !(v & (v - 1)) && (!!v) |
|
} |
|
|
|
function checkTexture2D (info, mipData, limits) { |
|
var i; |
|
var w = mipData.width; |
|
var h = mipData.height; |
|
var c = mipData.channels; |
|
|
|
// Check texture shape |
|
check(w > 0 && w <= limits.maxTextureSize && |
|
h > 0 && h <= limits.maxTextureSize, |
|
'invalid texture shape'); |
|
|
|
// check wrap mode |
|
if (info.wrapS !== GL_CLAMP_TO_EDGE || info.wrapT !== GL_CLAMP_TO_EDGE) { |
|
check(isPow2(w) && isPow2(h), |
|
'incompatible wrap mode for texture, both width and height must be power of 2'); |
|
} |
|
|
|
if (mipData.mipmask === 1) { |
|
if (w !== 1 && h !== 1) { |
|
check( |
|
info.minFilter !== GL_NEAREST_MIPMAP_NEAREST && |
|
info.minFilter !== GL_NEAREST_MIPMAP_LINEAR && |
|
info.minFilter !== GL_LINEAR_MIPMAP_NEAREST && |
|
info.minFilter !== GL_LINEAR_MIPMAP_LINEAR, |
|
'min filter requires mipmap'); |
|
} |
|
} else { |
|
// texture must be power of 2 |
|
check(isPow2(w) && isPow2(h), |
|
'texture must be a square power of 2 to support mipmapping'); |
|
check(mipData.mipmask === (w << 1) - 1, |
|
'missing or incomplete mipmap data'); |
|
} |
|
|
|
if (mipData.type === GL_FLOAT) { |
|
if (limits.extensions.indexOf('oes_texture_float_linear') < 0) { |
|
check(info.minFilter === GL_NEAREST && info.magFilter === GL_NEAREST, |
|
'filter not supported, must enable oes_texture_float_linear'); |
|
} |
|
check(!info.genMipmaps, |
|
'mipmap generation not supported with float textures'); |
|
} |
|
|
|
// check image complete |
|
var mipimages = mipData.images; |
|
for (i = 0; i < 16; ++i) { |
|
if (mipimages[i]) { |
|
var mw = w >> i; |
|
var mh = h >> i; |
|
check(mipData.mipmask & (1 << i), 'missing mipmap data'); |
|
|
|
var img = mipimages[i]; |
|
|
|
check( |
|
img.width === mw && |
|
img.height === mh, |
|
'invalid shape for mip images'); |
|
|
|
check( |
|
img.format === mipData.format && |
|
img.internalformat === mipData.internalformat && |
|
img.type === mipData.type, |
|
'incompatible type for mip image'); |
|
|
|
if (img.compressed) { |
|
// TODO: check size for compressed images |
|
} else if (img.data) { |
|
// check(img.data.byteLength === mw * mh * |
|
// Math.max(pixelSize(img.type, c), img.unpackAlignment), |
|
var rowSize = Math.ceil(pixelSize(img.type, c) * mw / img.unpackAlignment) * img.unpackAlignment; |
|
check(img.data.byteLength === rowSize * mh, |
|
'invalid data for image, buffer size is inconsistent with image format'); |
|
} else if (img.element) { |
|
// TODO: check element can be loaded |
|
} else if (img.copy) { |
|
// TODO: check compatible format and type |
|
} |
|
} else if (!info.genMipmaps) { |
|
check((mipData.mipmask & (1 << i)) === 0, 'extra mipmap data'); |
|
} |
|
} |
|
|
|
if (mipData.compressed) { |
|
check(!info.genMipmaps, |
|
'mipmap generation for compressed images not supported'); |
|
} |
|
} |
|
|
|
function checkTextureCube (texture, info, faces, limits) { |
|
var w = texture.width; |
|
var h = texture.height; |
|
var c = texture.channels; |
|
|
|
// Check texture shape |
|
check( |
|
w > 0 && w <= limits.maxTextureSize && h > 0 && h <= limits.maxTextureSize, |
|
'invalid texture shape'); |
|
check( |
|
w === h, |
|
'cube map must be square'); |
|
check( |
|
info.wrapS === GL_CLAMP_TO_EDGE && info.wrapT === GL_CLAMP_TO_EDGE, |
|
'wrap mode not supported by cube map'); |
|
|
|
for (var i = 0; i < faces.length; ++i) { |
|
var face = faces[i]; |
|
check( |
|
face.width === w && face.height === h, |
|
'inconsistent cube map face shape'); |
|
|
|
if (info.genMipmaps) { |
|
check(!face.compressed, |
|
'can not generate mipmap for compressed textures'); |
|
check(face.mipmask === 1, |
|
'can not specify mipmaps and generate mipmaps'); |
|
} else { |
|
// TODO: check mip and filter mode |
|
} |
|
|
|
var mipmaps = face.images; |
|
for (var j = 0; j < 16; ++j) { |
|
var img = mipmaps[j]; |
|
if (img) { |
|
var mw = w >> j; |
|
var mh = h >> j; |
|
check(face.mipmask & (1 << j), 'missing mipmap data'); |
|
check( |
|
img.width === mw && |
|
img.height === mh, |
|
'invalid shape for mip images'); |
|
check( |
|
img.format === texture.format && |
|
img.internalformat === texture.internalformat && |
|
img.type === texture.type, |
|
'incompatible type for mip image'); |
|
|
|
if (img.compressed) { |
|
// TODO: check size for compressed images |
|
} else if (img.data) { |
|
check(img.data.byteLength === mw * mh * |
|
Math.max(pixelSize(img.type, c), img.unpackAlignment), |
|
'invalid data for image, buffer size is inconsistent with image format'); |
|
} else if (img.element) { |
|
// TODO: check element can be loaded |
|
} else if (img.copy) { |
|
// TODO: check compatible format and type |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
var check$1 = extend(check, { |
|
optional: checkOptional, |
|
raise: raise, |
|
commandRaise: commandRaise, |
|
command: checkCommand, |
|
parameter: checkParameter, |
|
commandParameter: checkParameterCommand, |
|
constructor: checkConstructor, |
|
type: checkTypeOf, |
|
commandType: checkCommandType, |
|
isTypedArray: checkIsTypedArray, |
|
nni: checkNonNegativeInt, |
|
oneOf: checkOneOf, |
|
shaderError: checkShaderError, |
|
linkError: checkLinkError, |
|
callSite: guessCallSite, |
|
saveCommandRef: saveCommandRef, |
|
saveDrawInfo: saveDrawCommandInfo, |
|
framebufferFormat: checkFramebufferFormat, |
|
guessCommand: guessCommand, |
|
texture2D: checkTexture2D, |
|
textureCube: checkTextureCube |
|
}); |
|
|
|
var VARIABLE_COUNTER = 0; |
|
|
|
var DYN_FUNC = 0; |
|
|
|
function DynamicVariable (type, data) { |
|
this.id = (VARIABLE_COUNTER++); |
|
this.type = type; |
|
this.data = data; |
|
} |
|
|
|
function escapeStr (str) { |
|
return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"') |
|
} |
|
|
|
function splitParts (str) { |
|
if (str.length === 0) { |
|
return [] |
|
} |
|
|
|
var firstChar = str.charAt(0); |
|
var lastChar = str.charAt(str.length - 1); |
|
|
|
if (str.length > 1 && |
|
firstChar === lastChar && |
|
(firstChar === '"' || firstChar === "'")) { |
|
return ['"' + escapeStr(str.substr(1, str.length - 2)) + '"'] |
|
} |
|
|
|
var parts = /\[(false|true|null|\d+|'[^']*'|"[^"]*")\]/.exec(str); |
|
if (parts) { |
|
return ( |
|
splitParts(str.substr(0, parts.index)) |
|
.concat(splitParts(parts[1])) |
|
.concat(splitParts(str.substr(parts.index + parts[0].length))) |
|
) |
|
} |
|
|
|
var subparts = str.split('.'); |
|
if (subparts.length === 1) { |
|
return ['"' + escapeStr(str) + '"'] |
|
} |
|
|
|
var result = []; |
|
for (var i = 0; i < subparts.length; ++i) { |
|
result = result.concat(splitParts(subparts[i])); |
|
} |
|
return result |
|
} |
|
|
|
function toAccessorString (str) { |
|
return '[' + splitParts(str).join('][') + ']' |
|
} |
|
|
|
function defineDynamic (type, data) { |
|
return new DynamicVariable(type, toAccessorString(data + '')) |
|
} |
|
|
|
function isDynamic (x) { |
|
return (typeof x === 'function' && !x._reglType) || |
|
x instanceof DynamicVariable |
|
} |
|
|
|
function unbox (x, path) { |
|
if (typeof x === 'function') { |
|
return new DynamicVariable(DYN_FUNC, x) |
|
} |
|
return x |
|
} |
|
|
|
var dynamic = { |
|
DynamicVariable: DynamicVariable, |
|
define: defineDynamic, |
|
isDynamic: isDynamic, |
|
unbox: unbox, |
|
accessor: toAccessorString |
|
}; |
|
|
|
/* globals requestAnimationFrame, cancelAnimationFrame */ |
|
var raf = { |
|
next: typeof requestAnimationFrame === 'function' |
|
? function (cb) { return requestAnimationFrame(cb) } |
|
: function (cb) { return setTimeout(cb, 16) }, |
|
cancel: typeof cancelAnimationFrame === 'function' |
|
? function (raf) { return cancelAnimationFrame(raf) } |
|
: clearTimeout |
|
}; |
|
|
|
/* globals performance */ |
|
var clock = (typeof performance !== 'undefined' && performance.now) |
|
? function () { return performance.now() } |
|
: function () { return +(new Date()) }; |
|
|
|
function createStringStore () { |
|
var stringIds = {'': 0}; |
|
var stringValues = ['']; |
|
return { |
|
id: function (str) { |
|
var result = stringIds[str]; |
|
if (result) { |
|
return result |
|
} |
|
result = stringIds[str] = stringValues.length; |
|
stringValues.push(str); |
|
return result |
|
}, |
|
|
|
str: function (id) { |
|
return stringValues[id] |
|
} |
|
} |
|
} |
|
|
|
// Context and canvas creation helper functions |
|
function createCanvas (element, onDone, pixelRatio) { |
|
var canvas = document.createElement('canvas'); |
|
extend(canvas.style, { |
|
border: 0, |
|
margin: 0, |
|
padding: 0, |
|
top: 0, |
|
left: 0 |
|
}); |
|
element.appendChild(canvas); |
|
|
|
if (element === document.body) { |
|
canvas.style.position = 'absolute'; |
|
extend(element.style, { |
|
margin: 0, |
|
padding: 0 |
|
}); |
|
} |
|
|
|
function resize () { |
|
var w = window.innerWidth; |
|
var h = window.innerHeight; |
|
if (element !== document.body) { |
|
var bounds = element.getBoundingClientRect(); |
|
w = bounds.right - bounds.left; |
|
h = bounds.bottom - bounds.top; |
|
} |
|
canvas.width = pixelRatio * w; |
|
canvas.height = pixelRatio * h; |
|
extend(canvas.style, { |
|
width: w + 'px', |
|
height: h + 'px' |
|
}); |
|
} |
|
|
|
window.addEventListener('resize', resize, false); |
|
|
|
function onDestroy () { |
|
window.removeEventListener('resize', resize); |
|
element.removeChild(canvas); |
|
} |
|
|
|
resize(); |
|
|
|
return { |
|
canvas: canvas, |
|
onDestroy: onDestroy |
|
} |
|
} |
|
|
|
function createContext (canvas, contexAttributes) { |
|
function get (name) { |
|
try { |
|
return canvas.getContext(name, contexAttributes) |
|
} catch (e) { |
|
return null |
|
} |
|
} |
|
return ( |
|
get('webgl') || |
|
get('experimental-webgl') || |
|
get('webgl-experimental') |
|
) |
|
} |
|
|
|
function isHTMLElement (obj) { |
|
return ( |
|
typeof obj.nodeName === 'string' && |
|
typeof obj.appendChild === 'function' && |
|
typeof obj.getBoundingClientRect === 'function' |
|
) |
|
} |
|
|
|
function isWebGLContext (obj) { |
|
return ( |
|
typeof obj.drawArrays === 'function' || |
|
typeof obj.drawElements === 'function' |
|
) |
|
} |
|
|
|
function parseExtensions (input) { |
|
if (typeof input === 'string') { |
|
return input.split() |
|
} |
|
check$1(Array.isArray(input), 'invalid extension array'); |
|
return input |
|
} |
|
|
|
function getElement (desc) { |
|
if (typeof desc === 'string') { |
|
check$1(typeof document !== 'undefined', 'not supported outside of DOM'); |
|
return document.querySelector(desc) |
|
} |
|
return desc |
|
} |
|
|
|
function parseArgs (args_) { |
|
var args = args_ || {}; |
|
var element, container, canvas, gl; |
|
var contextAttributes = {}; |
|
var extensions = []; |
|
var optionalExtensions = []; |
|
var pixelRatio = (typeof window === 'undefined' ? 1 : window.devicePixelRatio); |
|
var profile = false; |
|
var onDone = function (err) { |
|
if (err) { |
|
check$1.raise(err); |
|
} |
|
}; |
|
var onDestroy = function () {}; |
|
if (typeof args === 'string') { |
|
check$1( |
|
typeof document !== 'undefined', |
|
'selector queries only supported in DOM enviroments'); |
|
element = document.querySelector(args); |
|
check$1(element, 'invalid query string for element'); |
|
} else if (typeof args === 'object') { |
|
if (isHTMLElement(args)) { |
|
element = args; |
|
} else if (isWebGLContext(args)) { |
|
gl = args; |
|
canvas = gl.canvas; |
|
} else { |
|
check$1.constructor(args); |
|
if ('gl' in args) { |
|
gl = args.gl; |
|
} else if ('canvas' in args) { |
|
canvas = getElement(args.canvas); |
|
} else if ('container' in args) { |
|
container = getElement(args.container); |
|
} |
|
if ('attributes' in args) { |
|
contextAttributes = args.attributes; |
|
check$1.type(contextAttributes, 'object', 'invalid context attributes'); |
|
} |
|
if ('extensions' in args) { |
|
extensions = parseExtensions(args.extensions); |
|
} |
|
if ('optionalExtensions' in args) { |
|
optionalExtensions = parseExtensions(args.optionalExtensions); |
|
} |
|
if ('onDone' in args) { |
|
check$1.type( |
|
args.onDone, 'function', |
|
'invalid or missing onDone callback'); |
|
onDone = args.onDone; |
|
} |
|
if ('profile' in args) { |
|
profile = !!args.profile; |
|
} |
|
if ('pixelRatio' in args) { |
|
pixelRatio = +args.pixelRatio; |
|
check$1(pixelRatio > 0, 'invalid pixel ratio'); |
|
} |
|
} |
|
} else { |
|
check$1.raise('invalid arguments to regl'); |
|
} |
|
|
|
if (element) { |
|
if (element.nodeName.toLowerCase() === 'canvas') { |
|
canvas = element; |
|
} else { |
|
container = element; |
|
} |
|
} |
|
|
|
if (!gl) { |
|
if (!canvas) { |
|
check$1( |
|
typeof document !== 'undefined', |
|
'must manually specify webgl context outside of DOM environments'); |
|
var result = createCanvas(container || document.body, onDone, pixelRatio); |
|
if (!result) { |
|
return null |
|
} |
|
canvas = result.canvas; |
|
onDestroy = result.onDestroy; |
|
} |
|
gl = createContext(canvas, contextAttributes); |
|
} |
|
|
|
if (!gl) { |
|
onDestroy(); |
|
onDone('webgl not supported, try upgrading your browser or graphics drivers http://get.webgl.org'); |
|
return null |
|
} |
|
|
|
return { |
|
gl: gl, |
|
canvas: canvas, |
|
container: container, |
|
extensions: extensions, |
|
optionalExtensions: optionalExtensions, |
|
pixelRatio: pixelRatio, |
|
profile: profile, |
|
onDone: onDone, |
|
onDestroy: onDestroy |
|
} |
|
} |
|
|
|
function createExtensionCache (gl, config) { |
|
var extensions = {}; |
|
|
|
function tryLoadExtension (name_) { |
|
check$1.type(name_, 'string', 'extension name must be string'); |
|
var name = name_.toLowerCase(); |
|
var ext; |
|
try { |
|
ext = extensions[name] = gl.getExtension(name); |
|
} catch (e) {} |
|
return !!ext |
|
} |
|
|
|
for (var i = 0; i < config.extensions.length; ++i) { |
|
var name = config.extensions[i]; |
|
if (!tryLoadExtension(name)) { |
|
config.onDestroy(); |
|
config.onDone('"' + name + '" extension is not supported by the current WebGL context, try upgrading your system or a different browser'); |
|
return null |
|
} |
|
} |
|
|
|
config.optionalExtensions.forEach(tryLoadExtension); |
|
|
|
return { |
|
extensions: extensions, |
|
restore: function () { |
|
Object.keys(extensions).forEach(function (name) { |
|
if (!tryLoadExtension(name)) { |
|
throw new Error('(regl): error restoring extension ' + name) |
|
} |
|
}); |
|
} |
|
} |
|
} |
|
|
|
var GL_SUBPIXEL_BITS = 0x0D50; |
|
var GL_RED_BITS = 0x0D52; |
|
var GL_GREEN_BITS = 0x0D53; |
|
var GL_BLUE_BITS = 0x0D54; |
|
var GL_ALPHA_BITS = 0x0D55; |
|
var GL_DEPTH_BITS = 0x0D56; |
|
var GL_STENCIL_BITS = 0x0D57; |
|
|
|
var GL_ALIASED_POINT_SIZE_RANGE = 0x846D; |
|
var GL_ALIASED_LINE_WIDTH_RANGE = 0x846E; |
|
|
|
var GL_MAX_TEXTURE_SIZE = 0x0D33; |
|
var GL_MAX_VIEWPORT_DIMS = 0x0D3A; |
|
var GL_MAX_VERTEX_ATTRIBS = 0x8869; |
|
var GL_MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB; |
|
var GL_MAX_VARYING_VECTORS = 0x8DFC; |
|
var GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D; |
|
var GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C; |
|
var GL_MAX_TEXTURE_IMAGE_UNITS = 0x8872; |
|
var GL_MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD; |
|
var GL_MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C; |
|
var GL_MAX_RENDERBUFFER_SIZE = 0x84E8; |
|
|
|
var GL_VENDOR = 0x1F00; |
|
var GL_RENDERER = 0x1F01; |
|
var GL_VERSION = 0x1F02; |
|
var GL_SHADING_LANGUAGE_VERSION = 0x8B8C; |
|
|
|
var GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF; |
|
|
|
var GL_MAX_COLOR_ATTACHMENTS_WEBGL = 0x8CDF; |
|
var GL_MAX_DRAW_BUFFERS_WEBGL = 0x8824; |
|
|
|
var wrapLimits = function (gl, extensions) { |
|
var maxAnisotropic = 1; |
|
if (extensions.ext_texture_filter_anisotropic) { |
|
maxAnisotropic = gl.getParameter(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT); |
|
} |
|
|
|
var maxDrawbuffers = 1; |
|
var maxColorAttachments = 1; |
|
if (extensions.webgl_draw_buffers) { |
|
maxDrawbuffers = gl.getParameter(GL_MAX_DRAW_BUFFERS_WEBGL); |
|
maxColorAttachments = gl.getParameter(GL_MAX_COLOR_ATTACHMENTS_WEBGL); |
|
} |
|
|
|
return { |
|
// drawing buffer bit depth |
|
colorBits: [ |
|
gl.getParameter(GL_RED_BITS), |
|
gl.getParameter(GL_GREEN_BITS), |
|
gl.getParameter(GL_BLUE_BITS), |
|
gl.getParameter(GL_ALPHA_BITS) |
|
], |
|
depthBits: gl.getParameter(GL_DEPTH_BITS), |
|
stencilBits: gl.getParameter(GL_STENCIL_BITS), |
|
subpixelBits: gl.getParameter(GL_SUBPIXEL_BITS), |
|
|
|
// supported extensions |
|
extensions: Object.keys(extensions).filter(function (ext) { |
|
return !!extensions[ext] |
|
}), |
|
|
|
// max aniso samples |
|
maxAnisotropic: maxAnisotropic, |
|
|
|
// max draw buffers |
|
maxDrawbuffers: maxDrawbuffers, |
|
maxColorAttachments: maxColorAttachments, |
|
|
|
// point and line size ranges |
|
pointSizeDims: gl.getParameter(GL_ALIASED_POINT_SIZE_RANGE), |
|
lineWidthDims: gl.getParameter(GL_ALIASED_LINE_WIDTH_RANGE), |
|
maxViewportDims: gl.getParameter(GL_MAX_VIEWPORT_DIMS), |
|
maxCombinedTextureUnits: gl.getParameter(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS), |
|
maxCubeMapSize: gl.getParameter(GL_MAX_CUBE_MAP_TEXTURE_SIZE), |
|
maxRenderbufferSize: gl.getParameter(GL_MAX_RENDERBUFFER_SIZE), |
|
maxTextureUnits: gl.getParameter(GL_MAX_TEXTURE_IMAGE_UNITS), |
|
maxTextureSize: gl.getParameter(GL_MAX_TEXTURE_SIZE), |
|
maxAttributes: gl.getParameter(GL_MAX_VERTEX_ATTRIBS), |
|
maxVertexUniforms: gl.getParameter(GL_MAX_VERTEX_UNIFORM_VECTORS), |
|
maxVertexTextureUnits: gl.getParameter(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS), |
|
maxVaryingVectors: gl.getParameter(GL_MAX_VARYING_VECTORS), |
|
maxFragmentUniforms: gl.getParameter(GL_MAX_FRAGMENT_UNIFORM_VECTORS), |
|
|
|
// vendor info |
|
glsl: gl.getParameter(GL_SHADING_LANGUAGE_VERSION), |
|
renderer: gl.getParameter(GL_RENDERER), |
|
vendor: gl.getParameter(GL_VENDOR), |
|
version: gl.getParameter(GL_VERSION) |
|
} |
|
}; |
|
|
|
function isNDArrayLike (obj) { |
|
return ( |
|
!!obj && |
|
typeof obj === 'object' && |
|
Array.isArray(obj.shape) && |
|
Array.isArray(obj.stride) && |
|
typeof obj.offset === 'number' && |
|
obj.shape.length === obj.stride.length && |
|
(Array.isArray(obj.data) || |
|
isTypedArray(obj.data))) |
|
} |
|
|
|
var values = function (obj) { |
|
return Object.keys(obj).map(function (key) { return obj[key] }) |
|
}; |
|
|
|
function loop (n, f) { |
|
var result = Array(n); |
|
for (var i = 0; i < n; ++i) { |
|
result[i] = f(i); |
|
} |
|
return result |
|
} |
|
|
|
var GL_BYTE$1 = 5120; |
|
var GL_UNSIGNED_BYTE$2 = 5121; |
|
var GL_SHORT$1 = 5122; |
|
var GL_UNSIGNED_SHORT$1 = 5123; |
|
var GL_INT$1 = 5124; |
|
var GL_UNSIGNED_INT$1 = 5125; |
|
var GL_FLOAT$2 = 5126; |
|
|
|
var bufferPool = loop(8, function () { |
|
return [] |
|
}); |
|
|
|
function nextPow16 (v) { |
|
for (var i = 16; i <= (1 << 28); i *= 16) { |
|
if (v <= i) { |
|
return i |
|
} |
|
} |
|
return 0 |
|
} |
|
|
|
function log2 (v) { |
|
var r, shift; |
|
r = (v > 0xFFFF) << 4; |
|
v >>>= r; |
|
shift = (v > 0xFF) << 3; |
|
v >>>= shift; r |= shift; |
|
shift = (v > 0xF) << 2; |
|
v >>>= shift; r |= shift; |
|
shift = (v > 0x3) << 1; |
|
v >>>= shift; r |= shift; |
|
return r | (v >> 1) |
|
} |
|
|
|
function alloc (n) { |
|
var sz = nextPow16(n); |
|
var bin = bufferPool[log2(sz) >> 2]; |
|
if (bin.length > 0) { |
|
return bin.pop() |
|
} |
|
return new ArrayBuffer(sz) |
|
} |
|
|
|
function free (buf) { |
|
bufferPool[log2(buf.byteLength) >> 2].push(buf); |
|
} |
|
|
|
function allocType (type, n) { |
|
var result = null; |
|
switch (type) { |
|
case GL_BYTE$1: |
|
result = new Int8Array(alloc(n), 0, n); |
|
break |
|
case GL_UNSIGNED_BYTE$2: |
|
result = new Uint8Array(alloc(n), 0, n); |
|
break |
|
case GL_SHORT$1: |
|
result = new Int16Array(alloc(2 * n), 0, n); |
|
break |
|
case GL_UNSIGNED_SHORT$1: |
|
result = new Uint16Array(alloc(2 * n), 0, n); |
|
break |
|
case GL_INT$1: |
|
result = new Int32Array(alloc(4 * n), 0, n); |
|
break |
|
case GL_UNSIGNED_INT$1: |
|
result = new Uint32Array(alloc(4 * n), 0, n); |
|
break |
|
case GL_FLOAT$2: |
|
result = new Float32Array(alloc(4 * n), 0, n); |
|
break |
|
default: |
|
return null |
|
} |
|
if (result.length !== n) { |
|
return result.subarray(0, n) |
|
} |
|
return result |
|
} |
|
|
|
function freeType (array) { |
|
free(array.buffer); |
|
} |
|
|
|
var pool = { |
|
alloc: alloc, |
|
free: free, |
|
allocType: allocType, |
|
freeType: freeType |
|
}; |
|
|
|
var flattenUtils = { |
|
shape: arrayShape$1, |
|
flatten: flattenArray |
|
}; |
|
|
|
function flatten1D (array, nx, out) { |
|
for (var i = 0; i < nx; ++i) { |
|
out[i] = array[i]; |
|
} |
|
} |
|
|
|
function flatten2D (array, nx, ny, out) { |
|
var ptr = 0; |
|
for (var i = 0; i < nx; ++i) { |
|
var row = array[i]; |
|
for (var j = 0; j < ny; ++j) { |
|
out[ptr++] = row[j]; |
|
} |
|
} |
|
} |
|
|
|
function flatten3D (array, nx, ny, nz, out, ptr_) { |
|
var ptr = ptr_; |
|
for (var i = 0; i < nx; ++i) { |
|
var row = array[i]; |
|
for (var j = 0; j < ny; ++j) { |
|
var col = row[j]; |
|
for (var k = 0; k < nz; ++k) { |
|
out[ptr++] = col[k]; |
|
} |
|
} |
|
} |
|
} |
|
|
|
function flattenRec (array, shape, level, out, ptr) { |
|
var stride = 1; |
|
for (var i = level + 1; i < shape.length; ++i) { |
|
stride *= shape[i]; |
|
} |
|
var n = shape[level]; |
|
if (shape.length - level === 4) { |
|
var nx = shape[level + 1]; |
|
var ny = shape[level + 2]; |
|
var nz = shape[level + 3]; |
|
for (i = 0; i < n; ++i) { |
|
flatten3D(array[i], nx, ny, nz, out, ptr); |
|
ptr += stride; |
|
} |
|
} else { |
|
for (i = 0; i < n; ++i) { |
|
flattenRec(array[i], shape, level + 1, out, ptr); |
|
ptr += stride; |
|
} |
|
} |
|
} |
|
|
|
function flattenArray (array, shape, type, out_) { |
|
var sz = 1; |
|
if (shape.length) { |
|
for (var i = 0; i < shape.length; ++i) { |
|
sz *= shape[i]; |
|
} |
|
} else { |
|
sz = 0; |
|
} |
|
var out = out_ || pool.allocType(type, sz); |
|
switch (shape.length) { |
|
case 0: |
|
break |
|
case 1: |
|
flatten1D(array, shape[0], out); |
|
break |
|
case 2: |
|
flatten2D(array, shape[0], shape[1], out); |
|
break |
|
case 3: |
|
flatten3D(array, shape[0], shape[1], shape[2], out, 0); |
|
break |
|
default: |
|
flattenRec(array, shape, 0, out, 0); |
|
} |
|
return out |
|
} |
|
|
|
function arrayShape$1 (array_) { |
|
var shape = []; |
|
for (var array = array_; array.length; array = array[0]) { |
|
shape.push(array.length); |
|
} |
|
return shape |
|
} |
|
|
|
var int8 = 5120; |
|
var int16 = 5122; |
|
var int32 = 5124; |
|
var uint8 = 5121; |
|
var uint16 = 5123; |
|
var uint32 = 5125; |
|
var float = 5126; |
|
var float32 = 5126; |
|
var glTypes = { |
|
int8: int8, |
|
int16: int16, |
|
int32: int32, |
|
uint8: uint8, |
|
uint16: uint16, |
|
uint32: uint32, |
|
float: float, |
|
float32: float32 |
|
}; |
|
|
|
var dynamic$1 = 35048; |
|
var stream = 35040; |
|
var usageTypes = { |
|
dynamic: dynamic$1, |
|
stream: stream, |
|
"static": 35044 |
|
}; |
|
|
|
var arrayFlatten = flattenUtils.flatten; |
|
var arrayShape = flattenUtils.shape; |
|
|
|
var GL_STATIC_DRAW = 0x88E4; |
|
var GL_STREAM_DRAW = 0x88E0; |
|
|
|
var GL_UNSIGNED_BYTE$1 = 5121; |
|
var GL_FLOAT$1 = 5126; |
|
|
|
var DTYPES_SIZES = []; |
|
DTYPES_SIZES[5120] = 1; // int8 |
|
DTYPES_SIZES[5122] = 2; // int16 |
|
DTYPES_SIZES[5124] = 4; // int32 |
|
DTYPES_SIZES[5121] = 1; // uint8 |
|
DTYPES_SIZES[5123] = 2; // uint16 |
|
DTYPES_SIZES[5125] = 4; // uint32 |
|
DTYPES_SIZES[5126] = 4; // float32 |
|
|
|
function typedArrayCode (data) { |
|
return arrayTypes[Object.prototype.toString.call(data)] | 0 |
|
} |
|
|
|
function copyArray (out, inp) { |
|
for (var i = 0; i < inp.length; ++i) { |
|
out[i] = inp[i]; |
|
} |
|
} |
|
|
|
function transpose ( |
|
result, data, shapeX, shapeY, strideX, strideY, offset) { |
|
var ptr = 0; |
|
for (var i = 0; i < shapeX; ++i) { |
|
for (var j = 0; j < shapeY; ++j) { |
|
result[ptr++] = data[strideX * i + strideY * j + offset]; |
|
} |
|
} |
|
} |
|
|
|
function wrapBufferState (gl, stats, config) { |
|
var bufferCount = 0; |
|
var bufferSet = {}; |
|
|
|
function REGLBuffer (type) { |
|
this.id = bufferCount++; |
|
this.buffer = gl.createBuffer(); |
|
this.type = type; |
|
this.usage = GL_STATIC_DRAW; |
|
this.byteLength = 0; |
|
this.dimension = 1; |
|
this.dtype = GL_UNSIGNED_BYTE$1; |
|
|
|
this.persistentData = null; |
|
|
|
if (config.profile) { |
|
this.stats = {size: 0}; |
|
} |
|
} |
|
|
|
REGLBuffer.prototype.bind = function () { |
|
gl.bindBuffer(this.type, this.buffer); |
|
}; |
|
|
|
REGLBuffer.prototype.destroy = function () { |
|
destroy(this); |
|
}; |
|
|
|
var streamPool = []; |
|
|
|
function createStream (type, data) { |
|
var buffer = streamPool.pop(); |
|
if (!buffer) { |
|
buffer = new REGLBuffer(type); |
|
} |
|
buffer.bind(); |
|
initBufferFromData(buffer, data, GL_STREAM_DRAW, 0, 1, false); |
|
return buffer |
|
} |
|
|
|
function destroyStream (stream$$1) { |
|
streamPool.push(stream$$1); |
|
} |
|
|
|
function initBufferFromTypedArray (buffer, data, usage) { |
|
buffer.byteLength = data.byteLength; |
|
gl.bufferData(buffer.type, data, usage); |
|
} |
|
|
|
function initBufferFromData (buffer, data, usage, dtype, dimension, persist) { |
|
var shape; |
|
buffer.usage = usage; |
|
if (Array.isArray(data)) { |
|
buffer.dtype = dtype || GL_FLOAT$1; |
|
if (data.length > 0) { |
|
var flatData; |
|
if (Array.isArray(data[0])) { |
|
shape = arrayShape(data); |
|
var dim = 1; |
|
for (var i = 1; i < shape.length; ++i) { |
|
dim *= shape[i]; |
|
} |
|
buffer.dimension = dim; |
|
flatData = arrayFlatten(data, shape, buffer.dtype); |
|
initBufferFromTypedArray(buffer, flatData, usage); |
|
if (persist) { |
|
buffer.persistentData = flatData; |
|
} else { |
|
pool.freeType(flatData); |
|
} |
|
} else if (typeof data[0] === 'number') { |
|
buffer.dimension = dimension; |
|
var typedData = pool.allocType(buffer.dtype, data.length); |
|
copyArray(typedData, data); |
|
initBufferFromTypedArray(buffer, typedData, usage); |
|
if (persist) { |
|
buffer.persistentData = typedData; |
|
} else { |
|
pool.freeType(typedData); |
|
} |
|
} else if (isTypedArray(data[0])) { |
|
buffer.dimension = data[0].length; |
|
buffer.dtype = dtype || typedArrayCode(data[0]) || GL_FLOAT$1; |
|
flatData = arrayFlatten( |
|
data, |
|
[data.length, data[0].length], |
|
buffer.dtype); |
|
initBufferFromTypedArray(buffer, flatData, usage); |
|
if (persist) { |
|
buffer.persistentData = flatData; |
|
} else { |
|
pool.freeType(flatData); |
|
} |
|
} else { |
|
check$1.raise('invalid buffer data'); |
|
} |
|
} |
|
} else if (isTypedArray(data)) { |
|
buffer.dtype = dtype || typedArrayCode(data); |
|
buffer.dimension = dimension; |
|
initBufferFromTypedArray(buffer, data, usage); |
|
if (persist) { |
|
buffer.persistentData = new Uint8Array(new Uint8Array(data.buffer)); |
|
} |
|
} else if (isNDArrayLike(data)) { |
|
shape = data.shape; |
|
var stride = data.stride; |
|
var offset = data.offset; |
|
|
|
var shapeX = 0; |
|
var shapeY = 0; |
|
var strideX = 0; |
|
var strideY = 0; |
|
if (shape.length === 1) { |
|
shapeX = shape[0]; |
|
shapeY = 1; |
|
strideX = stride[0]; |
|
strideY = 0; |
|
} else if (shape.length === 2) { |
|
shapeX = shape[0]; |
|
shapeY = shape[1]; |
|
strideX = stride[0]; |
|
strideY = stride[1]; |
|
} else { |
|
check$1.raise('invalid shape'); |
|
} |
|
|
|
buffer.dtype = dtype || typedArrayCode(data.data) || GL_FLOAT$1; |
|
buffer.dimension = shapeY; |
|
|
|
var transposeData = pool.allocType(buffer.dtype, shapeX * shapeY); |
|
transpose(transposeData, |
|
data.data, |
|
shapeX, shapeY, |
|
strideX, strideY, |
|
offset); |
|
initBufferFromTypedArray(buffer, transposeData, usage); |
|
if (persist) { |
|
buffer.persistentData = transposeData; |
|
} else { |
|
pool.freeType(transposeData); |
|
} |
|
} else { |
|
check$1.raise('invalid buffer data'); |
|
} |
|
} |
|
|
|
function destroy (buffer) { |
|
stats.bufferCount--; |
|
|
|
var handle = buffer.buffer; |
|
check$1(handle, 'buffer must not be deleted already'); |
|
gl.deleteBuffer(handle); |
|
buffer.buffer = null; |
|
delete bufferSet[buffer.id]; |
|
} |
|
|
|
function createBuffer (options, type, deferInit, persistent) { |
|
stats.bufferCount++; |
|
|
|
var buffer = new REGLBuffer(type); |
|
bufferSet[buffer.id] = buffer; |
|
|
|
function reglBuffer (options) { |
|
var usage = GL_STATIC_DRAW; |
|
var data = null; |
|
var byteLength = 0; |
|
var dtype = 0; |
|
var dimension = 1; |
|
if (Array.isArray(options) || |
|
isTypedArray(options) || |
|
isNDArrayLike(options)) { |
|
data = options; |
|
} else if (typeof options === 'number') { |
|
byteLength = options | 0; |
|
} else if (options) { |
|
check$1.type( |
|
options, 'object', |
|
'buffer arguments must be an object, a number or an array'); |
|
|
|
if ('data' in options) { |
|
check$1( |
|
data === null || |
|
Array.isArray(data) || |
|
isTypedArray(data) || |
|
isNDArrayLike(data), |
|
'invalid data for buffer'); |
|
data = options.data; |
|
} |
|
|
|
if ('usage' in options) { |
|
check$1.parameter(options.usage, usageTypes, 'invalid buffer usage'); |
|
usage = usageTypes[options.usage]; |
|
} |
|
|
|
if ('type' in options) { |
|
check$1.parameter(options.type, glTypes, 'invalid buffer type'); |
|
dtype = glTypes[options.type]; |
|
} |
|
|
|
if ('dimension' in options) { |
|
check$1.type(options.dimension, 'number', 'invalid dimension'); |
|
dimension = options.dimension | 0; |
|
} |
|
|
|
if ('length' in options) { |
|
check$1.nni(byteLength, 'buffer length must be a nonnegative integer'); |
|
byteLength = options.length | 0; |
|
} |
|
} |
|
|
|
buffer.bind(); |
|
if (!data) { |
|
gl.bufferData(buffer.type, byteLength, usage); |
|
buffer.dtype = dtype || GL_UNSIGNED_BYTE$1; |
|
buffer.usage = usage; |
|
buffer.dimension = dimension; |
|
buffer.byteLength = byteLength; |
|
} else { |
|
initBufferFromData(buffer, data, usage, dtype, dimension, persistent); |
|
} |
|
|
|
if (config.profile) { |
|
buffer.stats.size = buffer.byteLength * DTYPES_SIZES[buffer.dtype]; |
|
} |
|
|
|
return reglBuffer |
|
} |
|
|
|
function setSubData (data, offset) { |
|
check$1(offset + data.byteLength <= buffer.byteLength, |
|
'invalid buffer subdata call, buffer is too small. ' + ' Can\'t write data of size ' + data.byteLength + ' starting from offset ' + offset + ' to a buffer of size ' + buffer.byteLength); |
|
|
|
gl.bufferSubData(buffer.type, offset, data); |
|
} |
|
|
|
function subdata (data, offset_) { |
|
var offset = (offset_ || 0) | 0; |
|
var shape; |
|
buffer.bind(); |
|
if (Array.isArray(data)) { |
|
if (data.length > 0) { |
|
if (typeof data[0] === 'number') { |
|
var converted = pool.allocType(buffer.dtype, data.length); |
|
copyArray(converted, data); |
|
setSubData(converted, offset); |
|
pool.freeType(converted); |
|
} else if (Array.isArray(data[0]) || isTypedArray(data[0])) { |
|
shape = arrayShape(data); |
|
var flatData = arrayFlatten(data, shape, buffer.dtype); |
|
setSubData(flatData, offset); |
|
pool.freeType(flatData); |
|
} else { |
|
check$1.raise('invalid buffer data'); |
|
} |
|
} |
|
} else if (isTypedArray(data)) { |
|
setSubData(data, offset); |
|
} else if (isNDArrayLike(data)) { |
|
shape = data.shape; |
|
var stride = data.stride; |
|
|
|
var shapeX = 0; |
|
var shapeY = 0; |
|
var strideX = 0; |
|
var strideY = 0; |
|
if (shape.length === 1) { |
|
shapeX = shape[0]; |
|
shapeY = 1; |
|
strideX = stride[0]; |
|
strideY = 0; |
|
} else if (shape.length === 2) { |
|
shapeX = shape[0]; |
|
shapeY = shape[1]; |
|
strideX = stride[0]; |
|
strideY = stride[1]; |
|
} else { |
|
check$1.raise('invalid shape'); |
|
} |
|
var dtype = Array.isArray(data.data) |
|
? buffer.dtype |
|
: typedArrayCode(data.data); |
|
|
|
var transposeData = pool.allocType(dtype, shapeX * shapeY); |
|
transpose(transposeData, |
|
data.data, |
|
shapeX, shapeY, |
|
strideX, strideY, |
|
data.offset); |
|
setSubData(transposeData, offset); |
|
pool.freeType(transposeData); |
|
} else { |
|
check$1.raise('invalid data for buffer subdata'); |
|
} |
|
return reglBuffer |
|
} |
|
|
|
if (!deferInit) { |
|
reglBuffer(options); |
|
} |
|
|
|
reglBuffer._reglType = 'buffer'; |
|
reglBuffer._buffer = buffer; |
|
reglBuffer.subdata = subdata; |
|
if (config.profile) { |
|
reglBuffer.stats = buffer.stats; |
|
} |
|
reglBuffer.destroy = function () { destroy(buffer); }; |
|
|
|
return reglBuffer |
|
} |
|
|
|
function restoreBuffers () { |
|
values(bufferSet).forEach(function (buffer) { |
|
buffer.buffer = gl.createBuffer(); |
|
gl.bindBuffer(buffer.type, buffer.buffer); |
|
gl.bufferData( |
|
buffer.type, buffer.persistentData || buffer.byteLength, buffer.usage); |
|
}); |
|
} |
|
|
|
if (config.profile) { |
|
stats.getTotalBufferSize = function () { |
|
var total = 0; |
|
// TODO: Right now, the streams are not part of the total count. |
|
Object.keys(bufferSet).forEach(function (key) { |
|
total += bufferSet[key].stats.size; |
|
}); |
|
return total |
|
}; |
|
} |
|
|
|
return { |
|
create: createBuffer, |
|
|
|
createStream: createStream, |
|
destroyStream: destroyStream, |
|
|
|
clear: function () { |
|
values(bufferSet).forEach(destroy); |
|
streamPool.forEach(destroy); |
|
}, |
|
|
|
getBuffer: function (wrapper) { |
|
if (wrapper && wrapper._buffer instanceof REGLBuffer) { |
|
return wrapper._buffer |
|
} |
|
return null |
|
}, |
|
|
|
restore: restoreBuffers, |
|
|
|
_initBuffer: initBufferFromData |
|
} |
|
} |
|
|
|
var points = 0; |
|
var point = 0; |
|
var lines = 1; |
|
var line = 1; |
|
var triangles = 4; |
|
var triangle = 4; |
|
var primTypes = { |
|
points: points, |
|
point: point, |
|
lines: lines, |
|
line: line, |
|
triangles: triangles, |
|
triangle: triangle, |
|
"line loop": 2, |
|
"line strip": 3, |
|
"triangle strip": 5, |
|
"triangle fan": 6 |
|
}; |
|
|
|
var GL_POINTS = 0; |
|
var GL_LINES = 1; |
|
var GL_TRIANGLES = 4; |
|
|
|
var GL_BYTE$2 = 5120; |
|
var GL_UNSIGNED_BYTE$3 = 5121; |
|
var GL_SHORT$2 = 5122; |
|
var GL_UNSIGNED_SHORT$2 = 5123; |
|
var GL_INT$2 = 5124; |
|
var GL_UNSIGNED_INT$2 = 5125; |
|
|
|
var GL_ELEMENT_ARRAY_BUFFER = 34963; |
|
|
|
var GL_STREAM_DRAW$1 = 0x88E0; |
|
var GL_STATIC_DRAW$1 = 0x88E4; |
|
|
|
function wrapElementsState (gl, extensions, bufferState, stats) { |
|
var elementSet = {}; |
|
var elementCount = 0; |
|
|
|
var elementTypes = { |
|
'uint8': GL_UNSIGNED_BYTE$3, |
|
'uint16': GL_UNSIGNED_SHORT$2 |
|
}; |
|
|
|
if (extensions.oes_element_index_uint) { |
|
elementTypes.uint32 = GL_UNSIGNED_INT$2; |
|
} |
|
|
|
function REGLElementBuffer (buffer) { |
|
this.id = elementCount++; |
|
elementSet[this.id] = this; |
|
this.buffer = buffer; |
|
this.primType = GL_TRIANGLES; |
|
this.vertCount = 0; |
|
this.type = 0; |
|
} |
|
|
|
REGLElementBuffer.prototype.bind = function () { |
|
this.buffer.bind(); |
|
}; |
|
|
|
var bufferPool = []; |
|
|
|
function createElementStream (data) { |
|
var result = bufferPool.pop(); |
|
if (!result) { |
|
result = new REGLElementBuffer(bufferState.create( |
|
null, |
|
GL_ELEMENT_ARRAY_BUFFER, |
|
true, |
|
false)._buffer); |
|
} |
|
initElements(result, data, GL_STREAM_DRAW$1, -1, -1, 0, 0); |
|
return result |
|
} |
|
|
|
function destroyElementStream (elements) { |
|
bufferPool.push(elements); |
|
} |
|
|
|
function initElements ( |
|
elements, |
|
data, |
|
usage, |
|
prim, |
|
count, |
|
byteLength, |
|
type) { |
|
elements.buffer.bind(); |
|
if (data) { |
|
var predictedType = type; |
|
if (!type && ( |
|
!isTypedArray(data) || |
|
(isNDArrayLike(data) && !isTypedArray(data.data)))) { |
|
predictedType = extensions.oes_element_index_uint |
|
? GL_UNSIGNED_INT$2 |
|
: GL_UNSIGNED_SHORT$2; |
|
} |
|
bufferState._initBuffer( |
|
elements.buffer, |
|
data, |
|
usage, |
|
predictedType, |
|
3); |
|
} else { |
|
gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, byteLength, usage); |
|
elements.buffer.dtype = dtype || GL_UNSIGNED_BYTE$3; |
|
elements.buffer.usage = usage; |
|
elements.buffer.dimension = 3; |
|
elements.buffer.byteLength = byteLength; |
|
} |
|
|
|
var dtype = type; |
|
if (!type) { |
|
switch (elements.buffer.dtype) { |
|
case GL_UNSIGNED_BYTE$3: |
|
case GL_BYTE$2: |
|
dtype = GL_UNSIGNED_BYTE$3; |
|
break |
|
|
|
case GL_UNSIGNED_SHORT$2: |
|
case GL_SHORT$2: |
|
dtype = GL_UNSIGNED_SHORT$2; |
|
break |
|
|
|
case GL_UNSIGNED_INT$2: |
|
case GL_INT$2: |
|
dtype = GL_UNSIGNED_INT$2; |
|
break |
|
|
|
default: |
|
check$1.raise('unsupported type for element array'); |
|
} |
|
elements.buffer.dtype = dtype; |
|
} |
|
elements.type = dtype; |
|
|
|
// Check oes_element_index_uint extension |
|
check$1( |
|
dtype !== GL_UNSIGNED_INT$2 || |
|
!!extensions.oes_element_index_uint, |
|
'32 bit element buffers not supported, enable oes_element_index_uint first'); |
|
|
|
// try to guess default primitive type and arguments |
|
var vertCount = count; |
|
if (vertCount < 0) { |
|
vertCount = elements.buffer.byteLength; |
|
if (dtype === GL_UNSIGNED_SHORT$2) { |
|
vertCount >>= 1; |
|
} else if (dtype === GL_UNSIGNED_INT$2) { |
|
vertCount >>= 2; |
|
} |
|
} |
|
elements.vertCount = vertCount; |
|
|
|
// try to guess primitive type from cell dimension |
|
var primType = prim; |
|
if (prim < 0) { |
|
primType = GL_TRIANGLES; |
|
var dimension = elements.buffer.dimension; |
|
if (dimension === 1) primType = GL_POINTS; |
|
if (dimension === 2) primType = GL_LINES; |
|
if (dimension === 3) primType = GL_TRIANGLES; |
|
} |
|
elements.primType = primType; |
|
} |
|
|
|
function destroyElements (elements) { |
|
stats.elementsCount--; |
|
|
|
check$1(elements.buffer !== null, 'must not double destroy elements'); |
|
delete elementSet[elements.id]; |
|
elements.buffer.destroy(); |
|
elements.buffer = null; |
|
} |
|
|
|
function createElements (options, persistent) { |
|
var buffer = bufferState.create(null, GL_ELEMENT_ARRAY_BUFFER, true); |
|
var elements = new REGLElementBuffer(buffer._buffer); |
|
stats.elementsCount++; |
|
|
|
function reglElements (options) { |
|
if (!options) { |
|
buffer(); |
|
elements.primType = GL_TRIANGLES; |
|
elements.vertCount = 0; |
|
elements.type = GL_UNSIGNED_BYTE$3; |
|
} else if (typeof options === 'number') { |
|
buffer(options); |
|
elements.primType = GL_TRIANGLES; |
|
elements.vertCount = options | 0; |
|
elements.type = GL_UNSIGNED_BYTE$3; |
|
} else { |
|
var data = null; |
|
var usage = GL_STATIC_DRAW$1; |
|
var primType = -1; |
|
var vertCount = -1; |
|
var byteLength = 0; |
|
var dtype = 0; |
|
if (Array.isArray(options) || |
|
isTypedArray(options) || |
|
isNDArrayLike(options)) { |
|
data = options; |
|
} else { |
|
check$1.type(options, 'object', 'invalid arguments for elements'); |
|
if ('data' in options) { |
|
data = options.data; |
|
check$1( |
|
Array.isArray(data) || |
|
isTypedArray(data) || |
|
isNDArrayLike(data), |
|
'invalid data for element buffer'); |
|
} |
|
if ('usage' in options) { |
|
check$1.parameter( |
|
options.usage, |
|
usageTypes, |
|
'invalid element buffer usage'); |
|
usage = usageTypes[options.usage]; |
|
} |
|
if ('primitive' in options) { |
|
check$1.parameter( |
|
options.primitive, |
|
primTypes, |
|
'invalid element buffer primitive'); |
|
primType = primTypes[options.primitive]; |
|
} |
|
if ('count' in options) { |
|
check$1( |
|
typeof options.count === 'number' && options.count >= 0, |
|
'invalid vertex count for elements'); |
|
vertCount = options.count | 0; |
|
} |
|
if ('type' in options) { |
|
check$1.parameter( |
|
options.type, |
|
elementTypes, |
|
'invalid buffer type'); |
|
dtype = elementTypes[options.type]; |
|
} |
|
if ('length' in options) { |
|
byteLength = options.length | 0; |
|
} else { |
|
byteLength = vertCount; |
|
if (dtype === GL_UNSIGNED_SHORT$2 || dtype === GL_SHORT$2) { |
|
byteLength *= 2; |
|
} else if (dtype === GL_UNSIGNED_INT$2 || dtype === GL_INT$2) { |
|
byteLength *= 4; |
|
} |
|
} |
|
} |
|
initElements( |
|
elements, |
|
data, |
|
usage, |
|
primType, |
|
vertCount, |
|
byteLength, |
|
dtype); |
|
} |
|
|
|
return reglElements |
|
} |
|
|
|
reglElements(options); |
|
|
|
reglElements._reglType = 'elements'; |
|
reglElements._elements = elements; |
|
reglElements.subdata = function (data, offset) { |
|
buffer.subdata(data, offset); |
|
return reglElements |
|
}; |
|
reglElements.destroy = function () { |
|
destroyElements(elements); |
|
}; |
|
|
|
return reglElements |
|
} |
|
|
|
return { |
|
create: createElements, |
|
createStream: createElementStream, |
|
destroyStream: destroyElementStream, |
|
getElements: function (elements) { |
|
if (typeof elements === 'function' && |
|
elements._elements instanceof REGLElementBuffer) { |
|
return elements._elements |
|
} |
|
return null |
|
}, |
|
clear: function () { |
|
values(elementSet).forEach(destroyElements); |
|
} |
|
} |
|
} |
|
|
|
var FLOAT = new Float32Array(1); |
|
var INT = new Uint32Array(FLOAT.buffer); |
|
|
|
var GL_UNSIGNED_SHORT$4 = 5123; |
|
|
|
function convertToHalfFloat (array) { |
|
var ushorts = pool.allocType(GL_UNSIGNED_SHORT$4, array.length); |
|
|
|
for (var i = 0; i < array.length; ++i) { |
|
if (isNaN(array[i])) { |
|
ushorts[i] = 0xffff; |
|
} else if (array[i] === Infinity) { |
|
ushorts[i] = 0x7c00; |
|
} else if (array[i] === -Infinity) { |
|
ushorts[i] = 0xfc00; |
|
} else { |
|
FLOAT[0] = array[i]; |
|
var x = INT[0]; |
|
|
|
var sgn = (x >>> 31) << 15; |
|
var exp = ((x << 1) >>> 24) - 127; |
|
var frac = (x >> 13) & ((1 << 10) - 1); |
|
|
|
if (exp < -24) { |
|
// round non-representable denormals to 0 |
|
ushorts[i] = sgn; |
|
} else if (exp < -14) { |
|
// handle denormals |
|
var s = -14 - exp; |
|
ushorts[i] = sgn + ((frac + (1 << 10)) >> s); |
|
} else if (exp > 15) { |
|
// round overflow to +/- Infinity |
|
ushorts[i] = sgn + 0x7c00; |
|
} else { |
|
// otherwise convert directly |
|
ushorts[i] = sgn + ((exp + 15) << 10) + frac; |
|
} |
|
} |
|
} |
|
|
|
return ushorts |
|
} |
|
|
|
function isArrayLike (s) { |
|
return Array.isArray(s) || isTypedArray(s) |
|
} |
|
|
|
var GL_COMPRESSED_TEXTURE_FORMATS = 0x86A3; |
|
|
|
var GL_TEXTURE_2D = 0x0DE1; |
|
var GL_TEXTURE_CUBE_MAP = 0x8513; |
|
var GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515; |
|
|
|
var GL_RGBA = 0x1908; |
|
var GL_ALPHA = 0x1906; |
|
var GL_RGB = 0x1907; |
|
var GL_LUMINANCE = 0x1909; |
|
var GL_LUMINANCE_ALPHA = 0x190A; |
|
|
|
var GL_RGBA4 = 0x8056; |
|
var GL_RGB5_A1 = 0x8057; |
|
var GL_RGB565 = 0x8D62; |
|
|
|
var GL_UNSIGNED_SHORT_4_4_4_4$1 = 0x8033; |
|
var GL_UNSIGNED_SHORT_5_5_5_1$1 = 0x8034; |
|
var GL_UNSIGNED_SHORT_5_6_5$1 = 0x8363; |
|
var GL_UNSIGNED_INT_24_8_WEBGL$1 = 0x84FA; |
|
|
|
var GL_DEPTH_COMPONENT = 0x1902; |
|
var GL_DEPTH_STENCIL = 0x84F9; |
|
|
|
var GL_SRGB_EXT = 0x8C40; |
|
var GL_SRGB_ALPHA_EXT = 0x8C42; |
|
|
|
var GL_HALF_FLOAT_OES$1 = 0x8D61; |
|
|
|
var GL_COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0; |
|
var GL_COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1; |
|
var GL_COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2; |
|
var GL_COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3; |
|
|
|
var GL_COMPRESSED_RGB_ATC_WEBGL = 0x8C92; |
|
var GL_COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL = 0x8C93; |
|
var GL_COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL = 0x87EE; |
|
|
|
var GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00; |
|
var GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG = 0x8C01; |
|
var GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02; |
|
var GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG = 0x8C03; |
|
|
|
var GL_COMPRESSED_RGB_ETC1_WEBGL = 0x8D64; |
|
|
|
var GL_UNSIGNED_BYTE$4 = 0x1401; |
|
var GL_UNSIGNED_SHORT$3 = 0x1403; |
|
var GL_UNSIGNED_INT$3 = 0x1405; |
|
var GL_FLOAT$3 = 0x1406; |
|
|
|
var GL_TEXTURE_WRAP_S = 0x2802; |
|
var GL_TEXTURE_WRAP_T = 0x2803; |
|
|
|
var GL_REPEAT = 0x2901; |
|
var GL_CLAMP_TO_EDGE$1 = 0x812F; |
|
var GL_MIRRORED_REPEAT = 0x8370; |
|
|
|
var GL_TEXTURE_MAG_FILTER = 0x2800; |
|
var GL_TEXTURE_MIN_FILTER = 0x2801; |
|
|
|
var GL_NEAREST$1 = 0x2600; |
|
var GL_LINEAR = 0x2601; |
|
var GL_NEAREST_MIPMAP_NEAREST$1 = 0x2700; |
|
var GL_LINEAR_MIPMAP_NEAREST$1 = 0x2701; |
|
var GL_NEAREST_MIPMAP_LINEAR$1 = 0x2702; |
|
var GL_LINEAR_MIPMAP_LINEAR$1 = 0x2703; |
|
|
|
var GL_GENERATE_MIPMAP_HINT = 0x8192; |
|
var GL_DONT_CARE = 0x1100; |
|
var GL_FASTEST = 0x1101; |
|
var GL_NICEST = 0x1102; |
|
|
|
var GL_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE; |
|
|
|
var GL_UNPACK_ALIGNMENT = 0x0CF5; |
|
var GL_UNPACK_FLIP_Y_WEBGL = 0x9240; |
|
var GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241; |
|
var GL_UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243; |
|
|
|
var GL_BROWSER_DEFAULT_WEBGL = 0x9244; |
|
|
|
var GL_TEXTURE0 = 0x84C0; |
|
|
|
var MIPMAP_FILTERS = [ |
|
GL_NEAREST_MIPMAP_NEAREST$1, |
|
GL_NEAREST_MIPMAP_LINEAR$1, |
|
GL_LINEAR_MIPMAP_NEAREST$1, |
|
GL_LINEAR_MIPMAP_LINEAR$1 |
|
]; |
|
|
|
var CHANNELS_FORMAT = [ |
|
0, |
|
GL_LUMINANCE, |
|
GL_LUMINANCE_ALPHA, |
|
GL_RGB, |
|
GL_RGBA |
|
]; |
|
|
|
var FORMAT_CHANNELS = {}; |
|
FORMAT_CHANNELS[GL_LUMINANCE] = |
|
FORMAT_CHANNELS[GL_ALPHA] = |
|
FORMAT_CHANNELS[GL_DEPTH_COMPONENT] = 1; |
|
FORMAT_CHANNELS[GL_DEPTH_STENCIL] = |
|
FORMAT_CHANNELS[GL_LUMINANCE_ALPHA] = 2; |
|
FORMAT_CHANNELS[GL_RGB] = |
|
FORMAT_CHANNELS[GL_SRGB_EXT] = 3; |
|
FORMAT_CHANNELS[GL_RGBA] = |
|
FORMAT_CHANNELS[GL_SRGB_ALPHA_EXT] = 4; |
|
|
|
function objectName (str) { |
|
return '[object ' + str + ']' |
|
} |
|
|
|
var CANVAS_CLASS = objectName('HTMLCanvasElement'); |
|
var CONTEXT2D_CLASS = objectName('CanvasRenderingContext2D'); |
|
var IMAGE_CLASS = objectName('HTMLImageElement'); |
|
var VIDEO_CLASS = objectName('HTMLVideoElement'); |
|
|
|
var PIXEL_CLASSES = Object.keys(arrayTypes).concat([ |
|
CANVAS_CLASS, |
|
CONTEXT2D_CLASS, |
|
IMAGE_CLASS, |
|
VIDEO_CLASS |
|
]); |
|
|
|
// for every texture type, store |
|
// the size in bytes. |
|
var TYPE_SIZES = []; |
|
TYPE_SIZES[GL_UNSIGNED_BYTE$4] = 1; |
|
TYPE_SIZES[GL_FLOAT$3] = 4; |
|
TYPE_SIZES[GL_HALF_FLOAT_OES$1] = 2; |
|
|
|
TYPE_SIZES[GL_UNSIGNED_SHORT$3] = 2; |
|
TYPE_SIZES[GL_UNSIGNED_INT$3] = 4; |
|
|
|
var FORMAT_SIZES_SPECIAL = []; |
|
FORMAT_SIZES_SPECIAL[GL_RGBA4] = 2; |
|
FORMAT_SIZES_SPECIAL[GL_RGB5_A1] = 2; |
|
FORMAT_SIZES_SPECIAL[GL_RGB565] = 2; |
|
FORMAT_SIZES_SPECIAL[GL_DEPTH_STENCIL] = 4; |
|
|
|
FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_S3TC_DXT1_EXT] = 0.5; |
|
FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_S3TC_DXT1_EXT] = 0.5; |
|
FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_S3TC_DXT3_EXT] = 1; |
|
FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_S3TC_DXT5_EXT] = 1; |
|
|
|
FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_ATC_WEBGL] = 0.5; |
|
FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL] = 1; |
|
FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL] = 1; |
|
|
|
FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG] = 0.5; |
|
FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG] = 0.25; |
|
FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG] = 0.5; |
|
FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG] = 0.25; |
|
|
|
FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_ETC1_WEBGL] = 0.5; |
|
|
|
function isNumericArray (arr) { |
|
return ( |
|
Array.isArray(arr) && |
|
(arr.length === 0 || |
|
typeof arr[0] === 'number')) |
|
} |
|
|
|
function isRectArray (arr) { |
|
if (!Array.isArray(arr)) { |
|
return false |
|
} |
|
var width = arr.length; |
|
if (width === 0 || !isArrayLike(arr[0])) { |
|
return false |
|
} |
|
return true |
|
} |
|
|
|
function classString (x) { |
|
return Object.prototype.toString.call(x) |
|
} |
|
|
|
function isCanvasElement (object) { |
|
return classString(object) === CANVAS_CLASS |
|
} |
|
|
|
function isContext2D (object) { |
|
return classString(object) === CONTEXT2D_CLASS |
|
} |
|
|
|
function isImageElement (object) { |
|
return classString(object) === IMAGE_CLASS |
|
} |
|
|
|
function isVideoElement (object) { |
|
return classString(object) === VIDEO_CLASS |
|
} |
|
|
|
function isPixelData (object) { |
|
if (!object) { |
|
return false |
|
} |
|
var className = classString(object); |
|
if (PIXEL_CLASSES.indexOf(className) >= 0) { |
|
return true |
|
} |
|
return ( |
|
isNumericArray(object) || |
|
isRectArray(object) || |
|
isNDArrayLike(object)) |
|
} |
|
|
|
function typedArrayCode$1 (data) { |
|
return arrayTypes[Object.prototype.toString.call(data)] | 0 |
|
} |
|
|
|
function convertData (result, data) { |
|
var n = data.length; |
|
switch (result.type) { |
|
case GL_UNSIGNED_BYTE$4: |
|
case GL_UNSIGNED_SHORT$3: |
|
case GL_UNSIGNED_INT$3: |
|
case GL_FLOAT$3: |
|
var converted = pool.allocType(result.type, n); |
|
converted.set(data); |
|
result.data = converted; |
|
break |
|
|
|
case GL_HALF_FLOAT_OES$1: |
|
result.data = convertToHalfFloat(data); |
|
break |
|
|
|
default: |
|
check$1.raise('unsupported texture type, must specify a typed array'); |
|
} |
|
} |
|
|
|
function preConvert (image, n) { |
|
return pool.allocType( |
|
image.type === GL_HALF_FLOAT_OES$1 |
|
? GL_FLOAT$3 |
|
: image.type, n) |
|
} |
|
|
|
function postConvert (image, data) { |
|
if (image.type === GL_HALF_FLOAT_OES$1) { |
|
image.data = convertToHalfFloat(data); |
|
pool.freeType(data); |
|
} else { |
|
image.data = data; |
|
} |
|
} |
|
|
|
function transposeData (image, array, strideX, strideY, strideC, offset) { |
|
var w = image.width; |
|
var h = image.height; |
|
var c = image.channels; |
|
var n = w * h * c; |
|
var data = preConvert(image, n); |
|
|
|
var p = 0; |
|
for (var i = 0; i < h; ++i) { |
|
for (var j = 0; j < w; ++j) { |
|
for (var k = 0; k < c; ++k) { |
|
data[p++] = array[strideX * j + strideY * i + strideC * k + offset]; |
|
} |
|
} |
|
} |
|
|
|
postConvert(image, data); |
|
} |
|
|
|
function getTextureSize (format, type, width, height, isMipmap, isCube) { |
|
var s; |
|
if (typeof FORMAT_SIZES_SPECIAL[format] !== 'undefined') { |
|
// we have a special array for dealing with weird color formats such as RGB5A1 |
|
s = FORMAT_SIZES_SPECIAL[format]; |
|
} else { |
|
s = FORMAT_CHANNELS[format] * TYPE_SIZES[type]; |
|
} |
|
|
|
if (isCube) { |
|
s *= 6; |
|
} |
|
|
|
if (isMipmap) { |
|
// compute the total size of all the mipmaps. |
|
var total = 0; |
|
|
|
var w = width; |
|
while (w >= 1) { |
|
// we can only use mipmaps on a square image, |
|
// so we can simply use the width and ignore the height: |
|
total += s * w * w; |
|
w /= 2; |
|
} |
|
return total |
|
} else { |
|
return s * width * height |
|
} |
|
} |
|
|
|
function createTextureSet ( |
|
gl, extensions, limits, reglPoll, contextState, stats, config) { |
|
// ------------------------------------------------------- |
|
// Initialize constants and parameter tables here |
|
// ------------------------------------------------------- |
|
var mipmapHint = { |
|
"don't care": GL_DONT_CARE, |
|
'dont care': GL_DONT_CARE, |
|
'nice': GL_NICEST, |
|
'fast': GL_FASTEST |
|
}; |
|
|
|
var wrapModes = { |
|
'repeat': GL_REPEAT, |
|
'clamp': GL_CLAMP_TO_EDGE$1, |
|
'mirror': GL_MIRRORED_REPEAT |
|
}; |
|
|
|
var magFilters = { |
|
'nearest': GL_NEAREST$1, |
|
'linear': GL_LINEAR |
|
}; |
|
|
|
var minFilters = extend({ |
|
'mipmap': GL_LINEAR_MIPMAP_LINEAR$1, |
|
'nearest mipmap nearest': GL_NEAREST_MIPMAP_NEAREST$1, |
|
'linear mipmap nearest': GL_LINEAR_MIPMAP_NEAREST$1, |
|
'nearest mipmap linear': GL_NEAREST_MIPMAP_LINEAR$1, |
|
'linear mipmap linear': GL_LINEAR_MIPMAP_LINEAR$1 |
|
}, magFilters); |
|
|
|
var colorSpace = { |
|
'none': 0, |
|
'browser': GL_BROWSER_DEFAULT_WEBGL |
|
}; |
|
|
|
var textureTypes = { |
|
'uint8': GL_UNSIGNED_BYTE$4, |
|
'rgba4': GL_UNSIGNED_SHORT_4_4_4_4$1, |
|
'rgb565': GL_UNSIGNED_SHORT_5_6_5$1, |
|
'rgb5 a1': GL_UNSIGNED_SHORT_5_5_5_1$1 |
|
}; |
|
|
|
var textureFormats = { |
|
'alpha': GL_ALPHA, |
|
'luminance': GL_LUMINANCE, |
|
'luminance alpha': GL_LUMINANCE_ALPHA, |
|
'rgb': GL_RGB, |
|
'rgba': GL_RGBA, |
|
'rgba4': GL_RGBA4, |
|
'rgb5 a1': GL_RGB5_A1, |
|
'rgb565': GL_RGB565 |
|
}; |
|
|
|
var compressedTextureFormats = {}; |
|
|
|
if (extensions.ext_srgb) { |
|
textureFormats.srgb = GL_SRGB_EXT; |
|
textureFormats.srgba = GL_SRGB_ALPHA_EXT; |
|
} |
|
|
|
if (extensions.oes_texture_float) { |
|
textureTypes.float32 = textureTypes.float = GL_FLOAT$3; |
|
} |
|
|
|
if (extensions.oes_texture_half_float) { |
|
textureTypes['float16'] = textureTypes['half float'] = GL_HALF_FLOAT_OES$1; |
|
} |
|
|
|
if (extensions.webgl_depth_texture) { |
|
extend(textureFormats, { |
|
'depth': GL_DEPTH_COMPONENT, |
|
'depth stencil': GL_DEPTH_STENCIL |
|
}); |
|
|
|
extend(textureTypes, { |
|
'uint16': GL_UNSIGNED_SHORT$3, |
|
'uint32': GL_UNSIGNED_INT$3, |
|
'depth stencil': GL_UNSIGNED_INT_24_8_WEBGL$1 |
|
}); |
|
} |
|
|
|
if (extensions.webgl_compressed_texture_s3tc) { |
|
extend(compressedTextureFormats, { |
|
'rgb s3tc dxt1': GL_COMPRESSED_RGB_S3TC_DXT1_EXT, |
|
'rgba s3tc dxt1': GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, |
|
'rgba s3tc dxt3': GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, |
|
'rgba s3tc dxt5': GL_COMPRESSED_RGBA_S3TC_DXT5_EXT |
|
}); |
|
} |
|
|
|
if (extensions.webgl_compressed_texture_atc) { |
|
extend(compressedTextureFormats, { |
|
'rgb atc': GL_COMPRESSED_RGB_ATC_WEBGL, |
|
'rgba atc explicit alpha': GL_COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL, |
|
'rgba atc interpolated alpha': GL_COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL |
|
}); |
|
} |
|
|
|
if (extensions.webgl_compressed_texture_pvrtc) { |
|
extend(compressedTextureFormats, { |
|
'rgb pvrtc 4bppv1': GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG, |
|
'rgb pvrtc 2bppv1': GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG, |
|
'rgba pvrtc 4bppv1': GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, |
|
'rgba pvrtc 2bppv1': GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG |
|
}); |
|
} |
|
|
|
if (extensions.webgl_compressed_texture_etc1) { |
|
compressedTextureFormats['rgb etc1'] = GL_COMPRESSED_RGB_ETC1_WEBGL; |
|
} |
|
|
|
// Copy over all texture formats |
|
var supportedCompressedFormats = Array.prototype.slice.call( |
|
gl.getParameter(GL_COMPRESSED_TEXTURE_FORMATS)); |
|
Object.keys(compressedTextureFormats).forEach(function (name) { |
|
var format = compressedTextureFormats[name]; |
|
if (supportedCompressedFormats.indexOf(format) >= 0) { |
|
textureFormats[name] = format; |
|
} |
|
}); |
|
|
|
var supportedFormats = Object.keys(textureFormats); |
|
limits.textureFormats = supportedFormats; |
|
|
|
// associate with every format string its |
|
// corresponding GL-value. |
|
var textureFormatsInvert = []; |
|
Object.keys(textureFormats).forEach(function (key) { |
|
var val = textureFormats[key]; |
|
textureFormatsInvert[val] = key; |
|
}); |
|
|
|
// associate with every type string its |
|
// corresponding GL-value. |
|
var textureTypesInvert = []; |
|
Object.keys(textureTypes).forEach(function (key) { |
|
var val = textureTypes[key]; |
|
textureTypesInvert[val] = key; |
|
}); |
|
|
|
var magFiltersInvert = []; |
|
Object.keys(magFilters).forEach(function (key) { |
|
var val = magFilters[key]; |
|
magFiltersInvert[val] = key; |
|
}); |
|
|
|
var minFiltersInvert = []; |
|
Object.keys(minFilters).forEach(function (key) { |
|
var val = minFilters[key]; |
|
minFiltersInvert[val] = key; |
|
}); |
|
|
|
var wrapModesInvert = []; |
|
Object.keys(wrapModes).forEach(function (key) { |
|
var val = wrapModes[key]; |
|
wrapModesInvert[val] = key; |
|
}); |
|
|
|
// colorFormats[] gives the format (channels) associated to an |
|
// internalformat |
|
var colorFormats = supportedFormats.reduce(function (color, key) { |
|
var glenum = textureFormats[key]; |
|
if (glenum === GL_LUMINANCE || |
|
glenum === GL_ALPHA || |
|
glenum === GL_LUMINANCE || |
|
glenum === GL_LUMINANCE_ALPHA || |
|
glenum === GL_DEPTH_COMPONENT || |
|
glenum === GL_DEPTH_STENCIL) { |
|
color[glenum] = glenum; |
|
} else if (glenum === GL_RGB5_A1 || key.indexOf('rgba') >= 0) { |
|
color[glenum] = GL_RGBA; |
|
} else { |
|
color[glenum] = GL_RGB; |
|
} |
|
return color |
|
}, {}); |
|
|
|
function TexFlags () { |
|
// format info |
|
this.internalformat = GL_RGBA; |
|
this.format = GL_RGBA; |
|
this.type = GL_UNSIGNED_BYTE$4; |
|
this.compressed = false; |
|
|
|
// pixel storage |
|
this.premultiplyAlpha = false; |
|
this.flipY = false; |
|
this.unpackAlignment = 1; |
|
this.colorSpace = 0; |
|
|
|
// shape info |
|
this.width = 0; |
|
this.height = 0; |
|
this.channels = 0; |
|
} |
|
|
|
function copyFlags (result, other) { |
|
result.internalformat = other.internalformat; |
|
result.format = other.format; |
|
result.type = other.type; |
|
result.compressed = other.compressed; |
|
|
|
result.premultiplyAlpha = other.premultiplyAlpha; |
|
result.flipY = other.flipY; |
|
result.unpackAlignment = other.unpackAlignment; |
|
result.colorSpace = other.colorSpace; |
|
|
|
result.width = other.width; |
|
result.height = other.height; |
|
result.channels = other.channels; |
|
} |
|
|
|
function parseFlags (flags, options) { |
|
if (typeof options !== 'object' || !options) { |
|
return |
|
} |
|
|
|
if ('premultiplyAlpha' in options) { |
|
check$1.type(options.premultiplyAlpha, 'boolean', |
|
'invalid premultiplyAlpha'); |
|
flags.premultiplyAlpha = options.premultiplyAlpha; |
|
} |
|
|
|
if ('flipY' in options) { |
|
check$1.type(options.flipY, 'boolean', |
|
'invalid texture flip'); |
|
flags.flipY = options.flipY; |
|
} |
|
|
|
if ('alignment' in options) { |
|
check$1.oneOf(options.alignment, [1, 2, 4, 8], |
|
'invalid texture unpack alignment'); |
|
flags.unpackAlignment = options.alignment; |
|
} |
|
|
|
if ('colorSpace' in options) { |
|
check$1.parameter(options.colorSpace, colorSpace, |
|
'invalid colorSpace'); |
|
flags.colorSpace = colorSpace[options.colorSpace]; |
|
} |
|
|
|
if ('type' in options) { |
|
var type = options.type; |
|
check$1(extensions.oes_texture_float || |
|
!(type === 'float' || type === 'float32'), |
|
'you must enable the OES_texture_float extension in order to use floating point textures.'); |
|
check$1(extensions.oes_texture_half_float || |
|
!(type === 'half float' || type === 'float16'), |
|
'you must enable the OES_texture_half_float extension in order to use 16-bit floating point textures.'); |
|
check$1(extensions.webgl_depth_texture || |
|
!(type === 'uint16' || type === 'uint32' || type === 'depth stencil'), |
|
'you must enable the WEBGL_depth_texture extension in order to use depth/stencil textures.'); |
|
check$1.parameter(type, textureTypes, |
|
'invalid texture type'); |
|
flags.type = textureTypes[type]; |
|
} |
|
|
|
var w = flags.width; |
|
var h = flags.height; |
|
var c = flags.channels; |
|
var hasChannels = false; |
|
if ('shape' in options) { |
|
check$1(Array.isArray(options.shape) && options.shape.length >= 2, |
|
'shape must be an array'); |
|
w = options.shape[0]; |
|
h = options.shape[1]; |
|
if (options.shape.length === 3) { |
|
c = options.shape[2]; |
|
check$1(c > 0 && c <= 4, 'invalid number of channels'); |
|
hasChannels = true; |
|
} |
|
check$1(w >= 0 && w <= limits.maxTextureSize, 'invalid width'); |
|
check$1(h >= 0 && h <= limits.maxTextureSize, 'invalid height'); |
|
} else { |
|
if ('radius' in options) { |
|
w = h = options.radius; |
|
check$1(w >= 0 && w <= limits.maxTextureSize, 'invalid radius'); |
|
} |
|
if ('width' in options) { |
|
w = options.width; |
|
check$1(w >= 0 && w <= limits.maxTextureSize, 'invalid width'); |
|
} |
|
if ('height' in options) { |
|
h = options.height; |
|
check$1(h >= 0 && h <= limits.maxTextureSize, 'invalid height'); |
|
} |
|
if ('channels' in options) { |
|
c = options.channels; |
|
check$1(c > 0 && c <= 4, 'invalid number of channels'); |
|
hasChannels = true; |
|
} |
|
} |
|
flags.width = w | 0; |
|
flags.height = h | 0; |
|
flags.channels = c | 0; |
|
|
|
var hasFormat = false; |
|
if ('format' in options) { |
|
var formatStr = options.format; |
|
check$1(extensions.webgl_depth_texture || |
|
!(formatStr === 'depth' || formatStr === 'depth stencil'), |
|
'you must enable the WEBGL_depth_texture extension in order to use depth/stencil textures.'); |
|
check$1.parameter(formatStr, textureFormats, |
|
'invalid texture format'); |
|
var internalformat = flags.internalformat = textureFormats[formatStr]; |
|
flags.format = colorFormats[internalformat]; |
|
if (formatStr in textureTypes) { |
|
if (!('type' in options)) { |
|
flags.type = textureTypes[formatStr]; |
|
} |
|
} |
|
if (formatStr in compressedTextureFormats) { |
|
flags.compressed = true; |
|
} |
|
hasFormat = true; |
|
} |
|
|
|
// Reconcile channels and format |
|
if (!hasChannels && hasFormat) { |
|
flags.channels = FORMAT_CHANNELS[flags.format]; |
|
} else if (hasChannels && !hasFormat) { |
|
if (flags.channels !== CHANNELS_FORMAT[flags.format]) { |
|
flags.format = flags.internalformat = CHANNELS_FORMAT[flags.channels]; |
|
} |
|
} else if (hasFormat && hasChannels) { |
|
check$1( |
|
flags.channels === FORMAT_CHANNELS[flags.format], |
|
'number of channels inconsistent with specified format'); |
|
} |
|
} |
|
|
|
function setFlags (flags) { |
|
gl.pixelStorei(GL_UNPACK_FLIP_Y_WEBGL, flags.flipY); |
|
gl.pixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL, flags.premultiplyAlpha); |
|
gl.pixelStorei(GL_UNPACK_COLORSPACE_CONVERSION_WEBGL, flags.colorSpace); |
|
gl.pixelStorei(GL_UNPACK_ALIGNMENT, flags.unpackAlignment); |
|
} |
|
|
|
// ------------------------------------------------------- |
|
// Tex image data |
|
// ------------------------------------------------------- |
|
function TexImage () { |
|
TexFlags.call(this); |
|
|
|
this.xOffset = 0; |
|
this.yOffset = 0; |
|
|
|
// data |
|
this.data = null; |
|
this.needsFree = false; |
|
|
|
// html element |
|
this.element = null; |
|
|
|
// copyTexImage info |
|
this.needsCopy = false; |
|
} |
|
|
|
function parseImage (image, options) { |
|
var data = null; |
|
if (isPixelData(options)) { |
|
data = options; |
|
} else if (options) { |
|
check$1.type(options, 'object', 'invalid pixel data type'); |
|
parseFlags(image, options); |
|
if ('x' in options) { |
|
image.xOffset = options.x | 0; |
|
} |
|
if ('y' in options) { |
|
image.yOffset = options.y | 0; |
|
} |
|
if (isPixelData(options.data)) { |
|
data = options.data; |
|
} |
|
} |
|
|
|
check$1( |
|
!image.compressed || |
|
data instanceof Uint8Array, |
|
'compressed texture data must be stored in a uint8array'); |
|
|
|
if (options.copy) { |
|
check$1(!data, 'can not specify copy and data field for the same texture'); |
|
var viewW = contextState.viewportWidth; |
|
var viewH = contextState.viewportHeight; |
|
image.width = image.width || (viewW - image.xOffset); |
|
image.height = image.height || (viewH - image.yOffset); |
|
image.needsCopy = true; |
|
check$1(image.xOffset >= 0 && image.xOffset < viewW && |
|
image.yOffset >= 0 && image.yOffset < viewH && |
|
image.width > 0 && image.width <= viewW && |
|
image.height > 0 && image.height <= viewH, |
|
'copy texture read out of bounds'); |
|
} else if (!data) { |
|
image.width = image.width || 1; |
|
image.height = image.height || 1; |
|
image.channels = image.channels || 4; |
|
} else if (isTypedArray(data)) { |
|
image.channels = image.channels || 4; |
|
image.data = data; |
|
if (!('type' in options) && image.type === GL_UNSIGNED_BYTE$4) { |
|
image.type = typedArrayCode$1(data); |
|
} |
|
} else if (isNumericArray(data)) { |
|
image.channels = image.channels || 4; |
|
convertData(image, data); |
|
image.alignment = 1; |
|
image.needsFree = true; |
|
} else if (isNDArrayLike(data)) { |
|
var array = data.data; |
|
if (!Array.isArray(array) && image.type === GL_UNSIGNED_BYTE$4) { |
|
image.type = typedArrayCode$1(array); |
|
} |
|
var shape = data.shape; |
|
var stride = data.stride; |
|
var shapeX, shapeY, shapeC, strideX, strideY, strideC; |
|
if (shape.length === 3) { |
|
shapeC = shape[2]; |
|
strideC = stride[2]; |
|
} else { |
|
check$1(shape.length === 2, 'invalid ndarray pixel data, must be 2 or 3D'); |
|
shapeC = 1; |
|
strideC = 1; |
|
} |
|
shapeX = shape[0]; |
|
shapeY = shape[1]; |
|
strideX = stride[0]; |
|
strideY = stride[1]; |
|
image.alignment = 1; |
|
image.width = shapeX; |
|
image.height = shapeY; |
|
image.channels = shapeC; |
|
image.format = image.internalformat = CHANNELS_FORMAT[shapeC]; |
|
image.needsFree = true; |
|
transposeData(image, array, strideX, strideY, strideC, data.offset); |
|
} else if (isCanvasElement(data) || isContext2D(data)) { |
|
if (isCanvasElement(data)) { |
|
image.element = data; |
|
} else { |
|
image.element = data.canvas; |
|
} |
|
image.width = image.element.width; |
|
image.height = image.element.height; |
|
image.channels = 4; |
|
} else if (isImageElement(data)) { |
|
image.element = data; |
|
image.width = data.naturalWidth; |
|
image.height = data.naturalHeight; |
|
image.channels = 4; |
|
} else if (isVideoElement(data)) { |
|
image.element = data; |
|
image.width = data.videoWidth; |
|
image.height = data.videoHeight; |
|
image.channels = 4; |
|
} else if (isRectArray(data)) { |
|
var w = image.width || data[0].length; |
|
var h = image.height || data.length; |
|
var c = image.channels; |
|
if (isArrayLike(data[0][0])) { |
|
c = c || data[0][0].length; |
|
} else { |
|
c = c || 1; |
|
} |
|
var arrayShape = flattenUtils.shape(data); |
|
var n = 1; |
|
for (var dd = 0; dd < arrayShape.length; ++dd) { |
|
n *= arrayShape[dd]; |
|
} |
|
var allocData = preConvert(image, n); |
|
flattenUtils.flatten(data, arrayShape, '', allocData); |
|
postConvert(image, allocData); |
|
image.alignment = 1; |
|
image.width = w; |
|
image.height = h; |
|
image.channels = c; |
|
image.format = image.internalformat = CHANNELS_FORMAT[c]; |
|
image.needsFree = true; |
|
} |
|
|
|
if (image.type === GL_FLOAT$3) { |
|
check$1(limits.extensions.indexOf('oes_texture_float') >= 0, |
|
'oes_texture_float extension not enabled'); |
|
} else if (image.type === GL_HALF_FLOAT_OES$1) { |
|
check$1(limits.extensions.indexOf('oes_texture_half_float') >= 0, |
|
'oes_texture_half_float extension not enabled'); |
|
} |
|
|
|
// do compressed texture validation here. |
|
} |
|
|
|
function setImage (info, target, miplevel) { |
|
var element = info.element; |
|
var data = info.data; |
|
var internalformat = info.internalformat; |
|
var format = info.format; |
|
var type = info.type; |
|
var width = info.width; |
|
var height = info.height; |
|
|
|
setFlags(info); |
|
|
|
if (element) { |
|
gl.texImage2D(target, miplevel, format, format, type, element); |
|
} else if (info.compressed) { |
|
gl.compressedTexImage2D(target, miplevel, internalformat, width, height, 0, data); |
|
} else if (info.needsCopy) { |
|
reglPoll(); |
|
gl.copyTexImage2D( |
|
target, miplevel, format, info.xOffset, info.yOffset, width, height, 0); |
|
} else { |
|
gl.texImage2D( |
|
target, miplevel, format, width, height, 0, format, type, data); |
|
} |
|
} |
|
|
|
function setSubImage (info, target, x, y, miplevel) { |
|
var element = info.element; |
|
var data = info.data; |
|
var internalformat = info.internalformat; |
|
var format = info.format; |
|
var type = info.type; |
|
var width = info.width; |
|
var height = info.height; |
|
|
|
setFlags(info); |
|
|
|
if (element) { |
|
gl.texSubImage2D( |
|
target, miplevel, x, y, format, type, element); |
|
} else if (info.compressed) { |
|
gl.compressedTexSubImage2D( |
|
target, miplevel, x, y, internalformat, width, height, data); |
|
} else if (info.needsCopy) { |
|
reglPoll(); |
|
gl.copyTexSubImage2D( |
|
target, miplevel, x, y, info.xOffset, info.yOffset, width, height); |
|
} else { |
|
gl.texSubImage2D( |
|
target, miplevel, x, y, width, height, format, type, data); |
|
} |
|
} |
|
|
|
// texImage pool |
|
var imagePool = []; |
|
|
|
function allocImage () { |
|
return imagePool.pop() || new TexImage() |
|
} |
|
|
|
function freeImage (image) { |
|
if (image.needsFree) { |
|
pool.freeType(image.data); |
|
} |
|
TexImage.call(image); |
|
imagePool.push(image); |
|
} |
|
|
|
// ------------------------------------------------------- |
|
// Mip map |
|
// ------------------------------------------------------- |
|
function MipMap () { |
|
TexFlags.call(this); |
|
|
|
this.genMipmaps = false; |
|
this.mipmapHint = GL_DONT_CARE; |
|
this.mipmask = 0; |
|
this.images = Array(16); |
|
} |
|
|
|
function parseMipMapFromShape (mipmap, width, height) { |
|
var img = mipmap.images[0] = allocImage(); |
|
mipmap.mipmask = 1; |
|
img.width = mipmap.width = width; |
|
img.height = mipmap.height = height; |
|
img.channels = mipmap.channels = 4; |
|
} |
|
|
|
function parseMipMapFromObject (mipmap, options) { |
|
var imgData = null; |
|
if (isPixelData(options)) { |
|
imgData = mipmap.images[0] = allocImage(); |
|
copyFlags(imgData, mipmap); |
|
parseImage(imgData, options); |
|
mipmap.mipmask = 1; |
|
} else { |
|
parseFlags(mipmap, options); |
|
if (Array.isArray(options.mipmap)) { |
|
var mipData = options.mipmap; |
|
for (var i = 0; i < mipData.length; ++i) { |
|
imgData = mipmap.images[i] = allocImage(); |
|
copyFlags(imgData, mipmap); |
|
imgData.width >>= i; |
|
imgData.height >>= i; |
|
parseImage(imgData, mipData[i]); |
|
mipmap.mipmask |= (1 << i); |
|
} |
|
} else { |
|
imgData = mipmap.images[0] = allocImage(); |
|
copyFlags(imgData, mipmap); |
|
parseImage(imgData, options); |
|
mipmap.mipmask = 1; |
|
} |
|
} |
|
copyFlags(mipmap, mipmap.images[0]); |
|
|
|
// For textures of the compressed format WEBGL_compressed_texture_s3tc |
|
// we must have that |
|
// |
|
// "When level equals zero width and height must be a multiple of 4. |
|
// When level is greater than 0 width and height must be 0, 1, 2 or a multiple of 4. " |
|
// |
|
// but we do not yet support having multiple mipmap levels for compressed textures, |
|
// so we only test for level zero. |
|
|
|
if (mipmap.compressed && |
|
(mipmap.internalformat === GL_COMPRESSED_RGB_S3TC_DXT1_EXT) || |
|
(mipmap.internalformat === GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) || |
|
(mipmap.internalformat === GL_COMPRESSED_RGBA_S3TC_DXT3_EXT) || |
|
(mipmap.internalformat === GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)) { |
|
check$1(mipmap.width % 4 === 0 && |
|
mipmap.height % 4 === 0, |
|
'for compressed texture formats, mipmap level 0 must have width and height that are a multiple of 4'); |
|
} |
|
} |
|
|
|
function setMipMap (mipmap, target) { |
|
var images = mipmap.images; |
|
for (var i = 0; i < images.length; ++i) { |
|
if (!images[i]) { |
|
return |
|
} |
|
setImage(images[i], target, i); |
|
} |
|
} |
|
|
|
var mipPool = []; |
|
|
|
function allocMipMap () { |
|
var result = mipPool.pop() || new MipMap(); |
|
TexFlags.call(result); |
|
result.mipmask = 0; |
|
for (var i = 0; i < 16; ++i) { |
|
result.images[i] = null; |
|
} |
|
return result |
|
} |
|
|
|
function freeMipMap (mipmap) { |
|
var images = mipmap.images; |
|
for (var i = 0; i < images.length; ++i) { |
|
if (images[i]) { |
|
freeImage(images[i]); |
|
} |
|
images[i] = null; |
|
} |
|
mipPool.push(mipmap); |
|
} |
|
|
|
// ------------------------------------------------------- |
|
// Tex info |
|
// ------------------------------------------------------- |
|
function TexInfo () { |
|
this.minFilter = GL_NEAREST$1; |
|
this.magFilter = GL_NEAREST$1; |
|
|
|
this.wrapS = GL_CLAMP_TO_EDGE$1; |
|
this.wrapT = GL_CLAMP_TO_EDGE$1; |
|
|
|
this.anisotropic = 1; |
|
|
|
this.genMipmaps = false; |
|
this.mipmapHint = GL_DONT_CARE; |
|
} |
|
|
|
function parseTexInfo (info, options) { |
|
if ('min' in options) { |
|
var minFilter = options.min; |
|
check$1.parameter(minFilter, minFilters); |
|
info.minFilter = minFilters[minFilter]; |
|
if (MIPMAP_FILTERS.indexOf(info.minFilter) >= 0) { |
|
info.genMipmaps = true; |
|
} |
|
} |
|
|
|
if ('mag' in options) { |
|
var magFilter = options.mag; |
|
check$1.parameter(magFilter, magFilters); |
|
info.magFilter = magFilters[magFilter]; |
|
} |
|
|
|
var wrapS = info.wrapS; |
|
var wrapT = info.wrapT; |
|
if ('wrap' in options) { |
|
var wrap = options.wrap; |
|
if (typeof wrap === 'string') { |
|
check$1.parameter(wrap, wrapModes); |
|
wrapS = wrapT = wrapModes[wrap]; |
|
} else if (Array.isArray(wrap)) { |
|
check$1.parameter(wrap[0], wrapModes); |
|
check$1.parameter(wrap[1], wrapModes); |
|
wrapS = wrapModes[wrap[0]]; |
|
wrapT = wrapModes[wrap[1]]; |
|
} |
|
} else { |
|
if ('wrapS' in options) { |
|
var optWrapS = options.wrapS; |
|
check$1.parameter(optWrapS, wrapModes); |
|
wrapS = wrapModes[optWrapS]; |
|
} |
|
if ('wrapT' in options) { |
|
var optWrapT = options.wrapT; |
|
check$1.parameter(optWrapT, wrapModes); |
|
wrapT = wrapModes[optWrapT]; |
|
} |
|
} |
|
info.wrapS = wrapS; |
|
info.wrapT = wrapT; |
|
|
|
if ('anisotropic' in options) { |
|
var anisotropic = options.anisotropic; |
|
check$1(typeof anisotropic === 'number' && |
|
anisotropic >= 1 && anisotropic <= limits.maxAnisotropic, |
|
'aniso samples must be between 1 and '); |
|
info.anisotropic = options.anisotropic; |
|
} |
|
|
|
if ('mipmap' in options) { |
|
var hasMipMap = false; |
|
switch (typeof options.mipmap) { |
|
case 'string': |
|
check$1.parameter(options.mipmap, mipmapHint, |
|
'invalid mipmap hint'); |
|
info.mipmapHint = mipmapHint[options.mipmap]; |
|
info.genMipmaps = true; |
|
hasMipMap = true; |
|
break |
|
|
|
case 'boolean': |
|
hasMipMap = info.genMipmaps = options.mipmap; |
|
break |
|
|
|
case 'object': |
|
check$1(Array.isArray(options.mipmap), 'invalid mipmap type'); |
|
info.genMipmaps = false; |
|
hasMipMap = true; |
|
break |
|
|
|
default: |
|
check$1.raise('invalid mipmap type'); |
|
} |
|
if (hasMipMap && !('min' in options)) { |
|
info.minFilter = GL_NEAREST_MIPMAP_NEAREST$1; |
|
} |
|
} |
|
} |
|
|
|
function setTexInfo (info, target) { |
|
gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, info.minFilter); |
|
gl.texParameteri(target, GL_TEXTURE_MAG_FILTER, info.magFilter); |
|
gl.texParameteri(target, GL_TEXTURE_WRAP_S, info.wrapS); |
|
gl.texParameteri(target, GL_TEXTURE_WRAP_T, info.wrapT); |
|
if (extensions.ext_texture_filter_anisotropic) { |
|
gl.texParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, info.anisotropic); |
|
} |
|
if (info.genMipmaps) { |
|
gl.hint(GL_GENERATE_MIPMAP_HINT, info.mipmapHint); |
|
gl.generateMipmap(target); |
|
} |
|
} |
|
|
|
// ------------------------------------------------------- |
|
// Full texture object |
|
// ------------------------------------------------------- |
|
var textureCount = 0; |
|
var textureSet = {}; |
|
var numTexUnits = limits.maxTextureUnits; |
|
var textureUnits = Array(numTexUnits).map(function () { |
|
return null |
|
}); |
|
|
|
function REGLTexture (target) { |
|
TexFlags.call(this); |
|
this.mipmask = 0; |
|
this.internalformat = GL_RGBA; |
|
|
|
this.id = textureCount++; |
|
|
|
this.refCount = 1; |
|
|
|
this.target = target; |
|
this.texture = gl.createTexture(); |
|
|
|
this.unit = -1; |
|
this.bindCount = 0; |
|
|
|
this.texInfo = new TexInfo(); |
|
|
|
if (config.profile) { |
|
this.stats = {size: 0}; |
|
} |
|
} |
|
|
|
function tempBind (texture) { |
|
gl.activeTexture(GL_TEXTURE0); |
|
gl.bindTexture(texture.target, texture.texture); |
|
} |
|
|
|
function tempRestore () { |
|
var prev = textureUnits[0]; |
|
if (prev) { |
|
gl.bindTexture(prev.target, prev.texture); |
|
} else { |
|
gl.bindTexture(GL_TEXTURE_2D, null); |
|
} |
|
} |
|
|
|
function destroy (texture) { |
|
var handle = texture.texture; |
|
check$1(handle, 'must not double destroy texture'); |
|
var unit = texture.unit; |
|
var target = texture.target; |
|
if (unit >= 0) { |
|
gl.activeTexture(GL_TEXTURE0 + unit); |
|
gl.bindTexture(target, null); |
|
textureUnits[unit] = null; |
|
} |
|
gl.deleteTexture(handle); |
|
texture.texture = null; |
|
texture.params = null; |
|
texture.pixels = null; |
|
texture.refCount = 0; |
|
delete textureSet[texture.id]; |
|
stats.textureCount--; |
|
} |
|
|
|
extend(REGLTexture.prototype, { |
|
bind: function () { |
|
var texture = this; |
|
texture.bindCount += 1; |
|
var unit = texture.unit; |
|
if (unit < 0) { |
|
for (var i = 0; i < numTexUnits; ++i) { |
|
var other = textureUnits[i]; |
|
if (other) { |
|
if (other.bindCount > 0) { |
|
continue |
|
} |
|
other.unit = -1; |
|
} |
|
textureUnits[i] = texture; |
|
unit = i; |
|
break |
|
} |
|
if (unit >= numTexUnits) { |
|
check$1.raise('insufficient number of texture units'); |
|
} |
|
if (config.profile && stats.maxTextureUnits < (unit + 1)) { |
|
stats.maxTextureUnits = unit + 1; // +1, since the units are zero-based |
|
} |
|
texture.unit = unit; |
|
gl.activeTexture(GL_TEXTURE0 + unit); |
|
gl.bindTexture(texture.target, texture.texture); |
|
} |
|
return unit |
|
}, |
|
|
|
unbind: function () { |
|
this.bindCount -= 1; |
|
}, |
|
|
|
decRef: function () { |
|
if (--this.refCount <= 0) { |
|
destroy(this); |
|
} |
|
} |
|
}); |
|
|
|
function createTexture2D (a, b) { |
|
var texture = new REGLTexture(GL_TEXTURE_2D); |
|
textureSet[texture.id] = texture; |
|
stats.textureCount++; |
|
|
|
function reglTexture2D (a, b) { |
|
var texInfo = texture.texInfo; |
|
TexInfo.call(texInfo); |
|
var mipData = allocMipMap(); |
|
|
|
if (typeof a === 'number') { |
|
if (typeof b === 'number') { |
|
parseMipMapFromShape(mipData, a | 0, b | 0); |
|
} else { |
|
parseMipMapFromShape(mipData, a | 0, a | 0); |
|
} |
|
} else if (a) { |
|
check$1.type(a, 'object', 'invalid arguments to regl.texture'); |
|
parseTexInfo(texInfo, a); |
|
parseMipMapFromObject(mipData, a); |
|
} else { |
|
// empty textures get assigned a default shape of 1x1 |
|
parseMipMapFromShape(mipData, 1, 1); |
|
} |
|
|
|
if (texInfo.genMipmaps) { |
|
mipData.mipmask = (mipData.width << 1) - 1; |
|
} |
|
texture.mipmask = mipData.mipmask; |
|
|
|
copyFlags(texture, mipData); |
|
|
|
check$1.texture2D(texInfo, mipData, limits); |
|
texture.internalformat = mipData.internalformat; |
|
|
|
reglTexture2D.width = mipData.width; |
|
reglTexture2D.height = mipData.height; |
|
|
|
tempBind(texture); |
|
setMipMap(mipData, GL_TEXTURE_2D); |
|
setTexInfo(texInfo, GL_TEXTURE_2D); |
|
tempRestore(); |
|
|
|
freeMipMap(mipData); |
|
|
|
if (config.profile) { |
|
texture.stats.size = getTextureSize( |
|
texture.internalformat, |
|
texture.type, |
|
mipData.width, |
|
mipData.height, |
|
texInfo.genMipmaps, |
|
false); |
|
} |
|
reglTexture2D.format = textureFormatsInvert[texture.internalformat]; |
|
reglTexture2D.type = textureTypesInvert[texture.type]; |
|
|
|
reglTexture2D.mag = magFiltersInvert[texInfo.magFilter]; |
|
reglTexture2D.min = minFiltersInvert[texInfo.minFilter]; |
|
|
|
reglTexture2D.wrapS = wrapModesInvert[texInfo.wrapS]; |
|
reglTexture2D.wrapT = wrapModesInvert[texInfo.wrapT]; |
|
|
|
return reglTexture2D |
|
} |
|
|
|
function subimage (image, x_, y_, level_) { |
|
check$1(!!image, 'must specify image data'); |
|
|
|
var x = x_ | 0; |
|
var y = y_ | 0; |
|
var level = level_ | 0; |
|
|
|
var imageData = allocImage(); |
|
copyFlags(imageData, texture); |
|
imageData.width = 0; |
|
imageData.height = 0; |
|
parseImage(imageData, image); |
|
imageData.width = imageData.width || ((texture.width >> level) - x); |
|
imageData.height = imageData.height || ((texture.height >> level) - y); |
|
|
|
check$1( |
|
texture.type === imageData.type && |
|
texture.format === imageData.format && |
|
texture.internalformat === imageData.internalformat, |
|
'incompatible format for texture.subimage'); |
|
check$1( |
|
x >= 0 && y >= 0 && |
|
x + imageData.width <= texture.width && |
|
y + imageData.height <= texture.height, |
|
'texture.subimage write out of bounds'); |
|
check$1( |
|
texture.mipmask & (1 << level), |
|
'missing mipmap data'); |
|
check$1( |
|
imageData.data || imageData.element || imageData.needsCopy, |
|
'missing image data'); |
|
|
|
tempBind(texture); |
|
setSubImage(imageData, GL_TEXTURE_2D, x, y, level); |
|
tempRestore(); |
|
|
|
freeImage(imageData); |
|
|
|
return reglTexture2D |
|
} |
|
|
|
function resize (w_, h_) { |
|
var w = w_ | 0; |
|
var h = (h_ | 0) || w; |
|
if (w === texture.width && h === texture.height) { |
|
return reglTexture2D |
|
} |
|
|
|
reglTexture2D.width = texture.width = w; |
|
reglTexture2D.height = texture.height = h; |
|
|
|
tempBind(texture); |
|
for (var i = 0; texture.mipmask >> i; ++i) { |
|
gl.texImage2D( |
|
GL_TEXTURE_2D, |
|
i, |
|
texture.format, |
|
w >> i, |
|
h >> i, |
|
0, |
|
texture.format, |
|
texture.type, |
|
null); |
|
} |
|
tempRestore(); |
|
|
|
// also, recompute the texture size. |
|
if (config.profile) { |
|
texture.stats.size = getTextureSize( |
|
texture.internalformat, |
|
texture.type, |
|
w, |
|
h, |
|
false, |
|
false); |
|
} |
|
|
|
return reglTexture2D |
|
} |
|
|
|
reglTexture2D(a, b); |
|
|
|
reglTexture2D.subimage = subimage; |
|
reglTexture2D.resize = resize; |
|
reglTexture2D._reglType = 'texture2d'; |
|
reglTexture2D._texture = texture; |
|
if (config.profile) { |
|
reglTexture2D.stats = texture.stats; |
|
} |
|
reglTexture2D.destroy = function () { |
|
texture.decRef(); |
|
}; |
|
|
|
return reglTexture2D |
|
} |
|
|
|
function createTextureCube (a0, a1, a2, a3, a4, a5) { |
|
var texture = new REGLTexture(GL_TEXTURE_CUBE_MAP); |
|
textureSet[texture.id] = texture; |
|
stats.cubeCount++; |
|
|
|
var faces = new Array(6); |
|
|
|
function reglTextureCube (a0, a1, a2, a3, a4, a5) { |
|
var i; |
|
var texInfo = texture.texInfo; |
|
TexInfo.call(texInfo); |
|
for (i = 0; i < 6; ++i) { |
|
faces[i] = allocMipMap(); |
|
} |
|
|
|
if (typeof a0 === 'number' || !a0) { |
|
var s = (a0 | 0) || 1; |
|
for (i = 0; i < 6; ++i) { |
|
parseMipMapFromShape(faces[i], s, s); |
|
} |
|
} else if (typeof a0 === 'object') { |
|
if (a1) { |
|
parseMipMapFromObject(faces[0], a0); |
|
parseMipMapFromObject(faces[1], a1); |
|
parseMipMapFromObject(faces[2], a2); |
|
parseMipMapFromObject(faces[3], a3); |
|
parseMipMapFromObject(faces[4], a4); |
|
parseMipMapFromObject(faces[5], a5); |
|
} else { |
|
parseTexInfo(texInfo, a0); |
|
parseFlags(texture, a0); |
|
if ('faces' in a0) { |
|
var face_input = a0.faces; |
|
check$1(Array.isArray(face_input) && face_input.length === 6, |
|
'cube faces must be a length 6 array'); |
|
for (i = 0; i < 6; ++i) { |
|
check$1(typeof face_input[i] === 'object' && !!face_input[i], |
|
'invalid input for cube map face'); |
|
copyFlags(faces[i], texture); |
|
parseMipMapFromObject(faces[i], face_input[i]); |
|
} |
|
} else { |
|
for (i = 0; i < 6; ++i) { |
|
parseMipMapFromObject(faces[i], a0); |
|
} |
|
} |
|
} |
|
} else { |
|
check$1.raise('invalid arguments to cube map'); |
|
} |
|
|
|
copyFlags(texture, faces[0]); |
|
if (texInfo.genMipmaps) { |
|
texture.mipmask = (faces[0].width << 1) - 1; |
|
} else { |
|
texture.mipmask = faces[0].mipmask; |
|
} |
|
|
|
check$1.textureCube(texture, texInfo, faces, limits); |
|
texture.internalformat = faces[0].internalformat; |
|
|
|
reglTextureCube.width = faces[0].width; |
|
reglTextureCube.height = faces[0].height; |
|
|
|
tempBind(texture); |
|
for (i = 0; i < 6; ++i) { |
|
setMipMap(faces[i], GL_TEXTURE_CUBE_MAP_POSITIVE_X + i); |
|
} |
|
setTexInfo(texInfo, GL_TEXTURE_CUBE_MAP); |
|
tempRestore(); |
|
|
|
if (config.profile) { |
|
texture.stats.size = getTextureSize( |
|
texture.internalformat, |
|
texture.type, |
|
reglTextureCube.width, |
|
reglTextureCube.height, |
|
texInfo.genMipmaps, |
|
true); |
|
} |
|
|
|
reglTextureCube.format = textureFormatsInvert[texture.internalformat]; |
|
reglTextureCube.type = textureTypesInvert[texture.type]; |
|
|
|
reglTextureCube.mag = magFiltersInvert[texInfo.magFilter]; |
|
reglTextureCube.min = minFiltersInvert[texInfo.minFilter]; |
|
|
|
reglTextureCube.wrapS = wrapModesInvert[texInfo.wrapS]; |
|
reglTextureCube.wrapT = wrapModesInvert[texInfo.wrapT]; |
|
|
|
for (i = 0; i < 6; ++i) { |
|
freeMipMap(faces[i]); |
|
} |
|
|
|
return reglTextureCube |
|
} |
|
|
|
function subimage (face, image, x_, y_, level_) { |
|
check$1(!!image, 'must specify image data'); |
|
check$1(typeof face === 'number' && face === (face | 0) && |
|
face >= 0 && face < 6, 'invalid face'); |
|
|
|
var x = x_ | 0; |
|
var y = y_ | 0; |
|
var level = level_ | 0; |
|
|
|
var imageData = allocImage(); |
|
copyFlags(imageData, texture); |
|
imageData.width = 0; |
|
imageData.height = 0; |
|
parseImage(imageData, image); |
|
imageData.width = imageData.width || ((texture.width >> level) - x); |
|
imageData.height = imageData.height || ((texture.height >> level) - y); |
|
|
|
check$1( |
|
texture.type === imageData.type && |
|
texture.format === imageData.format && |
|
texture.internalformat === imageData.internalformat, |
|
'incompatible format for texture.subimage'); |
|
check$1( |
|
x >= 0 && y >= 0 && |
|
x + imageData.width <= texture.width && |
|
y + imageData.height <= texture.height, |
|
'texture.subimage write out of bounds'); |
|
check$1( |
|
texture.mipmask & (1 << level), |
|
'missing mipmap data'); |
|
check$1( |
|
imageData.data || imageData.element || imageData.needsCopy, |
|
'missing image data'); |
|
|
|
tempBind(texture); |
|
setSubImage(imageData, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, x, y, level); |
|
tempRestore(); |
|
|
|
freeImage(imageData); |
|
|
|
return reglTextureCube |
|
} |
|
|
|
function resize (radius_) { |
|
var radius = radius_ | 0; |
|
if (radius === texture.width) { |
|
return |
|
} |
|
|
|
reglTextureCube.width = texture.width = radius; |
|
reglTextureCube.height = texture.height = radius; |
|
|
|
tempBind(texture); |
|
for (var i = 0; i < 6; ++i) { |
|
for (var j = 0; texture.mipmask >> j; ++j) { |
|
gl.texImage2D( |
|
GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, |
|
j, |
|
texture.format, |
|
radius >> j, |
|
radius >> j, |
|
0, |
|
texture.format, |
|
texture.type, |
|
null); |
|
} |
|
} |
|
tempRestore(); |
|
|
|
if (config.profile) { |
|
texture.stats.size = getTextureSize( |
|
texture.internalformat, |
|
texture.type, |
|
reglTextureCube.width, |
|
reglTextureCube.height, |
|
false, |
|
true); |
|
} |
|
|
|
return reglTextureCube |
|
} |
|
|
|
reglTextureCube(a0, a1, a2, a3, a4, a5); |
|
|
|
reglTextureCube.subimage = subimage; |
|
reglTextureCube.resize = resize; |
|
reglTextureCube._reglType = 'textureCube'; |
|
reglTextureCube._texture = texture; |
|
if (config.profile) { |
|
reglTextureCube.stats = texture.stats; |
|
} |
|
reglTextureCube.destroy = function () { |
|
texture.decRef(); |
|
}; |
|
|
|
return reglTextureCube |
|
} |
|
|
|
// Called when regl is destroyed |
|
function destroyTextures () { |
|
for (var i = 0; i < numTexUnits; ++i) { |
|
gl.activeTexture(GL_TEXTURE0 + i); |
|
gl.bindTexture(GL_TEXTURE_2D, null); |
|
textureUnits[i] = null; |
|
} |
|
values(textureSet).forEach(destroy); |
|
|
|
stats.cubeCount = 0; |
|
stats.textureCount = 0; |
|
} |
|
|
|
if (config.profile) { |
|
stats.getTotalTextureSize = function () { |
|
var total = 0; |
|
Object.keys(textureSet).forEach(function (key) { |
|
total += textureSet[key].stats.size; |
|
}); |
|
return total |
|
}; |
|
} |
|
|
|
function restoreTextures () { |
|
values(textureSet).forEach(function (texture) { |
|
texture.texture = gl.createTexture(); |
|
gl.bindTexture(texture.target, texture.texture); |
|
for (var i = 0; i < 32; ++i) { |
|
if ((texture.mipmask & (1 << i)) === 0) { |
|
continue |
|
} |
|
if (texture.target === GL_TEXTURE_2D) { |
|
gl.texImage2D(GL_TEXTURE_2D, |
|
i, |
|
texture.internalformat, |
|
texture.width >> i, |
|
texture.height >> i, |
|
0, |
|
texture.internalformat, |
|
texture.type, |
|
null); |
|
} else { |
|
for (var j = 0; j < 6; ++j) { |
|
gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, |
|
i, |
|
texture.internalformat, |
|
texture.width >> i, |
|
texture.height >> i, |
|
0, |
|
texture.internalformat, |
|
texture.type, |
|
null); |
|
} |
|
} |
|
} |
|
setTexInfo(texture.texInfo, texture.target); |
|
}); |
|
} |
|
|
|
return { |
|
create2D: createTexture2D, |
|
createCube: createTextureCube, |
|
clear: destroyTextures, |
|
getTexture: function (wrapper) { |
|
return null |
|
}, |
|
restore: restoreTextures |
|
} |
|
} |
|
|
|
var GL_RENDERBUFFER = 0x8D41; |
|
|
|
var GL_RGBA4$1 = 0x8056; |
|
var GL_RGB5_A1$1 = 0x8057; |
|
var GL_RGB565$1 = 0x8D62; |
|
var GL_DEPTH_COMPONENT16 = 0x81A5; |
|
var GL_STENCIL_INDEX8 = 0x8D48; |
|
var GL_DEPTH_STENCIL$1 = 0x84F9; |
|
|
|
var GL_SRGB8_ALPHA8_EXT = 0x8C43; |
|
|
|
var GL_RGBA32F_EXT = 0x8814; |
|
|
|
var GL_RGBA16F_EXT = 0x881A; |
|
var GL_RGB16F_EXT = 0x881B; |
|
|
|
var FORMAT_SIZES = []; |
|
|
|
FORMAT_SIZES[GL_RGBA4$1] = 2; |
|
FORMAT_SIZES[GL_RGB5_A1$1] = 2; |
|
FORMAT_SIZES[GL_RGB565$1] = 2; |
|
|
|
FORMAT_SIZES[GL_DEPTH_COMPONENT16] = 2; |
|
FORMAT_SIZES[GL_STENCIL_INDEX8] = 1; |
|
FORMAT_SIZES[GL_DEPTH_STENCIL$1] = 4; |
|
|
|
FORMAT_SIZES[GL_SRGB8_ALPHA8_EXT] = 4; |
|
FORMAT_SIZES[GL_RGBA32F_EXT] = 16; |
|
FORMAT_SIZES[GL_RGBA16F_EXT] = 8; |
|
FORMAT_SIZES[GL_RGB16F_EXT] = 6; |
|
|
|
function getRenderbufferSize (format, width, height) { |
|
return FORMAT_SIZES[format] * width * height |
|
} |
|
|
|
var wrapRenderbuffers = function (gl, extensions, limits, stats, config) { |
|
var formatTypes = { |
|
'rgba4': GL_RGBA4$1, |
|
'rgb565': GL_RGB565$1, |
|
'rgb5 a1': GL_RGB5_A1$1, |
|
'depth': GL_DEPTH_COMPONENT16, |
|
'stencil': GL_STENCIL_INDEX8, |
|
'depth stencil': GL_DEPTH_STENCIL$1 |
|
}; |
|
|
|
if (extensions.ext_srgb) { |
|
formatTypes['srgba'] = GL_SRGB8_ALPHA8_EXT; |
|
} |
|
|
|
if (extensions.ext_color_buffer_half_float) { |
|
formatTypes['rgba16f'] = GL_RGBA16F_EXT; |
|
formatTypes['rgb16f'] = GL_RGB16F_EXT; |
|
} |
|
|
|
if (extensions.webgl_color_buffer_float) { |
|
formatTypes['rgba32f'] = GL_RGBA32F_EXT; |
|
} |
|
|
|
var formatTypesInvert = []; |
|
Object.keys(formatTypes).forEach(function (key) { |
|
var val = formatTypes[key]; |
|
formatTypesInvert[val] = key; |
|
}); |
|
|
|
var renderbufferCount = 0; |
|
var renderbufferSet = {}; |
|
|
|
function REGLRenderbuffer (renderbuffer) { |
|
this.id = renderbufferCount++; |
|
this.refCount = 1; |
|
|
|
this.renderbuffer = renderbuffer; |
|
|
|
this.format = GL_RGBA4$1; |
|
this.width = 0; |
|
this.height = 0; |
|
|
|
if (config.profile) { |
|
this.stats = {size: 0}; |
|
} |
|
} |
|
|
|
REGLRenderbuffer.prototype.decRef = function () { |
|
if (--this.refCount <= 0) { |
|
destroy(this); |
|
} |
|
}; |
|
|
|
function destroy (rb) { |
|
var handle = rb.renderbuffer; |
|
check$1(handle, 'must not double destroy renderbuffer'); |
|
gl.bindRenderbuffer(GL_RENDERBUFFER, null); |
|
gl.deleteRenderbuffer(handle); |
|
rb.renderbuffer = null; |
|
rb.refCount = 0; |
|
delete renderbufferSet[rb.id]; |
|
stats.renderbufferCount--; |
|
} |
|
|
|
function createRenderbuffer (a, b) { |
|
var renderbuffer = new REGLRenderbuffer(gl.createRenderbuffer()); |
|
renderbufferSet[renderbuffer.id] = renderbuffer; |
|
stats.renderbufferCount++; |
|
|
|
function reglRenderbuffer (a, b) { |
|
var w = 0; |
|
var h = 0; |
|
var format = GL_RGBA4$1; |
|
|
|
if (typeof a === 'object' && a) { |
|
var options = a; |
|
if ('shape' in options) { |
|
var shape = options.shape; |
|
check$1(Array.isArray(shape) && shape.length >= 2, |
|
'invalid renderbuffer shape'); |
|
w = shape[0] | 0; |
|
h = shape[1] | 0; |
|
} else { |
|
if ('radius' in options) { |
|
w = h = options.radius | 0; |
|
} |
|
if ('width' in options) { |
|
w = options.width | 0; |
|
} |
|
if ('height' in options) { |
|
h = options.height | 0; |
|
} |
|
} |
|
if ('format' in options) { |
|
check$1.parameter(options.format, formatTypes, |
|
'invalid renderbuffer format'); |
|
format = formatTypes[options.format]; |
|
} |
|
} else if (typeof a === 'number') { |
|
w = a | 0; |
|
if (typeof b === 'number') { |
|
h = b | 0; |
|
} else { |
|
h = w; |
|
} |
|
} else if (!a) { |
|
w = h = 1; |
|
} else { |
|
check$1.raise('invalid arguments to renderbuffer constructor'); |
|
} |
|
|
|
// check shape |
|
check$1( |
|
w > 0 && h > 0 && |
|
w <= limits.maxRenderbufferSize && h <= limits.maxRenderbufferSize, |
|
'invalid renderbuffer size'); |
|
|
|
if (w === renderbuffer.width && |
|
h === renderbuffer.height && |
|
format === renderbuffer.format) { |
|
return |
|
} |
|
|
|
reglRenderbuffer.width = renderbuffer.width = w; |
|
reglRenderbuffer.height = renderbuffer.height = h; |
|
renderbuffer.format = format; |
|
|
|
gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer.renderbuffer); |
|
gl.renderbufferStorage(GL_RENDERBUFFER, format, w, h); |
|
|
|
if (config.profile) { |
|
renderbuffer.stats.size = getRenderbufferSize(renderbuffer.format, renderbuffer.width, renderbuffer.height); |
|
} |
|
reglRenderbuffer.format = formatTypesInvert[renderbuffer.format]; |
|
|
|
return reglRenderbuffer |
|
} |
|
|
|
function resize (w_, h_) { |
|
var w = w_ | 0; |
|
var h = (h_ | 0) || w; |
|
|
|
if (w === renderbuffer.width && h === renderbuffer.height) { |
|
return reglRenderbuffer |
|
} |
|
|
|
// check shape |
|
check$1( |
|
w > 0 && h > 0 && |
|
w <= limits.maxRenderbufferSize && h <= limits.maxRenderbufferSize, |
|
'invalid renderbuffer size'); |
|
|
|
reglRenderbuffer.width = renderbuffer.width = w; |
|
reglRenderbuffer.height = renderbuffer.height = h; |
|
|
|
gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer.renderbuffer); |
|
gl.renderbufferStorage(GL_RENDERBUFFER, renderbuffer.format, w, h); |
|
|
|
// also, recompute size. |
|
if (config.profile) { |
|
renderbuffer.stats.size = getRenderbufferSize( |
|
renderbuffer.format, renderbuffer.width, renderbuffer.height); |
|
} |
|
|
|
return reglRenderbuffer |
|
} |
|
|
|
reglRenderbuffer(a, b); |
|
|
|
reglRenderbuffer.resize = resize; |
|
reglRenderbuffer._reglType = 'renderbuffer'; |
|
reglRenderbuffer._renderbuffer = renderbuffer; |
|
if (config.profile) { |
|
reglRenderbuffer.stats = renderbuffer.stats; |
|
} |
|
reglRenderbuffer.destroy = function () { |
|
renderbuffer.decRef(); |
|
}; |
|
|
|
return reglRenderbuffer |
|
} |
|
|
|
if (config.profile) { |
|
stats.getTotalRenderbufferSize = function () { |
|
var total = 0; |
|
Object.keys(renderbufferSet).forEach(function (key) { |
|
total += renderbufferSet[key].stats.size; |
|
}); |
|
return total |
|
}; |
|
} |
|
|
|
function restoreRenderbuffers () { |
|
values(renderbufferSet).forEach(function (rb) { |
|
rb.renderbuffer = gl.createRenderbuffer(); |
|
gl.bindRenderbuffer(GL_RENDERBUFFER, rb.renderbuffer); |
|
gl.renderbufferStorage(GL_RENDERBUFFER, rb.format, rb.width, rb.height); |
|
}); |
|
gl.bindRenderbuffer(GL_RENDERBUFFER, null); |
|
} |
|
|
|
return { |
|
create: createRenderbuffer, |
|
clear: function () { |
|
values(renderbufferSet).forEach(destroy); |
|
}, |
|
restore: restoreRenderbuffers |
|
} |
|
}; |
|
|
|
// We store these constants so that the minifier can inline them |
|
var GL_FRAMEBUFFER = 0x8D40; |
|
var GL_RENDERBUFFER$1 = 0x8D41; |
|
|
|
var GL_TEXTURE_2D$1 = 0x0DE1; |
|
var GL_TEXTURE_CUBE_MAP_POSITIVE_X$1 = 0x8515; |
|
|
|
var GL_COLOR_ATTACHMENT0 = 0x8CE0; |
|
var GL_DEPTH_ATTACHMENT = 0x8D00; |
|
var GL_STENCIL_ATTACHMENT = 0x8D20; |
|
var GL_DEPTH_STENCIL_ATTACHMENT = 0x821A; |
|
|
|
var GL_FRAMEBUFFER_COMPLETE = 0x8CD5; |
|
var GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6; |
|
var GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7; |
|
var GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x8CD9; |
|
var GL_FRAMEBUFFER_UNSUPPORTED = 0x8CDD; |
|
|
|
var GL_HALF_FLOAT_OES$2 = 0x8D61; |
|
var GL_UNSIGNED_BYTE$5 = 0x1401; |
|
var GL_FLOAT$4 = 0x1406; |
|
|
|
var GL_RGBA$1 = 0x1908; |
|
|
|
var GL_DEPTH_COMPONENT$1 = 0x1902; |
|
|
|
var colorTextureFormatEnums = [ |
|
GL_RGBA$1 |
|
]; |
|
|
|
// for every texture format, store |
|
// the number of channels |
|
var textureFormatChannels = []; |
|
textureFormatChannels[GL_RGBA$1] = 4; |
|
|
|
// for every texture type, store |
|
// the size in bytes. |
|
var textureTypeSizes = []; |
|
textureTypeSizes[GL_UNSIGNED_BYTE$5] = 1; |
|
textureTypeSizes[GL_FLOAT$4] = 4; |
|
textureTypeSizes[GL_HALF_FLOAT_OES$2] = 2; |
|
|
|
var GL_RGBA4$2 = 0x8056; |
|
var GL_RGB5_A1$2 = 0x8057; |
|
var GL_RGB565$2 = 0x8D62; |
|
var GL_DEPTH_COMPONENT16$1 = 0x81A5; |
|
var GL_STENCIL_INDEX8$1 = 0x8D48; |
|
var GL_DEPTH_STENCIL$2 = 0x84F9; |
|
|
|
var GL_SRGB8_ALPHA8_EXT$1 = 0x8C43; |
|
|
|
var GL_RGBA32F_EXT$1 = 0x8814; |
|
|
|
var GL_RGBA16F_EXT$1 = 0x881A; |
|
var GL_RGB16F_EXT$1 = 0x881B; |
|
|
|
var colorRenderbufferFormatEnums = [ |
|
GL_RGBA4$2, |
|
GL_RGB5_A1$2, |
|
GL_RGB565$2, |
|
GL_SRGB8_ALPHA8_EXT$1, |
|
GL_RGBA16F_EXT$1, |
|
GL_RGB16F_EXT$1, |
|
GL_RGBA32F_EXT$1 |
|
]; |
|
|
|
var statusCode = {}; |
|
statusCode[GL_FRAMEBUFFER_COMPLETE] = 'complete'; |
|
statusCode[GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT] = 'incomplete attachment'; |
|
statusCode[GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS] = 'incomplete dimensions'; |
|
statusCode[GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT] = 'incomplete, missing attachment'; |
|
statusCode[GL_FRAMEBUFFER_UNSUPPORTED] = 'unsupported'; |
|
|
|
function wrapFBOState ( |
|
gl, |
|
extensions, |
|
limits, |
|
textureState, |
|
renderbufferState, |
|
stats) { |
|
var framebufferState = { |
|
cur: null, |
|
next: null, |
|
dirty: false, |
|
setFBO: null |
|
}; |
|
|
|
var colorTextureFormats = ['rgba']; |
|
var colorRenderbufferFormats = ['rgba4', 'rgb565', 'rgb5 a1']; |
|
|
|
if (extensions.ext_srgb) { |
|
colorRenderbufferFormats.push('srgba'); |
|
} |
|
|
|
if (extensions.ext_color_buffer_half_float) { |
|
colorRenderbufferFormats.push('rgba16f', 'rgb16f'); |
|
} |
|
|
|
if (extensions.webgl_color_buffer_float) { |
|
colorRenderbufferFormats.push('rgba32f'); |
|
} |
|
|
|
var colorTypes = ['uint8']; |
|
if (extensions.oes_texture_half_float) { |
|
colorTypes.push('half float', 'float16'); |
|
} |
|
if (extensions.oes_texture_float) { |
|
colorTypes.push('float', 'float32'); |
|
} |
|
|
|
function FramebufferAttachment (target, texture, renderbuffer) { |
|
this.target = target; |
|
this.texture = texture; |
|
this.renderbuffer = renderbuffer; |
|
|
|
var w = 0; |
|
var h = 0; |
|
if (texture) { |
|
w = texture.width; |
|
h = texture.height; |
|
} else if (renderbuffer) { |
|
w = renderbuffer.width; |
|
h = renderbuffer.height; |
|
} |
|
this.width = w; |
|
this.height = h; |
|
} |
|
|
|
function decRef (attachment) { |
|
if (attachment) { |
|
if (attachment.texture) { |
|
attachment.texture._texture.decRef(); |
|
} |
|
if (attachment.renderbuffer) { |
|
attachment.renderbuffer._renderbuffer.decRef(); |
|
} |
|
} |
|
} |
|
|
|
function incRefAndCheckShape (attachment, width, height) { |
|
if (!attachment) { |
|
return |
|
} |
|
if (attachment.texture) { |
|
var texture = attachment.texture._texture; |
|
var tw = Math.max(1, texture.width); |
|
var th = Math.max(1, texture.height); |
|
check$1(tw === width && th === height, |
|
'inconsistent width/height for supplied texture'); |
|
texture.refCount += 1; |
|
} else { |
|
var renderbuffer = attachment.renderbuffer._renderbuffer; |
|
check$1( |
|
renderbuffer.width === width && renderbuffer.height === height, |
|
'inconsistent width/height for renderbuffer'); |
|
renderbuffer.refCount += 1; |
|
} |
|
} |
|
|
|
function attach (location, attachment) { |
|
if (attachment) { |
|
if (attachment.texture) { |
|
gl.framebufferTexture2D( |
|
GL_FRAMEBUFFER, |
|
location, |
|
attachment.target, |
|
attachment.texture._texture.texture, |
|
0); |
|
} else { |
|
gl.framebufferRenderbuffer( |
|
GL_FRAMEBUFFER, |
|
location, |
|
GL_RENDERBUFFER$1, |
|
attachment.renderbuffer._renderbuffer.renderbuffer); |
|
} |
|
} |
|
} |
|
|
|
function parseAttachment (attachment) { |
|
var target = GL_TEXTURE_2D$1; |
|
var texture = null; |
|
var renderbuffer = null; |
|
|
|
var data = attachment; |
|
if (typeof attachment === 'object') { |
|
data = attachment.data; |
|
if ('target' in attachment) { |
|
target = attachment.target | 0; |
|
} |
|
} |
|
|
|
check$1.type(data, 'function', 'invalid attachment data'); |
|
|
|
var type = data._reglType; |
|
if (type === 'texture2d') { |
|
texture = data; |
|
check$1(target === GL_TEXTURE_2D$1); |
|
} else if (type === 'textureCube') { |
|
texture = data; |
|
check$1( |
|
target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X$1 && |
|
target < GL_TEXTURE_CUBE_MAP_POSITIVE_X$1 + 6, |
|
'invalid cube map target'); |
|
} else if (type === 'renderbuffer') { |
|
renderbuffer = data; |
|
target = GL_RENDERBUFFER$1; |
|
} else { |
|
check$1.raise('invalid regl object for attachment'); |
|
} |
|
|
|
return new FramebufferAttachment(target, texture, renderbuffer) |
|
} |
|
|
|
function allocAttachment ( |
|
width, |
|
height, |
|
isTexture, |
|
format, |
|
type) { |
|
if (isTexture) { |
|
var texture = textureState.create2D({ |
|
width: width, |
|
height: height, |
|
format: format, |
|
type: type |
|
}); |
|
texture._texture.refCount = 0; |
|
return new FramebufferAttachment(GL_TEXTURE_2D$1, texture, null) |
|
} else { |
|
var rb = renderbufferState.create({ |
|
width: width, |
|
height: height, |
|
format: format |
|
}); |
|
rb._renderbuffer.refCount = 0; |
|
return new FramebufferAttachment(GL_RENDERBUFFER$1, null, rb) |
|
} |
|
} |
|
|
|
function unwrapAttachment (attachment) { |
|
return attachment && (attachment.texture || attachment.renderbuffer) |
|
} |
|
|
|
function resizeAttachment (attachment, w, h) { |
|
if (attachment) { |
|
if (attachment.texture) { |
|
attachment.texture.resize(w, h); |
|
} else if (attachment.renderbuffer) { |
|
attachment.renderbuffer.resize(w, h); |
|
} |
|
} |
|
} |
|
|
|
var framebufferCount = 0; |
|
var framebufferSet = {}; |
|
|
|
function REGLFramebuffer () { |
|
this.id = framebufferCount++; |
|
framebufferSet[this.id] = this; |
|
|
|
this.framebuffer = gl.createFramebuffer(); |
|
this.width = 0; |
|
this.height = 0; |
|
|
|
this.colorAttachments = []; |
|
this.depthAttachment = null; |
|
this.stencilAttachment = null; |
|
this.depthStencilAttachment = null; |
|
} |
|
|
|
function decFBORefs (framebuffer) { |
|
framebuffer.colorAttachments.forEach(decRef); |
|
decRef(framebuffer.depthAttachment); |
|
decRef(framebuffer.stencilAttachment); |
|
decRef(framebuffer.depthStencilAttachment); |
|
} |
|
|
|
function destroy (framebuffer) { |
|
var handle = framebuffer.framebuffer; |
|
check$1(handle, 'must not double destroy framebuffer'); |
|
gl.deleteFramebuffer(handle); |
|
framebuffer.framebuffer = null; |
|
stats.framebufferCount--; |
|
delete framebufferSet[framebuffer.id]; |
|
} |
|
|
|
function updateFramebuffer (framebuffer) { |
|
var i; |
|
|
|
gl.bindFramebuffer(GL_FRAMEBUFFER, framebuffer.framebuffer); |
|
var colorAttachments = framebuffer.colorAttachments; |
|
for (i = 0; i < colorAttachments.length; ++i) { |
|
attach(GL_COLOR_ATTACHMENT0 + i, colorAttachments[i]); |
|
} |
|
for (i = colorAttachments.length; i < limits.maxColorAttachments; ++i) { |
|
gl.framebufferTexture2D( |
|
GL_FRAMEBUFFER, |
|
GL_COLOR_ATTACHMENT0 + i, |
|
GL_TEXTURE_2D$1, |
|
null, |
|
0); |
|
} |
|
|
|
gl.framebufferTexture2D( |
|
GL_FRAMEBUFFER, |
|
GL_DEPTH_STENCIL_ATTACHMENT, |
|
GL_TEXTURE_2D$1, |
|
null, |
|
0); |
|
gl.framebufferTexture2D( |
|
GL_FRAMEBUFFER, |
|
GL_DEPTH_ATTACHMENT, |
|
GL_TEXTURE_2D$1, |
|
null, |
|
0); |
|
gl.framebufferTexture2D( |
|
GL_FRAMEBUFFER, |
|
GL_STENCIL_ATTACHMENT, |
|
GL_TEXTURE_2D$1, |
|
null, |
|
0); |
|
|
|
attach(GL_DEPTH_ATTACHMENT, framebuffer.depthAttachment); |
|
attach(GL_STENCIL_ATTACHMENT, framebuffer.stencilAttachment); |
|
attach(GL_DEPTH_STENCIL_ATTACHMENT, framebuffer.depthStencilAttachment); |
|
|
|
// Check status code |
|
var status = gl.checkFramebufferStatus(GL_FRAMEBUFFER); |
|
if (status !== GL_FRAMEBUFFER_COMPLETE) { |
|
check$1.raise('framebuffer configuration not supported, status = ' + |
|
statusCode[status]); |
|
} |
|
|
|
gl.bindFramebuffer(GL_FRAMEBUFFER, framebufferState.next); |
|
framebufferState.cur = framebufferState.next; |
|
|
|
// FIXME: Clear error code here. This is a work around for a bug in |
|
// headless-gl |
|
gl.getError(); |
|
} |
|
|
|
function createFBO (a0, a1) { |
|
var framebuffer = new REGLFramebuffer(); |
|
stats.framebufferCount++; |
|
|
|
function reglFramebuffer (a, b) { |
|
var i; |
|
|
|
check$1(framebufferState.next !== framebuffer, |
|
'can not update framebuffer which is currently in use'); |
|
|
|
var extDrawBuffers = extensions.webgl_draw_buffers; |
|
|
|
var width = 0; |
|
var height = 0; |
|
|
|
var needsDepth = true; |
|
var needsStencil = true; |
|
|
|
var colorBuffer = null; |
|
var colorTexture = true; |
|
var colorFormat = 'rgba'; |
|
var colorType = 'uint8'; |
|
var colorCount = 1; |
|
|
|
var depthBuffer = null; |
|
var stencilBuffer = null; |
|
var depthStencilBuffer = null; |
|
var depthStencilTexture = false; |
|
|
|
if (typeof a === 'number') { |
|
width = a | 0; |
|
height = (b | 0) || width; |
|
} else if (!a) { |
|
width = height = 1; |
|
} else { |
|
check$1.type(a, 'object', 'invalid arguments for framebuffer'); |
|
var options = a; |
|
|
|
if ('shape' in options) { |
|
var shape = options.shape; |
|
check$1(Array.isArray(shape) && shape.length >= 2, |
|
'invalid shape for framebuffer'); |
|
width = shape[0]; |
|
height = shape[1]; |
|
} else { |
|
if ('radius' in options) { |
|
width = height = options.radius; |
|
} |
|
if ('width' in options) { |
|
width = options.width; |
|
} |
|
if ('height' in options) { |
|
height = options.height; |
|
} |
|
} |
|
|
|
if ('color' in options || |
|
'colors' in options) { |
|
colorBuffer = |
|
options.color || |
|
options.colors; |
|
if (Array.isArray(colorBuffer)) { |
|
check$1( |
|
colorBuffer.length === 1 || extDrawBuffers, |
|
'multiple render targets not supported'); |
|
} |
|
} |
|
|
|
if (!colorBuffer) { |
|
if ('colorCount' in options) { |
|
colorCount = options.colorCount | 0; |
|
check$1(colorCount > 0, 'invalid color buffer count'); |
|
} |
|
|
|
if ('colorTexture' in options) { |
|
colorTexture = !!options.colorTexture; |
|
colorFormat = 'rgba4'; |
|
} |
|
|
|
if ('colorType' in options) { |
|
colorType = options.colorType; |
|
if (!colorTexture) { |
|
if (colorType === 'half float' || colorType === 'float16') { |
|
check$1(extensions.ext_color_buffer_half_float, |
|
'you must enable EXT_color_buffer_half_float to use 16-bit render buffers'); |
|
colorFormat = 'rgba16f'; |
|
} else if (colorType === 'float' || colorType === 'float32') { |
|
check$1(extensions.webgl_color_buffer_float, |
|
'you must enable WEBGL_color_buffer_float in order to use 32-bit floating point renderbuffers'); |
|
colorFormat = 'rgba32f'; |
|
} |
|
} else { |
|
check$1(extensions.oes_texture_float || |
|
!(colorType === 'float' || colorType === 'float32'), |
|
'you must enable OES_texture_float in order to use floating point framebuffer objects'); |
|
check$1(extensions.oes_texture_half_float || |
|
!(colorType === 'half float' || colorType === 'float16'), |
|
'you must enable OES_texture_half_float in order to use 16-bit floating point framebuffer objects'); |
|
} |
|
check$1.oneOf(colorType, colorTypes, 'invalid color type'); |
|
} |
|
|
|
if ('colorFormat' in options) { |
|
colorFormat = options.colorFormat; |
|
if (colorTextureFormats.indexOf(colorFormat) >= 0) { |
|
colorTexture = true; |
|
} else if (colorRenderbufferFormats.indexOf(colorFormat) >= 0) { |
|
colorTexture = false; |
|
} else { |
|
if (colorTexture) { |
|
check$1.oneOf( |
|
options.colorFormat, colorTextureFormats, |
|
'invalid color format for texture'); |
|
} else { |
|
check$1.oneOf( |
|
options.colorFormat, colorRenderbufferFormats, |
|
'invalid color format for renderbuffer'); |
|
} |
|
} |
|
} |
|
} |
|
|
|
if ('depthTexture' in options || 'depthStencilTexture' in options) { |
|
depthStencilTexture = !!(options.depthTexture || |
|
options.depthStencilTexture); |
|
check$1(!depthStencilTexture || extensions.webgl_depth_texture, |
|
'webgl_depth_texture extension not supported'); |
|
} |
|
|
|
if ('depth' in options) { |
|
if (typeof options.depth === 'boolean') { |
|
needsDepth = options.depth; |
|
} else { |
|
depthBuffer = options.depth; |
|
needsStencil = false; |
|
} |
|
} |
|
|
|
if ('stencil' in options) { |
|
if (typeof options.stencil === 'boolean') { |
|
needsStencil = options.stencil; |
|
} else { |
|
stencilBuffer = options.stencil; |
|
needsDepth = false; |
|
} |
|
} |
|
|
|
if ('depthStencil' in options) { |
|
if (typeof options.depthStencil === 'boolean') { |
|
needsDepth = needsStencil = options.depthStencil; |
|
} else { |
|
depthStencilBuffer = options.depthStencil; |
|
needsDepth = false; |
|
needsStencil = false; |
|
} |
|
} |
|
} |
|
|
|
// parse attachments |
|
var colorAttachments = null; |
|
var depthAttachment = null; |
|
var stencilAttachment = null; |
|
var depthStencilAttachment = null; |
|
|
|
// Set up color attachments |
|
if (Array.isArray(colorBuffer)) { |
|
colorAttachments = colorBuffer.map(parseAttachment); |
|
} else if (colorBuffer) { |
|
colorAttachments = [parseAttachment(colorBuffer)]; |
|
} else { |
|
colorAttachments = new Array(colorCount); |
|
for (i = 0; i < colorCount; ++i) { |
|
colorAttachments[i] = allocAttachment( |
|
width, |
|
height, |
|
colorTexture, |
|
colorFormat, |
|
colorType); |
|
} |
|
} |
|
|
|
check$1(extensions.webgl_draw_buffers || colorAttachments.length <= 1, |
|
'you must enable the WEBGL_draw_buffers extension in order to use multiple color buffers.'); |
|
check$1(colorAttachments.length <= limits.maxColorAttachments, |
|
'too many color attachments, not supported'); |
|
|
|
width = width || colorAttachments[0].width; |
|
height = height || colorAttachments[0].height; |
|
|
|
if (depthBuffer) { |
|
depthAttachment = parseAttachment(depthBuffer); |
|
} else if (needsDepth && !needsStencil) { |
|
depthAttachment = allocAttachment( |
|
width, |
|
height, |
|
depthStencilTexture, |
|
'depth', |
|
'uint32'); |
|
} |
|
|
|
if (stencilBuffer) { |
|
stencilAttachment = parseAttachment(stencilBuffer); |
|
} else if (needsStencil && !needsDepth) { |
|
stencilAttachment = allocAttachment( |
|
width, |
|
height, |
|
false, |
|
'stencil', |
|
'uint8'); |
|
} |
|
|
|
if (depthStencilBuffer) { |
|
depthStencilAttachment = parseAttachment(depthStencilBuffer); |
|
} else if (!depthBuffer && !stencilBuffer && needsStencil && needsDepth) { |
|
depthStencilAttachment = allocAttachment( |
|
width, |
|
height, |
|
depthStencilTexture, |
|
'depth stencil', |
|
'depth stencil'); |
|
} |
|
|
|
check$1( |
|
(!!depthBuffer) + (!!stencilBuffer) + (!!depthStencilBuffer) <= 1, |
|
'invalid framebuffer configuration, can specify exactly one depth/stencil attachment'); |
|
|
|
var commonColorAttachmentSize = null; |
|
|
|
for (i = 0; i < colorAttachments.length; ++i) { |
|
incRefAndCheckShape(colorAttachments[i], width, height); |
|
check$1(!colorAttachments[i] || |
|
(colorAttachments[i].texture && |
|
colorTextureFormatEnums.indexOf(colorAttachments[i].texture._texture.format) >= 0) || |
|
(colorAttachments[i].renderbuffer && |
|
colorRenderbufferFormatEnums.indexOf(colorAttachments[i].renderbuffer._renderbuffer.format) >= 0), |
|
'framebuffer color attachment ' + i + ' is invalid'); |
|
|
|
if (colorAttachments[i] && colorAttachments[i].texture) { |
|
var colorAttachmentSize = |
|
textureFormatChannels[colorAttachments[i].texture._texture.format] * |
|
textureTypeSizes[colorAttachments[i].texture._texture.type]; |
|
|
|
if (commonColorAttachmentSize === null) { |
|
commonColorAttachmentSize = colorAttachmentSize; |
|
} else { |
|
// We need to make sure that all color attachments have the same number of bitplanes |
|
// (that is, the same numer of bits per pixel) |
|
// This is required by the GLES2.0 standard. See the beginning of Chapter 4 in that document. |
|
check$1(commonColorAttachmentSize === colorAttachmentSize, |
|
'all color attachments much have the same number of bits per pixel.'); |
|
} |
|
} |
|
} |
|
incRefAndCheckShape(depthAttachment, width, height); |
|
check$1(!depthAttachment || |
|
(depthAttachment.texture && |
|
depthAttachment.texture._texture.format === GL_DEPTH_COMPONENT$1) || |
|
(depthAttachment.renderbuffer && |
|
depthAttachment.renderbuffer._renderbuffer.format === GL_DEPTH_COMPONENT16$1), |
|
'invalid depth attachment for framebuffer object'); |
|
incRefAndCheckShape(stencilAttachment, width, height); |
|
check$1(!stencilAttachment || |
|
(stencilAttachment.renderbuffer && |
|
stencilAttachment.renderbuffer._renderbuffer.format === GL_STENCIL_INDEX8$1), |
|
'invalid stencil attachment for framebuffer object'); |
|
incRefAndCheckShape(depthStencilAttachment, width, height); |
|
check$1(!depthStencilAttachment || |
|
(depthStencilAttachment.texture && |
|
depthStencilAttachment.texture._texture.format === GL_DEPTH_STENCIL$2) || |
|
(depthStencilAttachment.renderbuffer && |
|
depthStencilAttachment.renderbuffer._renderbuffer.format === GL_DEPTH_STENCIL$2), |
|
'invalid depth-stencil attachment for framebuffer object'); |
|
|
|
// decrement references |
|
decFBORefs(framebuffer); |
|
|
|
framebuffer.width = width; |
|
framebuffer.height = height; |
|
|
|
framebuffer.colorAttachments = colorAttachments; |
|
framebuffer.depthAttachment = depthAttachment; |
|
framebuffer.stencilAttachment = stencilAttachment; |
|
framebuffer.depthStencilAttachment = depthStencilAttachment; |
|
|
|
reglFramebuffer.color = colorAttachments.map(unwrapAttachment); |
|
reglFramebuffer.depth = unwrapAttachment(depthAttachment); |
|
reglFramebuffer.stencil = unwrapAttachment(stencilAttachment); |
|
reglFramebuffer.depthStencil = unwrapAttachment(depthStencilAttachment); |
|
|
|
reglFramebuffer.width = framebuffer.width; |
|
reglFramebuffer.height = framebuffer.height; |
|
|
|
updateFramebuffer(framebuffer); |
|
|
|
return reglFramebuffer |
|
} |
|
|
|
function resize (w_, h_) { |
|
check$1(framebufferState.next !== framebuffer, |
|
'can not resize a framebuffer which is currently in use'); |
|
|
|
var w = w_ | 0; |
|
var h = (h_ | 0) || w; |
|
if (w === framebuffer.width && h === framebuffer.height) { |
|
return reglFramebuffer |
|
} |
|
|
|
// resize all buffers |
|
var colorAttachments = framebuffer.colorAttachments; |
|
for (var i = 0; i < colorAttachments.length; ++i) { |
|
resizeAttachment(colorAttachments[i], w, h); |
|
} |
|
resizeAttachment(framebuffer.depthAttachment, w, h); |
|
resizeAttachment(framebuffer.stencilAttachment, w, h); |
|
resizeAttachment(framebuffer.depthStencilAttachment, w, h); |
|
|
|
framebuffer.width = reglFramebuffer.width = w; |
|
framebuffer.height = reglFramebuffer.height = h; |
|
|
|
updateFramebuffer(framebuffer); |
|
|
|
return reglFramebuffer |
|
} |
|
|
|
reglFramebuffer(a0, a1); |
|
|
|
return extend(reglFramebuffer, { |
|
resize: resize, |
|
_reglType: 'framebuffer', |
|
_framebuffer: framebuffer, |
|
destroy: function () { |
|
destroy(framebuffer); |
|
decFBORefs(framebuffer); |
|
}, |
|
use: function (block) { |
|
framebufferState.setFBO({ |
|
framebuffer: reglFramebuffer |
|
}, block); |
|
} |
|
}) |
|
} |
|
|
|
function createCubeFBO (options) { |
|
var faces = Array(6); |
|
|
|
function reglFramebufferCube (a) { |
|
var i; |
|
|
|
check$1(faces.indexOf(framebufferState.next) < 0, |
|
'can not update framebuffer which is currently in use'); |
|
|
|
var extDrawBuffers = extensions.webgl_draw_buffers; |
|
|
|
var params = { |
|
color: null |
|
}; |
|
|
|
var radius = 0; |
|
|
|
var colorBuffer = null; |
|
var colorFormat = 'rgba'; |
|
var colorType = 'uint8'; |
|
var colorCount = 1; |
|
|
|
if (typeof a === 'number') { |
|
radius = a | 0; |
|
} else if (!a) { |
|
radius = 1; |
|
} else { |
|
check$1.type(a, 'object', 'invalid arguments for framebuffer'); |
|
var options = a; |
|
|
|
if ('shape' in options) { |
|
var shape = options.shape; |
|
check$1( |
|
Array.isArray(shape) && shape.length >= 2, |
|
'invalid shape for framebuffer'); |
|
check$1( |
|
shape[0] === shape[1], |
|
'cube framebuffer must be square'); |
|
radius = shape[0]; |
|
} else { |
|
if ('radius' in options) { |
|
radius = options.radius | 0; |
|
} |
|
if ('width' in options) { |
|
radius = options.width | 0; |
|
if ('height' in options) { |
|
check$1(options.height === radius, 'must be square'); |
|
} |
|
} else if ('height' in options) { |
|
radius = options.height | 0; |
|
} |
|
} |
|
|
|
if ('color' in options || |
|
'colors' in options) { |
|
colorBuffer = |
|
options.color || |
|
options.colors; |
|
if (Array.isArray(colorBuffer)) { |
|
check$1( |
|
colorBuffer.length === 1 || extDrawBuffers, |
|
'multiple render targets not supported'); |
|
} |
|
} |
|
|
|
if (!colorBuffer) { |
|
if ('colorCount' in options) { |
|
colorCount = options.colorCount | 0; |
|
check$1(colorCount > 0, 'invalid color buffer count'); |
|
} |
|
|
|
if ('colorType' in options) { |
|
check$1.oneOf( |
|
options.colorType, colorTypes, |
|
'invalid color type'); |
|
colorType = options.colorType; |
|
} |
|
|
|
if ('colorFormat' in options) { |
|
colorFormat = options.colorFormat; |
|
check$1.oneOf( |
|
options.colorFormat, colorTextureFormats, |
|
'invalid color format for texture'); |
|
} |
|
} |
|
|
|
if ('depth' in options) { |
|
params.depth = options.depth; |
|
} |
|
|
|
if ('stencil' in options) { |
|
params.stencil = options.stencil; |
|
} |
|
|
|
if ('depthStencil' in options) { |
|
params.depthStencil = options.depthStencil; |
|
} |
|
} |
|
|
|
var colorCubes; |
|
if (colorBuffer) { |
|
if (Array.isArray(colorBuffer)) { |
|
colorCubes = []; |
|
for (i = 0; i < colorBuffer.length; ++i) { |
|
colorCubes[i] = colorBuffer[i]; |
|
} |
|
} else { |
|
colorCubes = [ colorBuffer ]; |
|
} |
|
} else { |
|
colorCubes = Array(colorCount); |
|
var cubeMapParams = { |
|
radius: radius, |
|
format: colorFormat, |
|
type: colorType |
|
}; |
|
for (i = 0; i < colorCount; ++i) { |
|
colorCubes[i] = textureState.createCube(cubeMapParams); |
|
} |
|
} |
|
|
|
// Check color cubes |
|
params.color = Array(colorCubes.length); |
|
for (i = 0; i < colorCubes.length; ++i) { |
|
var cube = colorCubes[i]; |
|
check$1( |
|
typeof cube === 'function' && cube._reglType === 'textureCube', |
|
'invalid cube map'); |
|
radius = radius || cube.width; |
|
check$1( |
|
cube.width === radius && cube.height === radius, |
|
'invalid cube map shape'); |
|
params.color[i] = { |
|
target: GL_TEXTURE_CUBE_MAP_POSITIVE_X$1, |
|
data: colorCubes[i] |
|
}; |
|
} |
|
|
|
for (i = 0; i < 6; ++i) { |
|
for (var j = 0; j < colorCubes.length; ++j) { |
|
params.color[j].target = GL_TEXTURE_CUBE_MAP_POSITIVE_X$1 + i; |
|
} |
|
// reuse depth-stencil attachments across all cube maps |
|
if (i > 0) { |
|
params.depth = faces[0].depth; |
|
params.stencil = faces[0].stencil; |
|
params.depthStencil = faces[0].depthStencil; |
|
} |
|
if (faces[i]) { |
|
(faces[i])(params); |
|
} else { |
|
faces[i] = createFBO(params); |
|
} |
|
} |
|
|
|
return extend(reglFramebufferCube, { |
|
width: radius, |
|
height: radius, |
|
color: colorCubes |
|
}) |
|
} |
|
|
|
function resize (radius_) { |
|
var i; |
|
var radius = radius_ | 0; |
|
check$1(radius > 0 && radius <= limits.maxCubeMapSize, |
|
'invalid radius for cube fbo'); |
|
|
|
if (radius === reglFramebufferCube.width) { |
|
return reglFramebufferCube |
|
} |
|
|
|
var colors = reglFramebufferCube.color; |
|
for (i = 0; i < colors.length; ++i) { |
|
colors[i].resize(radius); |
|
} |
|
|
|
for (i = 0; i < 6; ++i) { |
|
faces[i].resize(radius); |
|
} |
|
|
|
reglFramebufferCube.width = reglFramebufferCube.height = radius; |
|
|
|
return reglFramebufferCube |
|
} |
|
|
|
reglFramebufferCube(options); |
|
|
|
return extend(reglFramebufferCube, { |
|
faces: faces, |
|
resize: resize, |
|
_reglType: 'framebufferCube', |
|
destroy: function () { |
|
faces.forEach(function (f) { |
|
f.destroy(); |
|
}); |
|
} |
|
}) |
|
} |
|
|
|
function restoreFramebuffers () { |
|
values(framebufferSet).forEach(function (fb) { |
|
fb.framebuffer = gl.createFramebuffer(); |
|
updateFramebuffer(fb); |
|
}); |
|
} |
|
|
|
return extend(framebufferState, { |
|
getFramebuffer: function (object) { |
|
if (typeof object === 'function' && object._reglType === 'framebuffer') { |
|
var fbo = object._framebuffer; |
|
if (fbo instanceof REGLFramebuffer) { |
|
return fbo |
|
} |
|
} |
|
return null |
|
}, |
|
create: createFBO, |
|
createCube: createCubeFBO, |
|
clear: function () { |
|
values(framebufferSet).forEach(destroy); |
|
}, |
|
restore: restoreFramebuffers |
|
}) |
|
} |
|
|
|
var GL_FLOAT$5 = 5126; |
|
|
|
function AttributeRecord () { |
|
this.state = 0; |
|
|
|
this.x = 0.0; |
|
this.y = 0.0; |
|
this.z = 0.0; |
|
this.w = 0.0; |
|
|
|
this.buffer = null; |
|
this.size = 0; |
|
this.normalized = false; |
|
this.type = GL_FLOAT$5; |
|
this.offset = 0; |
|
this.stride = 0; |
|
this.divisor = 0; |
|
} |
|
|
|
function wrapAttributeState ( |
|
gl, |
|
extensions, |
|
limits, |
|
bufferState, |
|
stringStore) { |
|
var NUM_ATTRIBUTES = limits.maxAttributes; |
|
var attributeBindings = new Array(NUM_ATTRIBUTES); |
|
for (var i = 0; i < NUM_ATTRIBUTES; ++i) { |
|
attributeBindings[i] = new AttributeRecord(); |
|
} |
|
|
|
return { |
|
Record: AttributeRecord, |
|
scope: {}, |
|
state: attributeBindings |
|
} |
|
} |
|
|
|
var GL_FRAGMENT_SHADER = 35632; |
|
var GL_VERTEX_SHADER = 35633; |
|
|
|
var GL_ACTIVE_UNIFORMS = 0x8B86; |
|
var GL_ACTIVE_ATTRIBUTES = 0x8B89; |
|
|
|
function wrapShaderState (gl, stringStore, stats, config) { |
|
// =================================================== |
|
// glsl compilation and linking |
|
// =================================================== |
|
var fragShaders = {}; |
|
var vertShaders = {}; |
|
|
|
function ActiveInfo (name, id, location, info) { |
|
this.name = name; |
|
this.id = id; |
|
this.location = location; |
|
this.info = info; |
|
} |
|
|
|
function insertActiveInfo (list, info) { |
|
for (var i = 0; i < list.length; ++i) { |
|
if (list[i].id === info.id) { |
|
list[i].location = info.location; |
|
return |
|
} |
|
} |
|
list.push(info); |
|
} |
|
|
|
function getShader (type, id, command) { |
|
var cache = type === GL_FRAGMENT_SHADER ? fragShaders : vertShaders; |
|
var shader = cache[id]; |
|
|
|
if (!shader) { |
|
var source = stringStore.str(id); |
|
shader = gl.createShader(type); |
|
gl.shaderSource(shader, source); |
|
gl.compileShader(shader); |
|
check$1.shaderError(gl, shader, source, type, command); |
|
cache[id] = shader; |
|
} |
|
|
|
return shader |
|
} |
|
|
|
// =================================================== |
|
// program linking |
|
// =================================================== |
|
var programCache = {}; |
|
var programList = []; |
|
|
|
var PROGRAM_COUNTER = 0; |
|
|
|
function REGLProgram (fragId, vertId) { |
|
this.id = PROGRAM_COUNTER++; |
|
this.fragId = fragId; |
|
this.vertId = vertId; |
|
this.program = null; |
|
this.uniforms = []; |
|
this.attributes = []; |
|
|
|
if (config.profile) { |
|
this.stats = { |
|
uniformsCount: 0, |
|
attributesCount: 0 |
|
}; |
|
} |
|
} |
|
|
|
function linkProgram (desc, command) { |
|
var i, info; |
|
|
|
// ------------------------------- |
|
// compile & link |
|
// ------------------------------- |
|
var fragShader = getShader(GL_FRAGMENT_SHADER, desc.fragId); |
|
var vertShader = getShader(GL_VERTEX_SHADER, desc.vertId); |
|
|
|
var program = desc.program = gl.createProgram(); |
|
gl.attachShader(program, fragShader); |
|
gl.attachShader(program, vertShader); |
|
gl.linkProgram(program); |
|
check$1.linkError( |
|
gl, |
|
program, |
|
stringStore.str(desc.fragId), |
|
stringStore.str(desc.vertId), |
|
command); |
|
|
|
// ------------------------------- |
|
// grab uniforms |
|
// ------------------------------- |
|
var numUniforms = gl.getProgramParameter(program, GL_ACTIVE_UNIFORMS); |
|
if (config.profile) { |
|
desc.stats.uniformsCount = numUniforms; |
|
} |
|
var uniforms = desc.uniforms; |
|
for (i = 0; i < numUniforms; ++i) { |
|
info = gl.getActiveUniform(program, i); |
|
if (info) { |
|
if (info.size > 1) { |
|
for (var j = 0; j < info.size; ++j) { |
|
var name = info.name.replace('[0]', '[' + j + ']'); |
|
insertActiveInfo(uniforms, new ActiveInfo( |
|
name, |
|
stringStore.id(name), |
|
gl.getUniformLocation(program, name), |
|
info)); |
|
} |
|
} else { |
|
insertActiveInfo(uniforms, new ActiveInfo( |
|
info.name, |
|
stringStore.id(info.name), |
|
gl.getUniformLocation(program, info.name), |
|
info)); |
|
} |
|
} |
|
} |
|
|
|
// ------------------------------- |
|
// grab attributes |
|
// ------------------------------- |
|
var numAttributes = gl.getProgramParameter(program, GL_ACTIVE_ATTRIBUTES); |
|
if (config.profile) { |
|
desc.stats.attributesCount = numAttributes; |
|
} |
|
|
|
var attributes = desc.attributes; |
|
for (i = 0; i < numAttributes; ++i) { |
|
info = gl.getActiveAttrib(program, i); |
|
if (info) { |
|
insertActiveInfo(attributes, new ActiveInfo( |
|
info.name, |
|
stringStore.id(info.name), |
|
gl.getAttribLocation(program, info.name), |
|
info)); |
|
} |
|
} |
|
} |
|
|
|
if (config.profile) { |
|
stats.getMaxUniformsCount = function () { |
|
var m = 0; |
|
programList.forEach(function (desc) { |
|
if (desc.stats.uniformsCount > m) { |
|
m = desc.stats.uniformsCount; |
|
} |
|
}); |
|
return m |
|
}; |
|
|
|
stats.getMaxAttributesCount = function () { |
|
var m = 0; |
|
programList.forEach(function (desc) { |
|
if (desc.stats.attributesCount > m) { |
|
m = desc.stats.attributesCount; |
|
} |
|
}); |
|
return m |
|
}; |
|
} |
|
|
|
function restoreShaders () { |
|
fragShaders = {}; |
|
vertShaders = {}; |
|
for (var i = 0; i < programList.length; ++i) { |
|
linkProgram(programList[i]); |
|
} |
|
} |
|
|
|
return { |
|
clear: function () { |
|
var deleteShader = gl.deleteShader.bind(gl); |
|
values(fragShaders).forEach(deleteShader); |
|
fragShaders = {}; |
|
values(vertShaders).forEach(deleteShader); |
|
vertShaders = {}; |
|
|
|
programList.forEach(function (desc) { |
|
gl.deleteProgram(desc.program); |
|
}); |
|
programList.length = 0; |
|
programCache = {}; |
|
|
|
stats.shaderCount = 0; |
|
}, |
|
|
|
program: function (vertId, fragId, command) { |
|
check$1.command(vertId >= 0, 'missing vertex shader', command); |
|
check$1.command(fragId >= 0, 'missing fragment shader', command); |
|
|
|
var cache = programCache[fragId]; |
|
if (!cache) { |
|
cache = programCache[fragId] = {}; |
|
} |
|
var program = cache[vertId]; |
|
if (!program) { |
|
program = new REGLProgram(fragId, vertId); |
|
stats.shaderCount++; |
|
|
|
linkProgram(program, command); |
|
cache[vertId] = program; |
|
programList.push(program); |
|
} |
|
return program |
|
}, |
|
|
|
restore: restoreShaders, |
|
|
|
shader: getShader, |
|
|
|
frag: -1, |
|
vert: -1 |
|
} |
|
} |
|
|
|
var GL_RGBA$2 = 6408; |
|
var GL_UNSIGNED_BYTE$6 = 5121; |
|
var GL_PACK_ALIGNMENT = 0x0D05; |
|
var GL_FLOAT$6 = 0x1406; // 5126 |
|
|
|
function wrapReadPixels ( |
|
gl, |
|
framebufferState, |
|
reglPoll, |
|
context, |
|
glAttributes, |
|
extensions) { |
|
function readPixelsImpl (input) { |
|
var type; |
|
if (framebufferState.next === null) { |
|
check$1( |
|
glAttributes.preserveDrawingBuffer, |
|
'you must create a webgl context with "preserveDrawingBuffer":true in order to read pixels from the drawing buffer'); |
|
type = GL_UNSIGNED_BYTE$6; |
|
} else { |
|
check$1( |
|
framebufferState.next.colorAttachments[0].texture !== null, |
|
'You cannot read from a renderbuffer'); |
|
type = framebufferState.next.colorAttachments[0].texture._texture.type; |
|
|
|
if (extensions.oes_texture_float) { |
|
check$1( |
|
type === GL_UNSIGNED_BYTE$6 || type === GL_FLOAT$6, |
|
'Reading from a framebuffer is only allowed for the types \'uint8\' and \'float\''); |
|
} else { |
|
check$1( |
|
type === GL_UNSIGNED_BYTE$6, |
|
'Reading from a framebuffer is only allowed for the type \'uint8\''); |
|
} |
|
} |
|
|
|
var x = 0; |
|
var y = 0; |
|
var width = context.framebufferWidth; |
|
var height = context.framebufferHeight; |
|
var data = null; |
|
|
|
if (isTypedArray(input)) { |
|
data = input; |
|
} else if (input) { |
|
check$1.type(input, 'object', 'invalid arguments to regl.read()'); |
|
x = input.x | 0; |
|
y = input.y | 0; |
|
check$1( |
|
x >= 0 && x < context.framebufferWidth, |
|
'invalid x offset for regl.read'); |
|
check$1( |
|
y >= 0 && y < context.framebufferHeight, |
|
'invalid y offset for regl.read'); |
|
width = (input.width || (context.framebufferWidth - x)) | 0; |
|
height = (input.height || (context.framebufferHeight - y)) | 0; |
|
data = input.data || null; |
|
} |
|
|
|
// sanity check input.data |
|
if (data) { |
|
if (type === GL_UNSIGNED_BYTE$6) { |
|
check$1( |
|
data instanceof Uint8Array, |
|
'buffer must be \'Uint8Array\' when reading from a framebuffer of type \'uint8\''); |
|
} else if (type === GL_FLOAT$6) { |
|
check$1( |
|
data instanceof Float32Array, |
|
'buffer must be \'Float32Array\' when reading from a framebuffer of type \'float\''); |
|
} |
|
} |
|
|
|
check$1( |
|
width > 0 && width + x <= context.framebufferWidth, |
|
'invalid width for read pixels'); |
|
check$1( |
|
height > 0 && height + y <= context.framebufferHeight, |
|
'invalid height for read pixels'); |
|
|
|
// Update WebGL state |
|
reglPoll(); |
|
|
|
// Compute size |
|
var size = width * height * 4; |
|
|
|
// Allocate data |
|
if (!data) { |
|
if (type === GL_UNSIGNED_BYTE$6) { |
|
data = new Uint8Array(size); |
|
} else if (type === GL_FLOAT$6) { |
|
data = data || new Float32Array(size); |
|
} |
|
} |
|
|
|
// Type check |
|
check$1.isTypedArray(data, 'data buffer for regl.read() must be a typedarray'); |
|
check$1(data.byteLength >= size, 'data buffer for regl.read() too small'); |
|
|
|
// Run read pixels |
|
gl.pixelStorei(GL_PACK_ALIGNMENT, 4); |
|
gl.readPixels(x, y, width, height, GL_RGBA$2, |
|
type, |
|
data); |
|
|
|
return data |
|
} |
|
|
|
function readPixelsFBO (options) { |
|
var result; |
|
framebufferState.setFBO({ |
|
framebuffer: options.framebuffer |
|
}, function () { |
|
result = readPixelsImpl(options); |
|
}); |
|
return result |
|
} |
|
|
|
function readPixels (options) { |
|
if (!options || !('framebuffer' in options)) { |
|
return readPixelsImpl(options) |
|
} else { |
|
return readPixelsFBO(options) |
|
} |
|
} |
|
|
|
return readPixels |
|
} |
|
|
|
function slice (x) { |
|
return Array.prototype.slice.call(x) |
|
} |
|
|
|
function join (x) { |
|
return slice(x).join('') |
|
} |
|
|
|
function createEnvironment () { |
|
// Unique variable id counter |
|
var varCounter = 0; |
|
|
|
// Linked values are passed from this scope into the generated code block |
|
// Calling link() passes a value into the generated scope and returns |
|
// the variable name which it is bound to |
|
var linkedNames = []; |
|
var linkedValues = []; |
|
function link (value) { |
|
for (var i = 0; i < linkedValues.length; ++i) { |
|
if (linkedValues[i] === value) { |
|
return linkedNames[i] |
|
} |
|
} |
|
|
|
var name = 'g' + (varCounter++); |
|
linkedNames.push(name); |
|
linkedValues.push(value); |
|
return name |
|
} |
|
|
|
// create a code block |
|
function block () { |
|
var code = []; |
|
function push () { |
|
code.push.apply(code, slice(arguments)); |
|
} |
|
|
|
var vars = []; |
|
function def () { |
|
var name = 'v' + (varCounter++); |
|
vars.push(name); |
|
|
|
if (arguments.length > 0) { |
|
code.push(name, '='); |
|
code.push.apply(code, slice(arguments)); |
|
code.push(';'); |
|
} |
|
|
|
return name |
|
} |
|
|
|
return extend(push, { |
|
def: def, |
|
toString: function () { |
|
return join([ |
|
(vars.length > 0 ? 'var ' + vars + ';' : ''), |
|
join(code) |
|
]) |
|
} |
|
}) |
|
} |
|
|
|
function scope () { |
|
var entry = block(); |
|
var exit = block(); |
|
|
|
var entryToString = entry.toString; |
|
var exitToString = exit.toString; |
|
|
|
function save (object, prop) { |
|
exit(object, prop, '=', entry.def(object, prop), ';'); |
|
} |
|
|
|
return extend(function () { |
|
entry.apply(entry, slice(arguments)); |
|
}, { |
|
def: entry.def, |
|
entry: entry, |
|
exit: exit, |
|
save: save, |
|
set: function (object, prop, value) { |
|
save(object, prop); |
|
entry(object, prop, '=', value, ';'); |
|
}, |
|
toString: function () { |
|
return entryToString() + exitToString() |
|
} |
|
}) |
|
} |
|
|
|
function conditional () { |
|
var pred = join(arguments); |
|
var thenBlock = scope(); |
|
var elseBlock = scope(); |
|
|
|
var thenToString = thenBlock.toString; |
|
var elseToString = elseBlock.toString; |
|
|
|
return extend(thenBlock, { |
|
then: function () { |
|
thenBlock.apply(thenBlock, slice(arguments)); |
|
return this |
|
}, |
|
else: function () { |
|
elseBlock.apply(elseBlock, slice(arguments)); |
|
return this |
|
}, |
|
toString: function () { |
|
var elseClause = elseToString(); |
|
if (elseClause) { |
|
elseClause = 'else{' + elseClause + '}'; |
|
} |
|
return join([ |
|
'if(', pred, '){', |
|
thenToString(), |
|
'}', elseClause |
|
]) |
|
} |
|
}) |
|
} |
|
|
|
// procedure list |
|
var globalBlock = block(); |
|
var procedures = {}; |
|
function proc (name, count) { |
|
var args = []; |
|
function arg () { |
|
var name = 'a' + args.length; |
|
args.push(name); |
|
return name |
|
} |
|
|
|
count = count || 0; |
|
for (var i = 0; i < count; ++i) { |
|
arg(); |
|
} |
|
|
|
var body = scope(); |
|
var bodyToString = body.toString; |
|
|
|
var result = procedures[name] = extend(body, { |
|
arg: arg, |
|
toString: function () { |
|
return join([ |
|
'function(', args.join(), '){', |
|
bodyToString(), |
|
'}' |
|
]) |
|
} |
|
}); |
|
|
|
return result |
|
} |
|
|
|
function compile () { |
|
var code = ['"use strict";', |
|
globalBlock, |
|
'return {']; |
|
Object.keys(procedures).forEach(function (name) { |
|
code.push('"', name, '":', procedures[name].toString(), ','); |
|
}); |
|
code.push('}'); |
|
var src = join(code) |
|
.replace(/;/g, ';\n') |
|
.replace(/}/g, '}\n') |
|
.replace(/{/g, '{\n'); |
|
var proc = Function.apply(null, linkedNames.concat(src)); |
|
return proc.apply(null, linkedValues) |
|
} |
|
|
|
return { |
|
global: globalBlock, |
|
link: link, |
|
block: block, |
|
proc: proc, |
|
scope: scope, |
|
cond: conditional, |
|
compile: compile |
|
} |
|
} |
|
|
|
// "cute" names for vector components |
|
var CUTE_COMPONENTS = 'xyzw'.split(''); |
|
|
|
var GL_UNSIGNED_BYTE$7 = 5121; |
|
|
|
var ATTRIB_STATE_POINTER = 1; |
|
var ATTRIB_STATE_CONSTANT = 2; |
|
|
|
var DYN_FUNC$1 = 0; |
|
var DYN_PROP$1 = 1; |
|
var DYN_CONTEXT$1 = 2; |
|
var DYN_STATE$1 = 3; |
|
var DYN_THUNK = 4; |
|
|
|
var S_DITHER = 'dither'; |
|
var S_BLEND_ENABLE = 'blend.enable'; |
|
var S_BLEND_COLOR = 'blend.color'; |
|
var S_BLEND_EQUATION = 'blend.equation'; |
|
var S_BLEND_FUNC = 'blend.func'; |
|
var S_DEPTH_ENABLE = 'depth.enable'; |
|
var S_DEPTH_FUNC = 'depth.func'; |
|
var S_DEPTH_RANGE = 'depth.range'; |
|
var S_DEPTH_MASK = 'depth.mask'; |
|
var S_COLOR_MASK = 'colorMask'; |
|
var S_CULL_ENABLE = 'cull.enable'; |
|
var S_CULL_FACE = 'cull.face'; |
|
var S_FRONT_FACE = 'frontFace'; |
|
var S_LINE_WIDTH = 'lineWidth'; |
|
var S_POLYGON_OFFSET_ENABLE = 'polygonOffset.enable'; |
|
var S_POLYGON_OFFSET_OFFSET = 'polygonOffset.offset'; |
|
var S_SAMPLE_ALPHA = 'sample.alpha'; |
|
var S_SAMPLE_ENABLE = 'sample.enable'; |
|
var S_SAMPLE_COVERAGE = 'sample.coverage'; |
|
var S_STENCIL_ENABLE = 'stencil.enable'; |
|
var S_STENCIL_MASK = 'stencil.mask'; |
|
var S_STENCIL_FUNC = 'stencil.func'; |
|
var S_STENCIL_OPFRONT = 'stencil.opFront'; |
|
var S_STENCIL_OPBACK = 'stencil.opBack'; |
|
var S_SCISSOR_ENABLE = 'scissor.enable'; |
|
var S_SCISSOR_BOX = 'scissor.box'; |
|
var S_VIEWPORT = 'viewport'; |
|
|
|
var S_PROFILE = 'profile'; |
|
|
|
var S_FRAMEBUFFER = 'framebuffer'; |
|
var S_VERT = 'vert'; |
|
var S_FRAG = 'frag'; |
|
var S_ELEMENTS = 'elements'; |
|
var S_PRIMITIVE = 'primitive'; |
|
var S_COUNT = 'count'; |
|
var S_OFFSET = 'offset'; |
|
var S_INSTANCES = 'instances'; |
|
|
|
var SUFFIX_WIDTH = 'Width'; |
|
var SUFFIX_HEIGHT = 'Height'; |
|
|
|
var S_FRAMEBUFFER_WIDTH = S_FRAMEBUFFER + SUFFIX_WIDTH; |
|
var S_FRAMEBUFFER_HEIGHT = S_FRAMEBUFFER + SUFFIX_HEIGHT; |
|
var S_VIEWPORT_WIDTH = S_VIEWPORT + SUFFIX_WIDTH; |
|
var S_VIEWPORT_HEIGHT = S_VIEWPORT + SUFFIX_HEIGHT; |
|
var S_DRAWINGBUFFER = 'drawingBuffer'; |
|
var S_DRAWINGBUFFER_WIDTH = S_DRAWINGBUFFER + SUFFIX_WIDTH; |
|
var S_DRAWINGBUFFER_HEIGHT = S_DRAWINGBUFFER + SUFFIX_HEIGHT; |
|
|
|
var NESTED_OPTIONS = [ |
|
S_BLEND_FUNC, |
|
S_BLEND_EQUATION, |
|
S_STENCIL_FUNC, |
|
S_STENCIL_OPFRONT, |
|
S_STENCIL_OPBACK, |
|
S_SAMPLE_COVERAGE, |
|
S_VIEWPORT, |
|
S_SCISSOR_BOX, |
|
S_POLYGON_OFFSET_OFFSET |
|
]; |
|
|
|
var GL_ARRAY_BUFFER$1 = 34962; |
|
var GL_ELEMENT_ARRAY_BUFFER$1 = 34963; |
|
|
|
var GL_FRAGMENT_SHADER$1 = 35632; |
|
var GL_VERTEX_SHADER$1 = 35633; |
|
|
|
var GL_TEXTURE_2D$2 = 0x0DE1; |
|
var GL_TEXTURE_CUBE_MAP$1 = 0x8513; |
|
|
|
var GL_CULL_FACE = 0x0B44; |
|
var GL_BLEND = 0x0BE2; |
|
var GL_DITHER = 0x0BD0; |
|
var GL_STENCIL_TEST = 0x0B90; |
|
var GL_DEPTH_TEST = 0x0B71; |
|
var GL_SCISSOR_TEST = 0x0C11; |
|
var GL_POLYGON_OFFSET_FILL = 0x8037; |
|
var GL_SAMPLE_ALPHA_TO_COVERAGE = 0x809E; |
|
var GL_SAMPLE_COVERAGE = 0x80A0; |
|
|
|
var GL_FLOAT$7 = 5126; |
|
var GL_FLOAT_VEC2 = 35664; |
|
var GL_FLOAT_VEC3 = 35665; |
|
var GL_FLOAT_VEC4 = 35666; |
|
var GL_INT$3 = 5124; |
|
var GL_INT_VEC2 = 35667; |
|
var GL_INT_VEC3 = 35668; |
|
var GL_INT_VEC4 = 35669; |
|
var GL_BOOL = 35670; |
|
var GL_BOOL_VEC2 = 35671; |
|
var GL_BOOL_VEC3 = 35672; |
|
var GL_BOOL_VEC4 = 35673; |
|
var GL_FLOAT_MAT2 = 35674; |
|
var GL_FLOAT_MAT3 = 35675; |
|
var GL_FLOAT_MAT4 = 35676; |
|
var GL_SAMPLER_2D = 35678; |
|
var GL_SAMPLER_CUBE = 35680; |
|
|
|
var GL_TRIANGLES$1 = 4; |
|
|
|
var GL_FRONT = 1028; |
|
var GL_BACK = 1029; |
|
var GL_CW = 0x0900; |
|
var GL_CCW = 0x0901; |
|
var GL_MIN_EXT = 0x8007; |
|
var GL_MAX_EXT = 0x8008; |
|
var GL_ALWAYS = 519; |
|
var GL_KEEP = 7680; |
|
var GL_ZERO = 0; |
|
var GL_ONE = 1; |
|
var GL_FUNC_ADD = 0x8006; |
|
var GL_LESS = 513; |
|
|
|
var GL_FRAMEBUFFER$1 = 0x8D40; |
|
var GL_COLOR_ATTACHMENT0$1 = 0x8CE0; |
|
|
|
var blendFuncs = { |
|
'0': 0, |
|
'1': 1, |
|
'zero': 0, |
|
'one': 1, |
|
'src color': 768, |
|
'one minus src color': 769, |
|
'src alpha': 770, |
|
'one minus src alpha': 771, |
|
'dst color': 774, |
|
'one minus dst color': 775, |
|
'dst alpha': 772, |
|
'one minus dst alpha': 773, |
|
'constant color': 32769, |
|
'one minus constant color': 32770, |
|
'constant alpha': 32771, |
|
'one minus constant alpha': 32772, |
|
'src alpha saturate': 776 |
|
}; |
|
|
|
// There are invalid values for srcRGB and dstRGB. See: |
|
// https://www.khronos.org/registry/webgl/specs/1.0/#6.13 |
|
// https://github.com/KhronosGroup/WebGL/blob/0d3201f5f7ec3c0060bc1f04077461541f1987b9/conformance-suites/1.0.3/conformance/misc/webgl-specific.html#L56 |
|
var invalidBlendCombinations = [ |
|
'constant color, constant alpha', |
|
'one minus constant color, constant alpha', |
|
'constant color, one minus constant alpha', |
|
'one minus constant color, one minus constant alpha', |
|
'constant alpha, constant color', |
|
'constant alpha, one minus constant color', |
|
'one minus constant alpha, constant color', |
|
'one minus constant alpha, one minus constant color' |
|
]; |
|
|
|
var compareFuncs = { |
|
'never': 512, |
|
'less': 513, |
|
'<': 513, |
|
'equal': 514, |
|
'=': 514, |
|
'==': 514, |
|
'===': 514, |
|
'lequal': 515, |
|
'<=': 515, |
|
'greater': 516, |
|
'>': 516, |
|
'notequal': 517, |
|
'!=': 517, |
|
'!==': 517, |
|
'gequal': 518, |
|
'>=': 518, |
|
'always': 519 |
|
}; |
|
|
|
var stencilOps = { |
|
'0': 0, |
|
'zero': 0, |
|
'keep': 7680, |
|
'replace': 7681, |
|
'increment': 7682, |
|
'decrement': 7683, |
|
'increment wrap': 34055, |
|
'decrement wrap': 34056, |
|
'invert': 5386 |
|
}; |
|
|
|
var shaderType = { |
|
'frag': GL_FRAGMENT_SHADER$1, |
|
'vert': GL_VERTEX_SHADER$1 |
|
}; |
|
|
|
var orientationType = { |
|
'cw': GL_CW, |
|
'ccw': GL_CCW |
|
}; |
|
|
|
function isBufferArgs (x) { |
|
return Array.isArray(x) || |
|
isTypedArray(x) || |
|
isNDArrayLike(x) |
|
} |
|
|
|
// Make sure viewport is processed first |
|
function sortState (state) { |
|
return state.sort(function (a, b) { |
|
if (a === S_VIEWPORT) { |
|
return -1 |
|
} else if (b === S_VIEWPORT) { |
|
return 1 |
|
} |
|
return (a < b) ? -1 : 1 |
|
}) |
|
} |
|
|
|
function Declaration (thisDep, contextDep, propDep, append) { |
|
this.thisDep = thisDep; |
|
this.contextDep = contextDep; |
|
this.propDep = propDep; |
|
this.append = append; |
|
} |
|
|
|
function isStatic (decl) { |
|
return decl && !(decl.thisDep || decl.contextDep || decl.propDep) |
|
} |
|
|
|
function createStaticDecl (append) { |
|
return new Declaration(false, false, false, append) |
|
} |
|
|
|
function createDynamicDecl (dyn, append) { |
|
var type = dyn.type; |
|
if (type === DYN_FUNC$1) { |
|
var numArgs = dyn.data.length; |
|
return new Declaration( |
|
true, |
|
numArgs >= 1, |
|
numArgs >= 2, |
|
append) |
|
} else if (type === DYN_THUNK) { |
|
var data = dyn.data; |
|
return new Declaration( |
|
data.thisDep, |
|
data.contextDep, |
|
data.propDep, |
|
append) |
|
} else { |
|
return new Declaration( |
|
type === DYN_STATE$1, |
|
type === DYN_CONTEXT$1, |
|
type === DYN_PROP$1, |
|
append) |
|
} |
|
} |
|
|
|
var SCOPE_DECL = new Declaration(false, false, false, function () {}); |
|
|
|
function reglCore ( |
|
gl, |
|
stringStore, |
|
extensions, |
|
limits, |
|
bufferState, |
|
elementState, |
|
textureState, |
|
framebufferState, |
|
uniformState, |
|
attributeState, |
|
shaderState, |
|
drawState, |
|
contextState, |
|
timer, |
|
config) { |
|
var AttributeRecord = attributeState.Record; |
|
|
|
var blendEquations = { |
|
'add': 32774, |
|
'subtract': 32778, |
|
'reverse subtract': 32779 |
|
}; |
|
if (extensions.ext_blend_minmax) { |
|
blendEquations.min = GL_MIN_EXT; |
|
blendEquations.max = GL_MAX_EXT; |
|
} |
|
|
|
var extInstancing = extensions.angle_instanced_arrays; |
|
var extDrawBuffers = extensions.webgl_draw_buffers; |
|
|
|
// =================================================== |
|
// =================================================== |
|
// WEBGL STATE |
|
// =================================================== |
|
// =================================================== |
|
var currentState = { |
|
dirty: true, |
|
profile: config.profile |
|
}; |
|
var nextState = {}; |
|
var GL_STATE_NAMES = []; |
|
var GL_FLAGS = {}; |
|
var GL_VARIABLES = {}; |
|
|
|
function propName (name) { |
|
return name.replace('.', '_') |
|
} |
|
|
|
function stateFlag (sname, cap, init) { |
|
var name = propName(sname); |
|
GL_STATE_NAMES.push(sname); |
|
nextState[name] = currentState[name] = !!init; |
|
GL_FLAGS[name] = cap; |
|
} |
|
|
|
function stateVariable (sname, func, init) { |
|
var name = propName(sname); |
|
GL_STATE_NAMES.push(sname); |
|
if (Array.isArray(init)) { |
|
currentState[name] = init.slice(); |
|
nextState[name] = init.slice(); |
|
} else { |
|
currentState[name] = nextState[name] = init; |
|
} |
|
GL_VARIABLES[name] = func; |
|
} |
|
|
|
// Dithering |
|
stateFlag(S_DITHER, GL_DITHER); |
|
|
|
// Blending |
|
stateFlag(S_BLEND_ENABLE, GL_BLEND); |
|
stateVariable(S_BLEND_COLOR, 'blendColor', [0, 0, 0, 0]); |
|
stateVariable(S_BLEND_EQUATION, 'blendEquationSeparate', |
|
[GL_FUNC_ADD, GL_FUNC_ADD]); |
|
stateVariable(S_BLEND_FUNC, 'blendFuncSeparate', |
|
[GL_ONE, GL_ZERO, GL_ONE, GL_ZERO]); |
|
|
|
// Depth |
|
stateFlag(S_DEPTH_ENABLE, GL_DEPTH_TEST, true); |
|
stateVariable(S_DEPTH_FUNC, 'depthFunc', GL_LESS); |
|
stateVariable(S_DEPTH_RANGE, 'depthRange', [0, 1]); |
|
stateVariable(S_DEPTH_MASK, 'depthMask', true); |
|
|
|
// Color mask |
|
stateVariable(S_COLOR_MASK, S_COLOR_MASK, [true, true, true, true]); |
|
|
|
// Face culling |
|
stateFlag(S_CULL_ENABLE, GL_CULL_FACE); |
|
stateVariable(S_CULL_FACE, 'cullFace', GL_BACK); |
|
|
|
// Front face orientation |
|
stateVariable(S_FRONT_FACE, S_FRONT_FACE, GL_CCW); |
|
|
|
// Line width |
|
stateVariable(S_LINE_WIDTH, S_LINE_WIDTH, 1); |
|
|
|
// Polygon offset |
|
stateFlag(S_POLYGON_OFFSET_ENABLE, GL_POLYGON_OFFSET_FILL); |
|
stateVariable(S_POLYGON_OFFSET_OFFSET, 'polygonOffset', [0, 0]); |
|
|
|
// Sample coverage |
|
stateFlag(S_SAMPLE_ALPHA, GL_SAMPLE_ALPHA_TO_COVERAGE); |
|
stateFlag(S_SAMPLE_ENABLE, GL_SAMPLE_COVERAGE); |
|
stateVariable(S_SAMPLE_COVERAGE, 'sampleCoverage', [1, false]); |
|
|
|
// Stencil |
|
stateFlag(S_STENCIL_ENABLE, GL_STENCIL_TEST); |
|
stateVariable(S_STENCIL_MASK, 'stencilMask', -1); |
|
stateVariable(S_STENCIL_FUNC, 'stencilFunc', [GL_ALWAYS, 0, -1]); |
|
stateVariable(S_STENCIL_OPFRONT, 'stencilOpSeparate', |
|
[GL_FRONT, GL_KEEP, GL_KEEP, GL_KEEP]); |
|
stateVariable(S_STENCIL_OPBACK, 'stencilOpSeparate', |
|
[GL_BACK, GL_KEEP, GL_KEEP, GL_KEEP]); |
|
|
|
// Scissor |
|
stateFlag(S_SCISSOR_ENABLE, GL_SCISSOR_TEST); |
|
stateVariable(S_SCISSOR_BOX, 'scissor', |
|
[0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight]); |
|
|
|
// Viewport |
|
stateVariable(S_VIEWPORT, S_VIEWPORT, |
|
[0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight]); |
|
|
|
// =================================================== |
|
// =================================================== |
|
// ENVIRONMENT |
|
// =================================================== |
|
// =================================================== |
|
var sharedState = { |
|
gl: gl, |
|
context: contextState, |
|
strings: stringStore, |
|
next: nextState, |
|
current: currentState, |
|
draw: drawState, |
|
elements: elementState, |
|
buffer: bufferState, |
|
shader: shaderState, |
|
attributes: attributeState.state, |
|
uniforms: uniformState, |
|
framebuffer: framebufferState, |
|
extensions: extensions, |
|
|
|
timer: timer, |
|
isBufferArgs: isBufferArgs |
|
}; |
|
|
|
var sharedConstants = { |
|
primTypes: primTypes, |
|
compareFuncs: compareFuncs, |
|
blendFuncs: blendFuncs, |
|
blendEquations: blendEquations, |
|
stencilOps: stencilOps, |
|
glTypes: glTypes, |
|
orientationType: orientationType |
|
}; |
|
|
|
check$1.optional(function () { |
|
sharedState.isArrayLike = isArrayLike; |
|
}); |
|
|
|
if (extDrawBuffers) { |
|
sharedConstants.backBuffer = [GL_BACK]; |
|
sharedConstants.drawBuffer = loop(limits.maxDrawbuffers, function (i) { |
|
if (i === 0) { |
|
return [0] |
|
} |
|
return loop(i, function (j) { |
|
return GL_COLOR_ATTACHMENT0$1 + j |
|
}) |
|
}); |
|
} |
|
|
|
var drawCallCounter = 0; |
|
function createREGLEnvironment () { |
|
var env = createEnvironment(); |
|
var link = env.link; |
|
var global = env.global; |
|
env.id = drawCallCounter++; |
|
|
|
env.batchId = '0'; |
|
|
|
// link shared state |
|
var SHARED = link(sharedState); |
|
var shared = env.shared = { |
|
props: 'a0' |
|
}; |
|
Object.keys(sharedState).forEach(function (prop) { |
|
shared[prop] = global.def(SHARED, '.', prop); |
|
}); |
|
|
|
// Inject runtime assertion stuff for debug builds |
|
check$1.optional(function () { |
|
env.CHECK = link(check$1); |
|
env.commandStr = check$1.guessCommand(); |
|
env.command = link(env.commandStr); |
|
env.assert = function (block, pred, message) { |
|
block( |
|
'if(!(', pred, '))', |
|
this.CHECK, '.commandRaise(', link(message), ',', this.command, ');'); |
|
}; |
|
|
|
sharedConstants.invalidBlendCombinations = invalidBlendCombinations; |
|
}); |
|
|
|
// Copy GL state variables over |
|
var nextVars = env.next = {}; |
|
var currentVars = env.current = {}; |
|
Object.keys(GL_VARIABLES).forEach(function (variable) { |
|
if (Array.isArray(currentState[variable])) { |
|
nextVars[variable] = global.def(shared.next, '.', variable); |
|
currentVars[variable] = global.def(shared.current, '.', variable); |
|
} |
|
}); |
|
|
|
// Initialize shared constants |
|
var constants = env.constants = {}; |
|
Object.keys(sharedConstants).forEach(function (name) { |
|
constants[name] = global.def(JSON.stringify(sharedConstants[name])); |
|
}); |
|
|
|
// Helper function for calling a block |
|
env.invoke = function (block, x) { |
|
switch (x.type) { |
|
case DYN_FUNC$1: |
|
var argList = [ |
|
'this', |
|
shared.context, |
|
shared.props, |
|
env.batchId |
|
]; |
|
return block.def( |
|
link(x.data), '.call(', |
|
argList.slice(0, Math.max(x.data.length + 1, 4)), |
|
')') |
|
case DYN_PROP$1: |
|
return block.def(shared.props, x.data) |
|
case DYN_CONTEXT$1: |
|
return block.def(shared.context, x.data) |
|
case DYN_STATE$1: |
|
return block.def('this', x.data) |
|
case DYN_THUNK: |
|
x.data.append(env, block); |
|
return x.data.ref |
|
} |
|
}; |
|
|
|
env.attribCache = {}; |
|
|
|
var scopeAttribs = {}; |
|
env.scopeAttrib = function (name) { |
|
var id = stringStore.id(name); |
|
if (id in scopeAttribs) { |
|
return scopeAttribs[id] |
|
} |
|
var binding = attributeState.scope[id]; |
|
if (!binding) { |
|
binding = attributeState.scope[id] = new AttributeRecord(); |
|
} |
|
var result = scopeAttribs[id] = link(binding); |
|
return result |
|
}; |
|
|
|
return env |
|
} |
|
|
|
// =================================================== |
|
// =================================================== |
|
// PARSING |
|
// =================================================== |
|
// =================================================== |
|
function parseProfile (options) { |
|
var staticOptions = options.static; |
|
var dynamicOptions = options.dynamic; |
|
|
|
var profileEnable; |
|
if (S_PROFILE in staticOptions) { |
|
var value = !!staticOptions[S_PROFILE]; |
|
profileEnable = createStaticDecl(function (env, scope) { |
|
return value |
|
}); |
|
profileEnable.enable = value; |
|
} else if (S_PROFILE in dynamicOptions) { |
|
var dyn = dynamicOptions[S_PROFILE]; |
|
profileEnable = createDynamicDecl(dyn, function (env, scope) { |
|
return env.invoke(scope, dyn) |
|
}); |
|
} |
|
|
|
return profileEnable |
|
} |
|
|
|
function parseFramebuffer (options, env) { |
|
var staticOptions = options.static; |
|
var dynamicOptions = options.dynamic; |
|
|
|
if (S_FRAMEBUFFER in staticOptions) { |
|
var framebuffer = staticOptions[S_FRAMEBUFFER]; |
|
if (framebuffer) { |
|
framebuffer = framebufferState.getFramebuffer(framebuffer); |
|
check$1.command(framebuffer, 'invalid framebuffer object'); |
|
return createStaticDecl(function (env, block) { |
|
var FRAMEBUFFER = env.link(framebuffer); |
|
var shared = env.shared; |
|
block.set( |
|
shared.framebuffer, |
|
'.next', |
|
FRAMEBUFFER); |
|
var CONTEXT = shared.context; |
|
block.set( |
|
CONTEXT, |
|
'.' + S_FRAMEBUFFER_WIDTH, |
|
FRAMEBUFFER + '.width'); |
|
block.set( |
|
CONTEXT, |
|
'.' + S_FRAMEBUFFER_HEIGHT, |
|
FRAMEBUFFER + '.height'); |
|
return FRAMEBUFFER |
|
}) |
|
} else { |
|
return createStaticDecl(function (env, scope) { |
|
var shared = env.shared; |
|
scope.set( |
|
shared.framebuffer, |
|
'.next', |
|
'null'); |
|
var CONTEXT = shared.context; |
|
scope.set( |
|
CONTEXT, |
|
'.' + S_FRAMEBUFFER_WIDTH, |
|
CONTEXT + '.' + S_DRAWINGBUFFER_WIDTH); |
|
scope.set( |
|
CONTEXT, |
|
'.' + S_FRAMEBUFFER_HEIGHT, |
|
CONTEXT + '.' + S_DRAWINGBUFFER_HEIGHT); |
|
return 'null' |
|
}) |
|
} |
|
} else if (S_FRAMEBUFFER in dynamicOptions) { |
|
var dyn = dynamicOptions[S_FRAMEBUFFER]; |
|
return createDynamicDecl(dyn, function (env, scope) { |
|
var FRAMEBUFFER_FUNC = env.invoke(scope, dyn); |
|
var shared = env.shared; |
|
var FRAMEBUFFER_STATE = shared.framebuffer; |
|
var FRAMEBUFFER = scope.def( |
|
FRAMEBUFFER_STATE, '.getFramebuffer(', FRAMEBUFFER_FUNC, ')'); |
|
|
|
check$1.optional(function () { |
|
env.assert(scope, |
|
'!' + FRAMEBUFFER_FUNC + '||' + FRAMEBUFFER, |
|
'invalid framebuffer object'); |
|
}); |
|
|
|
scope.set( |
|
FRAMEBUFFER_STATE, |
|
'.next', |
|
FRAMEBUFFER); |
|
var CONTEXT = shared.context; |
|
scope.set( |
|
CONTEXT, |
|
'.' + S_FRAMEBUFFER_WIDTH, |
|
FRAMEBUFFER + '?' + FRAMEBUFFER + '.width:' + |
|
CONTEXT + '.' + S_DRAWINGBUFFER_WIDTH); |
|
scope.set( |
|
CONTEXT, |
|
'.' + S_FRAMEBUFFER_HEIGHT, |
|
FRAMEBUFFER + |
|
'?' + FRAMEBUFFER + '.height:' + |
|
CONTEXT + '.' + S_DRAWINGBUFFER_HEIGHT); |
|
return FRAMEBUFFER |
|
}) |
|
} else { |
|
return null |
|
} |
|
} |
|
|
|
function parseViewportScissor (options, framebuffer, env) { |
|
var staticOptions = options.static; |
|
var dynamicOptions = options.dynamic; |
|
|
|
function parseBox (param) { |
|
if (param in staticOptions) { |
|
var box = staticOptions[param]; |
|
check$1.commandType(box, 'object', 'invalid ' + param, env.commandStr); |
|
|
|
var isStatic = true; |
|
var x = box.x | 0; |
|
var y = box.y | 0; |
|
var w, h; |
|
if ('width' in box) { |
|
w = box.width | 0; |
|
check$1.command(w >= 0, 'invalid ' + param, env.commandStr); |
|
} else { |
|
isStatic = false; |
|
} |
|
if ('height' in box) { |
|
h = box.height | 0; |
|
check$1.command(h >= 0, 'invalid ' + param, env.commandStr); |
|
} else { |
|
isStatic = false; |
|
} |
|
|
|
return new Declaration( |
|
!isStatic && framebuffer && framebuffer.thisDep, |
|
!isStatic && framebuffer && framebuffer.contextDep, |
|
!isStatic && framebuffer && framebuffer.propDep, |
|
function (env, scope) { |
|
var CONTEXT = env.shared.context; |
|
var BOX_W = w; |
|
if (!('width' in box)) { |
|
BOX_W = scope.def(CONTEXT, '.', S_FRAMEBUFFER_WIDTH, '-', x); |
|
} |
|
var BOX_H = h; |
|
if (!('height' in box)) { |
|
BOX_H = scope.def(CONTEXT, '.', S_FRAMEBUFFER_HEIGHT, '-', y); |
|
} |
|
return [x, y, BOX_W, BOX_H] |
|
}) |
|
} else if (param in dynamicOptions) { |
|
var dynBox = dynamicOptions[param]; |
|
var result = createDynamicDecl(dynBox, function (env, scope) { |
|
var BOX = env.invoke(scope, dynBox); |
|
|
|
check$1.optional(function () { |
|
env.assert(scope, |
|
BOX + '&&typeof ' + BOX + '==="object"', |
|
'invalid ' + param); |
|
}); |
|
|
|
var CONTEXT = env.shared.context; |
|
var BOX_X = scope.def(BOX, '.x|0'); |
|
var BOX_Y = scope.def(BOX, '.y|0'); |
|
var BOX_W = scope.def( |
|
'"width" in ', BOX, '?', BOX, '.width|0:', |
|
'(', CONTEXT, '.', S_FRAMEBUFFER_WIDTH, '-', BOX_X, ')'); |
|
var BOX_H = scope.def( |
|
'"height" in ', BOX, '?', BOX, '.height|0:', |
|
'(', CONTEXT, '.', S_FRAMEBUFFER_HEIGHT, '-', BOX_Y, ')'); |
|
|
|
check$1.optional(function () { |
|
env.assert(scope, |
|
BOX_W + '>=0&&' + |
|
BOX_H + '>=0', |
|
'invalid ' + param); |
|
}); |
|
|
|
return [BOX_X, BOX_Y, BOX_W, BOX_H] |
|
}); |
|
if (framebuffer) { |
|
result.thisDep = result.thisDep || framebuffer.thisDep; |
|
result.contextDep = result.contextDep || framebuffer.contextDep; |
|
result.propDep = result.propDep || framebuffer.propDep; |
|
} |
|
return result |
|
} else if (framebuffer) { |
|
return new Declaration( |
|
framebuffer.thisDep, |
|
framebuffer.contextDep, |
|
framebuffer.propDep, |
|
function (env, scope) { |
|
var CONTEXT = env.shared.context; |
|
return [ |
|
0, 0, |
|
scope.def(CONTEXT, '.', S_FRAMEBUFFER_WIDTH), |
|
scope.def(CONTEXT, '.', S_FRAMEBUFFER_HEIGHT)] |
|
}) |
|
} else { |
|
return null |
|
} |
|
} |
|
|
|
var viewport = parseBox(S_VIEWPORT); |
|
|
|
if (viewport) { |
|
var prevViewport = viewport; |
|
viewport = new Declaration( |
|
viewport.thisDep, |
|
viewport.contextDep, |
|
viewport.propDep, |
|
function (env, scope) { |
|
var VIEWPORT = prevViewport.append(env, scope); |
|
var CONTEXT = env.shared.context; |
|
scope.set( |
|
CONTEXT, |
|
'.' + S_VIEWPORT_WIDTH, |
|
VIEWPORT[2]); |
|
scope.set( |
|
CONTEXT, |
|
'.' + S_VIEWPORT_HEIGHT, |
|
VIEWPORT[3]); |
|
return VIEWPORT |
|
}); |
|
} |
|
|
|
return { |
|
viewport: viewport, |
|
scissor_box: parseBox(S_SCISSOR_BOX) |
|
} |
|
} |
|
|
|
function parseProgram (options) { |
|
var staticOptions = options.static; |
|
var dynamicOptions = options.dynamic; |
|
|
|
function parseShader (name) { |
|
if (name in staticOptions) { |
|
var id = stringStore.id(staticOptions[name]); |
|
check$1.optional(function () { |
|
shaderState.shader(shaderType[name], id, check$1.guessCommand()); |
|
}); |
|
var result = createStaticDecl(function () { |
|
return id |
|
}); |
|
result.id = id; |
|
return result |
|
} else if (name in dynamicOptions) { |
|
var dyn = dynamicOptions[name]; |
|
return createDynamicDecl(dyn, function (env, scope) { |
|
var str = env.invoke(scope, dyn); |
|
var id = scope.def(env.shared.strings, '.id(', str, ')'); |
|
check$1.optional(function () { |
|
scope( |
|
env.shared.shader, '.shader(', |
|
shaderType[name], ',', |
|
id, ',', |
|
env.command, ');'); |
|
}); |
|
return id |
|
}) |
|
} |
|
return null |
|
} |
|
|
|
var frag = parseShader(S_FRAG); |
|
var vert = parseShader(S_VERT); |
|
|
|
var program = null; |
|
var progVar; |
|
if (isStatic(frag) && isStatic(vert)) { |
|
program = shaderState.program(vert.id, frag.id); |
|
progVar = createStaticDecl(function (env, scope) { |
|
return env.link(program) |
|
}); |
|
} else { |
|
progVar = new Declaration( |
|
(frag && frag.thisDep) || (vert && vert.thisDep), |
|
(frag && frag.contextDep) || (vert && vert.contextDep), |
|
(frag && frag.propDep) || (vert && vert.propDep), |
|
function (env, scope) { |
|
var SHADER_STATE = env.shared.shader; |
|
var fragId; |
|
if (frag) { |
|
fragId = frag.append(env, scope); |
|
} else { |
|
fragId = scope.def(SHADER_STATE, '.', S_FRAG); |
|
} |
|
var vertId; |
|
if (vert) { |
|
vertId = vert.append(env, scope); |
|
} else { |
|
vertId = scope.def(SHADER_STATE, '.', S_VERT); |
|
} |
|
var progDef = SHADER_STATE + '.program(' + vertId + ',' + fragId; |
|
check$1.optional(function () { |
|
progDef += ',' + env.command; |
|
}); |
|
return scope.def(progDef + ')') |
|
}); |
|
} |
|
|
|
return { |
|
frag: frag, |
|
vert: vert, |
|
progVar: progVar, |
|
program: program |
|
} |
|
} |
|
|
|
function parseDraw (options, env) { |
|
var staticOptions = options.static; |
|
var dynamicOptions = options.dynamic; |
|
|
|
function parseElements () { |
|
if (S_ELEMENTS in staticOptions) { |
|
var elements = staticOptions[S_ELEMENTS]; |
|
if (isBufferArgs(elements)) { |
|
elements = elementState.getElements(elementState.create(elements, true)); |
|
} else if (elements) { |
|
elements = elementState.getElements(elements); |
|
check$1.command(elements, 'invalid elements', env.commandStr); |
|
} |
|
var result = createStaticDecl(function (env, scope) { |
|
if (elements) { |
|
var result = env.link(elements); |
|
env.ELEMENTS = result; |
|
return result |
|
} |
|
env.ELEMENTS = null; |
|
return null |
|
}); |
|
result.value = elements; |
|
return result |
|
} else if (S_ELEMENTS in dynamicOptions) { |
|
var dyn = dynamicOptions[S_ELEMENTS]; |
|
return createDynamicDecl(dyn, function (env, scope) { |
|
var shared = env.shared; |
|
|
|
var IS_BUFFER_ARGS = shared.isBufferArgs; |
|
var ELEMENT_STATE = shared.elements; |
|
|
|
var elementDefn = env.invoke(scope, dyn); |
|
var elements = scope.def('null'); |
|
var elementStream = scope.def(IS_BUFFER_ARGS, '(', elementDefn, ')'); |
|
|
|
var ifte = env.cond(elementStream) |
|
.then(elements, '=', ELEMENT_STATE, '.createStream(', elementDefn, ');') |
|
.else(elements, '=', ELEMENT_STATE, '.getElements(', elementDefn, ');'); |
|
|
|
check$1.optional(function () { |
|
env.assert(ifte.else, |
|
'!' + elementDefn + '||' + elements, |
|
'invalid elements'); |
|
}); |
|
|
|
scope.entry(ifte); |
|
scope.exit( |
|
env.cond(elementStream) |
|
.then(ELEMENT_STATE, '.destroyStream(', elements, ');')); |
|
|
|
env.ELEMENTS = elements; |
|
|
|
return elements |
|
}) |
|
} |
|
|
|
return null |
|
} |
|
|
|
var elements = parseElements(); |
|
|
|
function parsePrimitive () { |
|
if (S_PRIMITIVE in staticOptions) { |
|
var primitive = staticOptions[S_PRIMITIVE]; |
|
check$1.commandParameter(primitive, primTypes, 'invalid primitve', env.commandStr); |
|
return createStaticDecl(function (env, scope) { |
|
return primTypes[primitive] |
|
}) |
|
} else if (S_PRIMITIVE in dynamicOptions) { |
|
var dynPrimitive = dynamicOptions[S_PRIMITIVE]; |
|
return createDynamicDecl(dynPrimitive, function (env, scope) { |
|
var PRIM_TYPES = env.constants.primTypes; |
|
var prim = env.invoke(scope, dynPrimitive); |
|
check$1.optional(function () { |
|
env.assert(scope, |
|
prim + ' in ' + PRIM_TYPES, |
|
'invalid primitive, must be one of ' + Object.keys(primTypes)); |
|
}); |
|
return scope.def(PRIM_TYPES, '[', prim, ']') |
|
}) |
|
} else if (elements) { |
|
if (isStatic(elements)) { |
|
if (elements.value) { |
|
return createStaticDecl(function (env, scope) { |
|
return scope.def(env.ELEMENTS, '.primType') |
|
}) |
|
} else { |
|
return createStaticDecl(function () { |
|
return GL_TRIANGLES$1 |
|
}) |
|
} |
|
} else { |
|
return new Declaration( |
|
elements.thisDep, |
|
elements.contextDep, |
|
elements.propDep, |
|
function (env, scope) { |
|
var elements = env.ELEMENTS; |
|
return scope.def(elements, '?', elements, '.primType:', GL_TRIANGLES$1) |
|
}) |
|
} |
|
} |
|
return null |
|
} |
|
|
|
function parseParam (param, isOffset) { |
|
if (param in staticOptions) { |
|
var value = staticOptions[param] | 0; |
|
check$1.command(!isOffset || value >= 0, 'invalid ' + param, env.commandStr); |
|
return createStaticDecl(function (env, scope) { |
|
if (isOffset) { |
|
env.OFFSET = value; |
|
} |
|
return value |
|
}) |
|
} else if (param in dynamicOptions) { |
|
var dynValue = dynamicOptions[param]; |
|
return createDynamicDecl(dynValue, function (env, scope) { |
|
var result = env.invoke(scope, dynValue); |
|
if (isOffset) { |
|
env.OFFSET = result; |
|
check$1.optional(function () { |
|
env.assert(scope, |
|
result + '>=0', |
|
'invalid ' + param); |
|
}); |
|
} |
|
return result |
|
}) |
|
} else if (isOffset && elements) { |
|
return createStaticDecl(function (env, scope) { |
|
env.OFFSET = '0'; |
|
return 0 |
|
}) |
|
} |
|
return null |
|
} |
|
|
|
var OFFSET = parseParam(S_OFFSET, true); |
|
|
|
function parseVertCount () { |
|
if (S_COUNT in staticOptions) { |
|
var count = staticOptions[S_COUNT] | 0; |
|
check$1.command( |
|
typeof count === 'number' && count >= 0, 'invalid vertex count', env.commandStr); |
|
return createStaticDecl(function () { |
|
return count |
|
}) |
|
} else if (S_COUNT in dynamicOptions) { |
|
var dynCount = dynamicOptions[S_COUNT]; |
|
return createDynamicDecl(dynCount, function (env, scope) { |
|
var result = env.invoke(scope, dynCount); |
|
check$1.optional(function () { |
|
env.assert(scope, |
|
'typeof ' + result + '==="number"&&' + |
|
result + '>=0&&' + |
|
result + '===(' + result + '|0)', |
|
'invalid vertex count'); |
|
}); |
|
return result |
|
}) |
|
} else if (elements) { |
|
if (isStatic(elements)) { |
|
if (elements) { |
|
if (OFFSET) { |
|
return new Declaration( |
|
OFFSET.thisDep, |
|
OFFSET.contextDep, |
|
OFFSET.propDep, |
|
function (env, scope) { |
|
var result = scope.def( |
|
env.ELEMENTS, '.vertCount-', env.OFFSET); |
|
|
|
check$1.optional(function () { |
|
env.assert(scope, |
|
result + '>=0', |
|
'invalid vertex offset/element buffer too small'); |
|
}); |
|
|
|
return result |
|
}) |
|
} else { |
|
return createStaticDecl(function (env, scope) { |
|
return scope.def(env.ELEMENTS, '.vertCount') |
|
}) |
|
} |
|
} else { |
|
var result = createStaticDecl(function () { |
|
return -1 |
|
}); |
|
check$1.optional(function () { |
|
result.MISSING = true; |
|
}); |
|
return result |
|
} |
|
} else { |
|
var variable = new Declaration( |
|
elements.thisDep || OFFSET.thisDep, |
|
elements.contextDep || OFFSET.contextDep, |
|
elements.propDep || OFFSET.propDep, |
|
function (env, scope) { |
|
var elements = env.ELEMENTS; |
|
if (env.OFFSET) { |
|
return scope.def(elements, '?', elements, '.vertCount-', |
|
env.OFFSET, ':-1') |
|
} |
|
return scope.def(elements, '?', elements, '.vertCount:-1') |
|
}); |
|
check$1.optional(function () { |
|
variable.DYNAMIC = true; |
|
}); |
|
return variable |
|
} |
|
} |
|
return null |
|
} |
|
|
|
return { |
|
elements: elements, |
|
primitive: parsePrimitive(), |
|
count: parseVertCount(), |
|
instances: parseParam(S_INSTANCES, false), |
|
offset: OFFSET |
|
} |
|
} |
|
|
|
function parseGLState (options, env) { |
|
var staticOptions = options.static; |
|
var dynamicOptions = options.dynamic; |
|
|
|
var STATE = {}; |
|
|
|
GL_STATE_NAMES.forEach(function (prop) { |
|
var param = propName(prop); |
|
|
|
function parseParam (parseStatic, parseDynamic) { |
|
if (prop in staticOptions) { |
|
var value = parseStatic(staticOptions[prop]); |
|
STATE[param] = createStaticDecl(function () { |
|
return value |
|
}); |
|
} else if (prop in dynamicOptions) { |
|
var dyn = dynamicOptions[prop]; |
|
STATE[param] = createDynamicDecl(dyn, function (env, scope) { |
|
return parseDynamic(env, scope, env.invoke(scope, dyn)) |
|
}); |
|
} |
|
} |
|
|
|
switch (prop) { |
|
case S_CULL_ENABLE: |
|
case S_BLEND_ENABLE: |
|
case S_DITHER: |
|
case S_STENCIL_ENABLE: |
|
case S_DEPTH_ENABLE: |
|
case S_SCISSOR_ENABLE: |
|
case S_POLYGON_OFFSET_ENABLE: |
|
case S_SAMPLE_ALPHA: |
|
case S_SAMPLE_ENABLE: |
|
case S_DEPTH_MASK: |
|
return parseParam( |
|
function (value) { |
|
check$1.commandType(value, 'boolean', prop, env.commandStr); |
|
return value |
|
}, |
|
function (env, scope, value) { |
|
check$1.optional(function () { |
|
env.assert(scope, |
|
'typeof ' + value + '==="boolean"', |
|
'invalid flag ' + prop, env.commandStr); |
|
}); |
|
return value |
|
}) |
|
|
|
case S_DEPTH_FUNC: |
|
return parseParam( |
|
function (value) { |
|
check$1.commandParameter(value, compareFuncs, 'invalid ' + prop, env.commandStr); |
|
return compareFuncs[value] |
|
}, |
|
function (env, scope, value) { |
|
var COMPARE_FUNCS = env.constants.compareFuncs; |
|
check$1.optional(function () { |
|
env.assert(scope, |
|
value + ' in ' + COMPARE_FUNCS, |
|
'invalid ' + prop + ', must be one of ' + Object.keys(compareFuncs)); |
|
}); |
|
return scope.def(COMPARE_FUNCS, '[', value, ']') |
|
}) |
|
|
|
case S_DEPTH_RANGE: |
|
return parseParam( |
|
function (value) { |
|
check$1.command( |
|
isArrayLike(value) && |
|
value.length === 2 && |
|
typeof value[0] === 'number' && |
|
typeof value[1] === 'number' && |
|
value[0] <= value[1], |
|
'depth range is 2d array', |
|
env.commandStr); |
|
return value |
|
}, |
|
function (env, scope, value) { |
|
check$1.optional(function () { |
|
env.assert(scope, |
|
env.shared.isArrayLike + '(' + value + ')&&' + |
|
value + '.length===2&&' + |
|
'typeof ' + value + '[0]==="number"&&' + |
|
'typeof ' + value + '[1]==="number"&&' + |
|
value + '[0]<=' + value + '[1]', |
|
'depth range must be a 2d array'); |
|
}); |
|
|
|
var Z_NEAR = scope.def('+', value, '[0]'); |
|
var Z_FAR = scope.def('+', value, '[1]'); |
|
return [Z_NEAR, Z_FAR] |
|
}) |
|
|
|
case S_BLEND_FUNC: |
|
return parseParam( |
|
function (value) { |
|
check$1.commandType(value, 'object', 'blend.func', env.commandStr); |
|
var srcRGB = ('srcRGB' in value ? value.srcRGB : value.src); |
|
var srcAlpha = ('srcAlpha' in value ? value.srcAlpha : value.src); |
|
var dstRGB = ('dstRGB' in value ? value.dstRGB : value.dst); |
|
var dstAlpha = ('dstAlpha' in value ? value.dstAlpha : value.dst); |
|
check$1.commandParameter(srcRGB, blendFuncs, param + '.srcRGB', env.commandStr); |
|
check$1.commandParameter(srcAlpha, blendFuncs, param + '.srcAlpha', env.commandStr); |
|
check$1.commandParameter(dstRGB, blendFuncs, param + '.dstRGB', env.commandStr); |
|
check$1.commandParameter(dstAlpha, blendFuncs, param + '.dstAlpha', env.commandStr); |
|
|
|
check$1.command( |
|
(invalidBlendCombinations.indexOf(srcRGB + ', ' + dstRGB) === -1), |
|
'unallowed blending combination (srcRGB, dstRGB) = (' + srcRGB + ', ' + dstRGB + ')', env.commandStr); |
|
|
|
return [ |
|
blendFuncs[srcRGB], |
|
blendFuncs[dstRGB], |
|
blendFuncs[srcAlpha], |
|
blendFuncs[dstAlpha] |
|
] |
|
}, |
|
function (env, scope, value) { |
|
var BLEND_FUNCS = env.constants.blendFuncs; |
|
|
|
check$1.optional(function () { |
|
env.assert(scope, |
|
value + '&&typeof ' + value + '==="object"', |
|
'invalid blend func, must be an object'); |
|
}); |
|
|
|
function read (prefix, suffix) { |
|
var func = scope.def( |
|
'"', prefix, suffix, '" in ', value, |
|
'?', value, '.', prefix, suffix, |
|
':', value, '.', prefix); |
|
|
|
check$1.optional(function () { |
|
env.assert(scope, |
|
func + ' in ' + BLEND_FUNCS, |
|
'invalid ' + prop + '.' + prefix + suffix + ', must be one of ' + Object.keys(blendFuncs)); |
|
}); |
|
|
|
return func |
|
} |
|
|
|
var srcRGB = read('src', 'RGB'); |
|
var dstRGB = read('dst', 'RGB'); |
|
|
|
check$1.optional(function () { |
|
var INVALID_BLEND_COMBINATIONS = env.constants.invalidBlendCombinations; |
|
|
|
env.assert(scope, |
|
INVALID_BLEND_COMBINATIONS + |
|
'.indexOf(' + srcRGB + '+", "+' + dstRGB + ') === -1 ', |
|
'unallowed blending combination for (srcRGB, dstRGB)' |
|
); |
|
}); |
|
|
|
var SRC_RGB = scope.def(BLEND_FUNCS, '[', srcRGB, ']'); |
|
var SRC_ALPHA = scope.def(BLEND_FUNCS, '[', read('src', 'Alpha'), ']'); |
|
var DST_RGB = scope.def(BLEND_FUNCS, '[', dstRGB, ']'); |
|
var DST_ALPHA = scope.def(BLEND_FUNCS, '[', read('dst', 'Alpha'), ']'); |
|
|
|
return [SRC_RGB, DST_RGB, SRC_ALPHA, DST_ALPHA] |
|
}) |
|
|
|
case S_BLEND_EQUATION: |
|
return parseParam( |
|
function (value) { |
|
if (typeof value === 'string') { |
|
check$1.commandParameter(value, blendEquations, 'invalid ' + prop, env.commandStr); |
|
return [ |
|
blendEquations[value], |
|
blendEquations[value] |
|
] |
|
} else if (typeof value === 'object') { |
|
check$1.commandParameter( |
|
value.rgb, blendEquations, prop + '.rgb', env.commandStr); |
|
check$1.commandParameter( |
|
value.alpha, blendEquations, prop + '.alpha', env.commandStr); |
|
return [ |
|
blendEquations[value.rgb], |
|
blendEquations[value.alpha] |
|
] |
|
} else { |
|
check$1.commandRaise('invalid blend.equation', env.commandStr); |
|
} |
|
}, |
|
function (env, scope, value) { |
|
var BLEND_EQUATIONS = env.constants.blendEquations; |
|
|
|
var RGB = scope.def(); |
|
var ALPHA = scope.def(); |
|
|
|
var ifte = env.cond('typeof ', value, '==="string"'); |
|
|
|
check$1.optional(function () { |
|
function checkProp (block, name, value) { |
|
env.assert(block, |
|
value + ' in ' + BLEND_EQUATIONS, |
|
'invalid ' + name + ', must be one of ' + Object.keys(blendEquations)); |
|
} |
|
checkProp(ifte.then, prop, value); |
|
|
|
env.assert(ifte.else, |
|
value + '&&typeof ' + value + '==="object"', |
|
'invalid ' + prop); |
|
checkProp(ifte.else, prop + '.rgb', value + '.rgb'); |
|
checkProp(ifte.else, prop + '.alpha', value + '.alpha'); |
|
}); |
|
|
|
ifte.then( |
|
RGB, '=', ALPHA, '=', BLEND_EQUATIONS, '[', value, '];'); |
|
ifte.else( |
|
RGB, '=', BLEND_EQUATIONS, '[', value, '.rgb];', |
|
ALPHA, '=', BLEND_EQUATIONS, '[', value, '.alpha];'); |
|
|
|
scope(ifte); |
|
|
|
return [RGB, ALPHA] |
|
}) |
|
|
|
case S_BLEND_COLOR: |
|
return parseParam( |
|
function (value) { |
|
check$1.command( |
|
isArrayLike(value) && |
|
value.length === 4, |
|
'blend.color must be a 4d array', env.commandStr); |
|
return loop(4, function (i) { |
|
return +value[i] |
|
}) |
|
}, |
|
function (env, scope, value) { |
|
check$1.optional(function () { |
|
env.assert(scope, |
|
env.shared.isArrayLike + '(' + value + ')&&' + |
|
value + '.length===4', |
|
'blend.color must be a 4d array'); |
|
}); |
|
return loop(4, function (i) { |
|
return scope.def('+', value, '[', i, ']') |
|
}) |
|
}) |
|
|
|
case S_STENCIL_MASK: |
|
return parseParam( |
|
function (value) { |
|
check$1.commandType(value, 'number', param, env.commandStr); |
|
return value | 0 |
|
}, |
|
function (env, scope, value) { |
|
check$1.optional(function () { |
|
env.assert(scope, |
|
'typeof ' + value + '==="number"', |
|
'invalid stencil.mask'); |
|
}); |
|
return scope.def(value, '|0') |
|
}) |
|
|
|
case S_STENCIL_FUNC: |
|
return parseParam( |
|
function (value) { |
|
check$1.commandType(value, 'object', param, env.commandStr); |
|
var cmp = value.cmp || 'keep'; |
|
var ref = value.ref || 0; |
|
var mask = 'mask' in value ? value.mask : -1; |
|
check$1.commandParameter(cmp, compareFuncs, prop + '.cmp', env.commandStr); |
|
check$1.commandType(ref, 'number', prop + '.ref', env.commandStr); |
|
check$1.commandType(mask, 'number', prop + '.mask', env.commandStr); |
|
return [ |
|
compareFuncs[cmp], |
|
ref, |
|
mask |
|
] |
|
}, |
|
function (env, scope, value) { |
|
var COMPARE_FUNCS = env.constants.compareFuncs; |
|
check$1.optional(function () { |
|
function assert () { |
|
env.assert(scope, |
|
Array.prototype.join.call(arguments, ''), |
|
'invalid stencil.func'); |
|
} |
|
assert(value + '&&typeof ', value, '==="object"'); |
|
assert('!("cmp" in ', value, ')||(', |
|
value, '.cmp in ', COMPARE_FUNCS, ')'); |
|
}); |
|
var cmp = scope.def( |
|
'"cmp" in ', value, |
|
'?', COMPARE_FUNCS, '[', value, '.cmp]', |
|
':', GL_KEEP); |
|
var ref = scope.def(value, '.ref|0'); |
|
var mask = scope.def( |
|
'"mask" in ', value, |
|
'?', value, '.mask|0:-1'); |
|
return [cmp, ref, mask] |
|
}) |
|
|
|
case S_STENCIL_OPFRONT: |
|
case S_STENCIL_OPBACK: |
|
return parseParam( |
|
function (value) { |
|
check$1.commandType(value, 'object', param, env.commandStr); |
|
var fail = value.fail || 'keep'; |
|
var zfail = value.zfail || 'keep'; |
|
var zpass = value.zpass || 'keep'; |
|
check$1.commandParameter(fail, stencilOps, prop + '.fail', env.commandStr); |
|
check$1.commandParameter(zfail, stencilOps, prop + '.zfail', env.commandStr); |
|
check$1.commandParameter(zpass, stencilOps, prop + '.zpass', env.commandStr); |
|
return [ |
|
prop === S_STENCIL_OPBACK ? GL_BACK : GL_FRONT, |
|
stencilOps[fail], |
|
stencilOps[zfail], |
|
stencilOps[zpass] |
|
] |
|
}, |
|
function (env, scope, value) { |
|
var STENCIL_OPS = env.constants.stencilOps; |
|
|
|
check$1.optional(function () { |
|
env.assert(scope, |
|
value + '&&typeof ' + value + '==="object"', |
|
'invalid ' + prop); |
|
}); |
|
|
|
function read (name) { |
|
check$1.optional(function () { |
|
env.assert(scope, |
|
'!("' + name + '" in ' + value + ')||' + |
|
'(' + value + '.' + name + ' in ' + STENCIL_OPS + ')', |
|
'invalid ' + prop + '.' + name + ', must be one of ' + Object.keys(stencilOps)); |
|
}); |
|
|
|
return scope.def( |
|
'"', name, '" in ', value, |
|
'?', STENCIL_OPS, '[', value, '.', name, ']:', |
|
GL_KEEP) |
|
} |
|
|
|
return [ |
|
prop === S_STENCIL_OPBACK ? GL_BACK : GL_FRONT, |
|
read('fail'), |
|
read('zfail'), |
|
read('zpass') |
|
] |
|
}) |
|
|
|
case S_POLYGON_OFFSET_OFFSET: |
|
return parseParam( |
|
function (value) { |
|
check$1.commandType(value, 'object', param, env.commandStr); |
|
var factor = value.factor | 0; |
|
var units = value.units | 0; |
|
check$1.commandType(factor, 'number', param + '.factor', env.commandStr); |
|
check$1.commandType(units, 'number', param + '.units', env.commandStr); |
|
return [factor, units] |
|
}, |
|
function (env, scope, value) { |
|
check$1.optional(function () { |
|
env.assert(scope, |
|
value + '&&typeof ' + value + '==="object"', |
|
'invalid ' + prop); |
|
}); |
|
|
|
var FACTOR = scope.def(value, '.factor|0'); |
|
var UNITS = scope.def(value, '.units|0'); |
|
|
|
return [FACTOR, UNITS] |
|
}) |
|
|
|
case S_CULL_FACE: |
|
return parseParam( |
|
function (value) { |
|
var face = 0; |
|
if (value === 'front') { |
|
face = GL_FRONT; |
|
} else if (value === 'back') { |
|
face = GL_BACK; |
|
} |
|
check$1.command(!!face, param, env.commandStr); |
|
return face |
|
}, |
|
function (env, scope, value) { |
|
check$1.optional(function () { |
|
env.assert(scope, |
|
value + '==="front"||' + |
|
value + '==="back"', |
|
'invalid cull.face'); |
|
}); |
|
return scope.def(value, '==="front"?', GL_FRONT, ':', GL_BACK) |
|
}) |
|
|
|
case S_LINE_WIDTH: |
|
return parseParam( |
|
function (value) { |
|
check$1.command( |
|
typeof value === 'number' && |
|
value >= limits.lineWidthDims[0] && |
|
value <= limits.lineWidthDims[1], |
|
'invalid line width, must positive number between ' + |
|
limits.lineWidthDims[0] + ' and ' + limits.lineWidthDims[1], env.commandStr); |
|
return value |
|
}, |
|
function (env, scope, value) { |
|
check$1.optional(function () { |
|
env.assert(scope, |
|
'typeof ' + value + '==="number"&&' + |
|
value + '>=' + limits.lineWidthDims[0] + '&&' + |
|
value + '<=' + limits.lineWidthDims[1], |
|
'invalid line width'); |
|
}); |
|
|
|
return value |
|
}) |
|
|
|
case S_FRONT_FACE: |
|
return parseParam( |
|
function (value) { |
|
check$1.commandParameter(value, orientationType, param, env.commandStr); |
|
return orientationType[value] |
|
}, |
|
function (env, scope, value) { |
|
check$1.optional(function () { |
|
env.assert(scope, |
|
value + '==="cw"||' + |
|
value + '==="ccw"', |
|
'invalid frontFace, must be one of cw,ccw'); |
|
}); |
|
return scope.def(value + '==="cw"?' + GL_CW + ':' + GL_CCW) |
|
}) |
|
|
|
case S_COLOR_MASK: |
|
return parseParam( |
|
function (value) { |
|
check$1.command( |
|
isArrayLike(value) && value.length === 4, |
|
'color.mask must be length 4 array', env.commandStr); |
|
return value.map(function (v) { return !!v }) |
|
}, |
|
function (env, scope, value) { |
|
check$1.optional(function () { |
|
env.assert(scope, |
|
env.shared.isArrayLike + '(' + value + ')&&' + |
|
value + '.length===4', |
|
'invalid color.mask'); |
|
}); |
|
return loop(4, function (i) { |
|
return '!!' + value + '[' + i + ']' |
|
}) |
|
}) |
|
|
|
case S_SAMPLE_COVERAGE: |
|
return parseParam( |
|
function (value) { |
|
check$1.command(typeof value === 'object' && value, param, env.commandStr); |
|
var sampleValue = 'value' in value ? value.value : 1; |
|
var sampleInvert = !!value.invert; |
|
check$1.command( |
|
typeof sampleValue === 'number' && |
|
sampleValue >= 0 && sampleValue <= 1, |
|
'sample.coverage.value must be a number between 0 and 1', env.commandStr); |
|
return [sampleValue, sampleInvert] |
|
}, |
|
function (env, scope, value) { |
|
check$1.optional(function () { |
|
env.assert(scope, |
|
value + '&&typeof ' + value + '==="object"', |
|
'invalid sample.coverage'); |
|
}); |
|
var VALUE = scope.def( |
|
'"value" in ', value, '?+', value, '.value:1'); |
|
var INVERT = scope.def('!!', value, '.invert'); |
|
return [VALUE, INVERT] |
|
}) |
|
} |
|
}); |
|
|
|
return STATE |
|
} |
|
|
|
function parseUniforms (uniforms, env) { |
|
var staticUniforms = uniforms.static; |
|
var dynamicUniforms = uniforms.dynamic; |
|
|
|
var UNIFORMS = {}; |
|
|
|
Object.keys(staticUniforms).forEach(function (name) { |
|
var value = staticUniforms[name]; |
|
var result; |
|
if (typeof value === 'number' || |
|
typeof value === 'boolean') { |
|
result = createStaticDecl(function () { |
|
return value |
|
}); |
|
} else if (typeof value === 'function') { |
|
var reglType = value._reglType; |
|
if (reglType === 'texture2d' || |
|
reglType === 'textureCube') { |
|
result = createStaticDecl(function (env) { |
|
return env.link(value) |
|
}); |
|
} else if (reglType === 'framebuffer' || |
|
reglType === 'framebufferCube') { |
|
check$1.command(value.color.length > 0, |
|
'missing color attachment for framebuffer sent to uniform "' + name + '"', env.commandStr); |
|
result = createStaticDecl(function (env) { |
|
return env.link(value.color[0]) |
|
}); |
|
} else { |
|
check$1.commandRaise('invalid data for uniform "' + name + '"', env.commandStr); |
|
} |
|
} else if (isArrayLike(value)) { |
|
result = createStaticDecl(function (env) { |
|
var ITEM = env.global.def('[', |
|
loop(value.length, function (i) { |
|
check$1.command( |
|
typeof value[i] === 'number' || |
|
typeof value[i] === 'boolean', |
|
'invalid uniform ' + name, env.commandStr); |
|
return value[i] |
|
}), ']'); |
|
return ITEM |
|
}); |
|
} else { |
|
check$1.commandRaise('invalid or missing data for uniform "' + name + '"', env.commandStr); |
|
} |
|
result.value = value; |
|
UNIFORMS[name] = result; |
|
}); |
|
|
|
Object.keys(dynamicUniforms).forEach(function (key) { |
|
var dyn = dynamicUniforms[key]; |
|
UNIFORMS[key] = createDynamicDecl(dyn, function (env, scope) { |
|
return env.invoke(scope, dyn) |
|
}); |
|
}); |
|
|
|
return UNIFORMS |
|
} |
|
|
|
function parseAttributes (attributes, env) { |
|
var staticAttributes = attributes.static; |
|
var dynamicAttributes = attributes.dynamic; |
|
|
|
var attributeDefs = {}; |
|
|
|
Object.keys(staticAttributes).forEach(function (attribute) { |
|
var value = staticAttributes[attribute]; |
|
var id = stringStore.id(attribute); |
|
|
|
var record = new AttributeRecord(); |
|
if (isBufferArgs(value)) { |
|
record.state = ATTRIB_STATE_POINTER; |
|
record.buffer = bufferState.getBuffer( |
|
bufferState.create(value, GL_ARRAY_BUFFER$1, false, true)); |
|
record.type = 0; |
|
} else { |
|
var buffer = bufferState.getBuffer(value); |
|
if (buffer) { |
|
record.state = ATTRIB_STATE_POINTER; |
|
record.buffer = buffer; |
|
record.type = 0; |
|
} else { |
|
check$1.command(typeof value === 'object' && value, |
|
'invalid data for attribute ' + attribute, env.commandStr); |
|
if (value.constant) { |
|
var constant = value.constant; |
|
record.buffer = 'null'; |
|
record.state = ATTRIB_STATE_CONSTANT; |
|
if (typeof constant === 'number') { |
|
record.x = constant; |
|
} else { |
|
check$1.command( |
|
isArrayLike(constant) && |
|
constant.length > 0 && |
|
constant.length <= 4, |
|
'invalid constant for attribute ' + attribute, env.commandStr); |
|
CUTE_COMPONENTS.forEach(function (c, i) { |
|
if (i < constant.length) { |
|
record[c] = constant[i]; |
|
} |
|
}); |
|
} |
|
} else { |
|
if (isBufferArgs(value.buffer)) { |
|
buffer = bufferState.getBuffer( |
|
bufferState.create(value.buffer, GL_ARRAY_BUFFER$1, false, true)); |
|
} else { |
|
buffer = bufferState.getBuffer(value.buffer); |
|
} |
|
check$1.command(!!buffer, 'missing buffer for attribute "' + attribute + '"', env.commandStr); |
|
|
|
var offset = value.offset | 0; |
|
check$1.command(offset >= 0, |
|
'invalid offset for attribute "' + attribute + '"', env.commandStr); |
|
|
|
var stride = value.stride | 0; |
|
check$1.command(stride >= 0 && stride < 256, |
|
'invalid stride for attribute "' + attribute + '", must be integer betweeen [0, 255]', env.commandStr); |
|
|
|
var size = value.size | 0; |
|
check$1.command(!('size' in value) || (size > 0 && size <= 4), |
|
'invalid size for attribute "' + attribute + '", must be 1,2,3,4', env.commandStr); |
|
|
|
var normalized = !!value.normalized; |
|
|
|
var type = 0; |
|
if ('type' in value) { |
|
check$1.commandParameter( |
|
value.type, glTypes, |
|
'invalid type for attribute ' + attribute, env.commandStr); |
|
type = glTypes[value.type]; |
|
} |
|
|
|
var divisor = value.divisor | 0; |
|
if ('divisor' in value) { |
|
check$1.command(divisor === 0 || extInstancing, |
|
'cannot specify divisor for attribute "' + attribute + '", instancing not supported', env.commandStr); |
|
check$1.command(divisor >= 0, |
|
'invalid divisor for attribute "' + attribute + '"', env.commandStr); |
|
} |
|
|
|
check$1.optional(function () { |
|
var command = env.commandStr; |
|
|
|
var VALID_KEYS = [ |
|
'buffer', |
|
'offset', |
|
'divisor', |
|
'normalized', |
|
'type', |
|
'size', |
|
'stride' |
|
]; |
|
|
|
Object.keys(value).forEach(function (prop) { |
|
check$1.command( |
|
VALID_KEYS.indexOf(prop) >= 0, |
|
'unknown parameter "' + prop + '" for attribute pointer "' + attribute + '" (valid parameters are ' + VALID_KEYS + ')', |
|
command); |
|
}); |
|
}); |
|
|
|
record.buffer = buffer; |
|
record.state = ATTRIB_STATE_POINTER; |
|
record.size = size; |
|
record.normalized = normalized; |
|
record.type = type || buffer.dtype; |
|
record.offset = offset; |
|
record.stride = stride; |
|
record.divisor = divisor; |
|
} |
|
} |
|
} |
|
|
|
attributeDefs[attribute] = createStaticDecl(function (env, scope) { |
|
var cache = env.attribCache; |
|
if (id in cache) { |
|
return cache[id] |
|
} |
|
var result = { |
|
isStream: false |
|
}; |
|
Object.keys(record).forEach(function (key) { |
|
result[key] = record[key]; |
|
}); |
|
if (record.buffer) { |
|
result.buffer = env.link(record.buffer); |
|
result.type = result.type || (result.buffer + '.dtype'); |
|
} |
|
cache[id] = result; |
|
return result |
|
}); |
|
}); |
|
|
|
Object.keys(dynamicAttributes).forEach(function (attribute) { |
|
var dyn = dynamicAttributes[attribute]; |
|
|
|
function appendAttributeCode (env, block) { |
|
var VALUE = env.invoke(block, dyn); |
|
|
|
var shared = env.shared; |
|
|
|
var IS_BUFFER_ARGS = shared.isBufferArgs; |
|
var BUFFER_STATE = shared.buffer; |
|
|
|
// Perform validation on attribute |
|
check$1.optional(function () { |
|
env.assert(block, |
|
VALUE + '&&(typeof ' + VALUE + '==="object"||typeof ' + |
|
VALUE + '==="function")&&(' + |
|
IS_BUFFER_ARGS + '(' + VALUE + ')||' + |
|
BUFFER_STATE + '.getBuffer(' + VALUE + ')||' + |
|
BUFFER_STATE + '.getBuffer(' + VALUE + '.buffer)||' + |
|
IS_BUFFER_ARGS + '(' + VALUE + '.buffer)||' + |
|
'("constant" in ' + VALUE + |
|
'&&(typeof ' + VALUE + '.constant==="number"||' + |
|
shared.isArrayLike + '(' + VALUE + '.constant))))', |
|
'invalid dynamic attribute "' + attribute + '"'); |
|
}); |
|
|
|
// allocate names for result |
|
var result = { |
|
isStream: block.def(false) |
|
}; |
|
var defaultRecord = new AttributeRecord(); |
|
defaultRecord.state = ATTRIB_STATE_POINTER; |
|
Object.keys(defaultRecord).forEach(function (key) { |
|
result[key] = block.def('' + defaultRecord[key]); |
|
}); |
|
|
|
var BUFFER = result.buffer; |
|
var TYPE = result.type; |
|
block( |
|
'if(', IS_BUFFER_ARGS, '(', VALUE, ')){', |
|
result.isStream, '=true;', |
|
BUFFER, '=', BUFFER_STATE, '.createStream(', GL_ARRAY_BUFFER$1, ',', VALUE, ');', |
|
TYPE, '=', BUFFER, '.dtype;', |
|
'}else{', |
|
BUFFER, '=', BUFFER_STATE, '.getBuffer(', VALUE, ');', |
|
'if(', BUFFER, '){', |
|
TYPE, '=', BUFFER, '.dtype;', |
|
'}else if("constant" in ', VALUE, '){', |
|
result.state, '=', ATTRIB_STATE_CONSTANT, ';', |
|
'if(typeof ' + VALUE + '.constant === "number"){', |
|
result[CUTE_COMPONENTS[0]], '=', VALUE, '.constant;', |
|
CUTE_COMPONENTS.slice(1).map(function (n) { |
|
return result[n] |
|
}).join('='), '=0;', |
|
'}else{', |
|
CUTE_COMPONENTS.map(function (name, i) { |
|
return ( |
|
result[name] + '=' + VALUE + '.constant.length>=' + i + |
|
'?' + VALUE + '.constant[' + i + ']:0;' |
|
) |
|
}).join(''), |
|
'}}else{', |
|
'if(', IS_BUFFER_ARGS, '(', VALUE, '.buffer)){', |
|
BUFFER, '=', BUFFER_STATE, '.createStream(', GL_ARRAY_BUFFER$1, ',', VALUE, '.buffer);', |
|
'}else{', |
|
BUFFER, '=', BUFFER_STATE, '.getBuffer(', VALUE, '.buffer);', |
|
'}', |
|
TYPE, '="type" in ', VALUE, '?', |
|
shared.glTypes, '[', VALUE, '.type]:', BUFFER, '.dtype;', |
|
result.normalized, '=!!', VALUE, '.normalized;'); |
|
function emitReadRecord (name) { |
|
block(result[name], '=', VALUE, '.', name, '|0;'); |
|
} |
|
emitReadRecord('size'); |
|
emitReadRecord('offset'); |
|
emitReadRecord('stride'); |
|
emitReadRecord('divisor'); |
|
|
|
block('}}'); |
|
|
|
block.exit( |
|
'if(', result.isStream, '){', |
|
BUFFER_STATE, '.destroyStream(', BUFFER, ');', |
|
'}'); |
|
|
|
return result |
|
} |
|
|
|
attributeDefs[attribute] = createDynamicDecl(dyn, appendAttributeCode); |
|
}); |
|
|
|
return attributeDefs |
|
} |
|
|
|
function parseContext (context) { |
|
var staticContext = context.static; |
|
var dynamicContext = context.dynamic; |
|
var result = {}; |
|
|
|
Object.keys(staticContext).forEach(function (name) { |
|
var value = staticContext[name]; |
|
result[name] = createStaticDecl(function (env, scope) { |
|
if (typeof value === 'number' || typeof value === 'boolean') { |
|
return '' + value |
|
} else { |
|
return env.link(value) |
|
} |
|
}); |
|
}); |
|
|
|
Object.keys(dynamicContext).forEach(function (name) { |
|
var dyn = dynamicContext[name]; |
|
result[name] = createDynamicDecl(dyn, function (env, scope) { |
|
return env.invoke(scope, dyn) |
|
}); |
|
}); |
|
|
|
return result |
|
} |
|
|
|
function parseArguments (options, attributes, uniforms, context, env) { |
|
var staticOptions = options.static; |
|
var dynamicOptions = options.dynamic; |
|
|
|
check$1.optional(function () { |
|
var KEY_NAMES = [ |
|
S_FRAMEBUFFER, |
|
S_VERT, |
|
S_FRAG, |
|
S_ELEMENTS, |
|
S_PRIMITIVE, |
|
S_OFFSET, |
|
S_COUNT, |
|
S_INSTANCES, |
|
S_PROFILE |
|
].concat(GL_STATE_NAMES); |
|
|
|
function checkKeys (dict) { |
|
Object.keys(dict).forEach(function (key) { |
|
check$1.command( |
|
KEY_NAMES.indexOf(key) >= 0, |
|
'unknown parameter "' + key + '"', |
|
env.commandStr); |
|
}); |
|
} |
|
|
|
checkKeys(staticOptions); |
|
checkKeys(dynamicOptions); |
|
}); |
|
|
|
var framebuffer = parseFramebuffer(options, env); |
|
var viewportAndScissor = parseViewportScissor(options, framebuffer, env); |
|
var draw = parseDraw(options, env); |
|
var state = parseGLState(options, env); |
|
var shader = parseProgram(options, env); |
|
|
|
function copyBox (name) { |
|
var defn = viewportAndScissor[name]; |
|
if (defn) { |
|
state[name] = defn; |
|
} |
|
} |
|
copyBox(S_VIEWPORT); |
|
copyBox(propName(S_SCISSOR_BOX)); |
|
|
|
var dirty = Object.keys(state).length > 0; |
|
|
|
var result = { |
|
framebuffer: framebuffer, |
|
draw: draw, |
|
shader: shader, |
|
state: state, |
|
dirty: dirty |
|
}; |
|
|
|
result.profile = parseProfile(options, env); |
|
result.uniforms = parseUniforms(uniforms, env); |
|
result.attributes = parseAttributes(attributes, env); |
|
result.context = parseContext(context, env); |
|
return result |
|
} |
|
|
|
// =================================================== |
|
// =================================================== |
|
// COMMON UPDATE FUNCTIONS |
|
// =================================================== |
|
// =================================================== |
|
function emitContext (env, scope, context) { |
|
var shared = env.shared; |
|
var CONTEXT = shared.context; |
|
|
|
var contextEnter = env.scope(); |
|
|
|
Object.keys(context).forEach(function (name) { |
|
scope.save(CONTEXT, '.' + name); |
|
var defn = context[name]; |
|
contextEnter(CONTEXT, '.', name, '=', defn.append(env, scope), ';'); |
|
}); |
|
|
|
scope(contextEnter); |
|
} |
|
|
|
// =================================================== |
|
// =================================================== |
|
// COMMON DRAWING FUNCTIONS |
|
// =================================================== |
|
// =================================================== |
|
function emitPollFramebuffer (env, scope, framebuffer, skipCheck) { |
|
var shared = env.shared; |
|
|
|
var GL = shared.gl; |
|
var FRAMEBUFFER_STATE = shared.framebuffer; |
|
var EXT_DRAW_BUFFERS; |
|
if (extDrawBuffers) { |
|
EXT_DRAW_BUFFERS = scope.def(shared.extensions, '.webgl_draw_buffers'); |
|
} |
|
|
|
var constants = env.constants; |
|
|
|
var DRAW_BUFFERS = constants.drawBuffer; |
|
var BACK_BUFFER = constants.backBuffer; |
|
|
|
var NEXT; |
|
if (framebuffer) { |
|
NEXT = framebuffer.append(env, scope); |
|
} else { |
|
NEXT = scope.def(FRAMEBUFFER_STATE, '.next'); |
|
} |
|
|
|
if (!skipCheck) { |
|
scope('if(', NEXT, '!==', FRAMEBUFFER_STATE, '.cur){'); |
|
} |
|
scope( |
|
'if(', NEXT, '){', |
|
GL, '.bindFramebuffer(', GL_FRAMEBUFFER$1, ',', NEXT, '.framebuffer);'); |
|
if (extDrawBuffers) { |
|
scope(EXT_DRAW_BUFFERS, '.drawBuffersWEBGL(', |
|
DRAW_BUFFERS, '[', NEXT, '.colorAttachments.length]);'); |
|
} |
|
scope('}else{', |
|
GL, '.bindFramebuffer(', GL_FRAMEBUFFER$1, ',null);'); |
|
if (extDrawBuffers) { |
|
scope(EXT_DRAW_BUFFERS, '.drawBuffersWEBGL(', BACK_BUFFER, ');'); |
|
} |
|
scope( |
|
'}', |
|
FRAMEBUFFER_STATE, '.cur=', NEXT, ';'); |
|
if (!skipCheck) { |
|
scope('}'); |
|
} |
|
} |
|
|
|
function emitPollState (env, scope, args) { |
|
var shared = env.shared; |
|
|
|
var GL = shared.gl; |
|
|
|
var CURRENT_VARS = env.current; |
|
var NEXT_VARS = env.next; |
|
var CURRENT_STATE = shared.current; |
|
var NEXT_STATE = shared.next; |
|
|
|
var block = env.cond(CURRENT_STATE, '.dirty'); |
|
|
|
GL_STATE_NAMES.forEach(function (prop) { |
|
var param = propName(prop); |
|
if (param in args.state) { |
|
return |
|
} |
|
|
|
var NEXT, CURRENT; |
|
if (param in NEXT_VARS) { |
|
NEXT = NEXT_VARS[param]; |
|
CURRENT = CURRENT_VARS[param]; |
|
var parts = loop(currentState[param].length, function (i) { |
|
return block.def(NEXT, '[', i, ']') |
|
}); |
|
block(env.cond(parts.map(function (p, i) { |
|
return p + '!==' + CURRENT + '[' + i + ']' |
|
}).join('||')) |
|
.then( |
|
GL, '.', GL_VARIABLES[param], '(', parts, ');', |
|
parts.map(function (p, i) { |
|
return CURRENT + '[' + i + ']=' + p |
|
}).join(';'), ';')); |
|
} else { |
|
NEXT = block.def(NEXT_STATE, '.', param); |
|
var ifte = env.cond(NEXT, '!==', CURRENT_STATE, '.', param); |
|
block(ifte); |
|
if (param in GL_FLAGS) { |
|
ifte( |
|
env.cond(NEXT) |
|
.then(GL, '.enable(', GL_FLAGS[param], ');') |
|
.else(GL, '.disable(', GL_FLAGS[param], ');'), |
|
CURRENT_STATE, '.', param, '=', NEXT, ';'); |
|
} else { |
|
ifte( |
|
GL, '.', GL_VARIABLES[param], '(', NEXT, ');', |
|
CURRENT_STATE, '.', param, '=', NEXT, ';'); |
|
} |
|
} |
|
}); |
|
if (Object.keys(args.state).length === 0) { |
|
block(CURRENT_STATE, '.dirty=false;'); |
|
} |
|
scope(block); |
|
} |
|
|
|
function emitSetOptions (env, scope, options, filter) { |
|
var shared = env.shared; |
|
var CURRENT_VARS = env.current; |
|
var CURRENT_STATE = shared.current; |
|
var GL = shared.gl; |
|
sortState(Object.keys(options)).forEach(function (param) { |
|
var defn = options[param]; |
|
if (filter && !filter(defn)) { |
|
return |
|
} |
|
var variable = defn.append(env, scope); |
|
if (GL_FLAGS[param]) { |
|
var flag = GL_FLAGS[param]; |
|
if (isStatic(defn)) { |
|
if (variable) { |
|
scope(GL, '.enable(', flag, ');'); |
|
} else { |
|
scope(GL, '.disable(', flag, ');'); |
|
} |
|
} else { |
|
scope(env.cond(variable) |
|
.then(GL, '.enable(', flag, ');') |
|
.else(GL, '.disable(', flag, ');')); |
|
} |
|
scope(CURRENT_STATE, '.', param, '=', variable, ';'); |
|
} else if (isArrayLike(variable)) { |
|
var CURRENT = CURRENT_VARS[param]; |
|
scope( |
|
GL, '.', GL_VARIABLES[param], '(', variable, ');', |
|
variable.map(function (v, i) { |
|
return CURRENT + '[' + i + ']=' + v |
|
}).join(';'), ';'); |
|
} else { |
|
scope( |
|
GL, '.', GL_VARIABLES[param], '(', variable, ');', |
|
CURRENT_STATE, '.', param, '=', variable, ';'); |
|
} |
|
}); |
|
} |
|
|
|
function injectExtensions (env, scope) { |
|
if (extInstancing) { |
|
env.instancing = scope.def( |
|
env.shared.extensions, '.angle_instanced_arrays'); |
|
} |
|
} |
|
|
|
function emitProfile (env, scope, args, useScope, incrementCounter) { |
|
var shared = env.shared; |
|
var STATS = env.stats; |
|
var CURRENT_STATE = shared.current; |
|
var TIMER = shared.timer; |
|
var profileArg = args.profile; |
|
|
|
function perfCounter () { |
|
if (typeof performance === 'undefined') { |
|
return 'Date.now()' |
|
} else { |
|
return 'performance.now()' |
|
} |
|
} |
|
|
|
var CPU_START, QUERY_COUNTER; |
|
function emitProfileStart (block) { |
|
CPU_START = scope.def(); |
|
block(CPU_START, '=', perfCounter(), ';'); |
|
if (typeof incrementCounter === 'string') { |
|
block(STATS, '.count+=', incrementCounter, ';'); |
|
} else { |
|
block(STATS, '.count++;'); |
|
} |
|
if (timer) { |
|
if (useScope) { |
|
QUERY_COUNTER = scope.def(); |
|
block(QUERY_COUNTER, '=', TIMER, '.getNumPendingQueries();'); |
|
} else { |
|
block(TIMER, '.beginQuery(', STATS, ');'); |
|
} |
|
} |
|
} |
|
|
|
function emitProfileEnd (block) { |
|
block(STATS, '.cpuTime+=', perfCounter(), '-', CPU_START, ';'); |
|
if (timer) { |
|
if (useScope) { |
|
block(TIMER, '.pushScopeStats(', |
|
QUERY_COUNTER, ',', |
|
TIMER, '.getNumPendingQueries(),', |
|
STATS, ');'); |
|
} else { |
|
block(TIMER, '.endQuery();'); |
|
} |
|
} |
|
} |
|
|
|
function scopeProfile (value) { |
|
var prev = scope.def(CURRENT_STATE, '.profile'); |
|
scope(CURRENT_STATE, '.profile=', value, ';'); |
|
scope.exit(CURRENT_STATE, '.profile=', prev, ';'); |
|
} |
|
|
|
var USE_PROFILE; |
|
if (profileArg) { |
|
if (isStatic(profileArg)) { |
|
if (profileArg.enable) { |
|
emitProfileStart(scope); |
|
emitProfileEnd(scope.exit); |
|
scopeProfile('true'); |
|
} else { |
|
scopeProfile('false'); |
|
} |
|
return |
|
} |
|
USE_PROFILE = profileArg.append(env, scope); |
|
scopeProfile(USE_PROFILE); |
|
} else { |
|
USE_PROFILE = scope.def(CURRENT_STATE, '.profile'); |
|
} |
|
|
|
var start = env.block(); |
|
emitProfileStart(start); |
|
scope('if(', USE_PROFILE, '){', start, '}'); |
|
var end = env.block(); |
|
emitProfileEnd(end); |
|
scope.exit('if(', USE_PROFILE, '){', end, '}'); |
|
} |
|
|
|
function emitAttributes (env, scope, args, attributes, filter) { |
|
var shared = env.shared; |
|
|
|
function typeLength (x) { |
|
switch (x) { |
|
case GL_FLOAT_VEC2: |
|
case GL_INT_VEC2: |
|
case GL_BOOL_VEC2: |
|
return 2 |
|
case GL_FLOAT_VEC3: |
|
case GL_INT_VEC3: |
|
case GL_BOOL_VEC3: |
|
return 3 |
|
case GL_FLOAT_VEC4: |
|
case GL_INT_VEC4: |
|
case GL_BOOL_VEC4: |
|
return 4 |
|
default: |
|
return 1 |
|
} |
|
} |
|
|
|
function emitBindAttribute (ATTRIBUTE, size, record) { |
|
var GL = shared.gl; |
|
|
|
var LOCATION = scope.def(ATTRIBUTE, '.location'); |
|
var BINDING = scope.def(shared.attributes, '[', LOCATION, ']'); |
|
|
|
var STATE = record.state; |
|
var BUFFER = record.buffer; |
|
var CONST_COMPONENTS = [ |
|
record.x, |
|
record.y, |
|
record.z, |
|
record.w |
|
]; |
|
|
|
var COMMON_KEYS = [ |
|
'buffer', |
|
'normalized', |
|
'offset', |
|
'stride' |
|
]; |
|
|
|
function emitBuffer () { |
|
scope( |
|
'if(!', BINDING, '.buffer){', |
|
GL, '.enableVertexAttribArray(', LOCATION, ');}'); |
|
|
|
var TYPE = record.type; |
|
var SIZE; |
|
if (!record.size) { |
|
SIZE = size; |
|
} else { |
|
SIZE = scope.def(record.size, '||', size); |
|
} |
|
|
|
scope('if(', |
|
BINDING, '.type!==', TYPE, '||', |
|
BINDING, '.size!==', SIZE, '||', |
|
COMMON_KEYS.map(function (key) { |
|
return BINDING + '.' + key + '!==' + record[key] |
|
}).join('||'), |
|
'){', |
|
GL, '.bindBuffer(', GL_ARRAY_BUFFER$1, ',', BUFFER, '.buffer);', |
|
GL, '.vertexAttribPointer(', [ |
|
LOCATION, |
|
SIZE, |
|
TYPE, |
|
record.normalized, |
|
record.stride, |
|
record.offset |
|
], ');', |
|
BINDING, '.type=', TYPE, ';', |
|
BINDING, '.size=', SIZE, ';', |
|
COMMON_KEYS.map(function (key) { |
|
return BINDING + '.' + key + '=' + record[key] + ';' |
|
}).join(''), |
|
'}'); |
|
|
|
if (extInstancing) { |
|
var DIVISOR = record.divisor; |
|
scope( |
|
'if(', BINDING, '.divisor!==', DIVISOR, '){', |
|
env.instancing, '.vertexAttribDivisorANGLE(', [LOCATION, DIVISOR], ');', |
|
BINDING, '.divisor=', DIVISOR, ';}'); |
|
} |
|
} |
|
|
|
function emitConstant () { |
|
scope( |
|
'if(', BINDING, '.buffer){', |
|
GL, '.disableVertexAttribArray(', LOCATION, ');', |
|
'}if(', CUTE_COMPONENTS.map(function (c, i) { |
|
return BINDING + '.' + c + '!==' + CONST_COMPONENTS[i] |
|
}).join('||'), '){', |
|
GL, '.vertexAttrib4f(', LOCATION, ',', CONST_COMPONENTS, ');', |
|
CUTE_COMPONENTS.map(function (c, i) { |
|
return BINDING + '.' + c + '=' + CONST_COMPONENTS[i] + ';' |
|
}).join(''), |
|
'}'); |
|
} |
|
|
|
if (STATE === ATTRIB_STATE_POINTER) { |
|
emitBuffer(); |
|
} else if (STATE === ATTRIB_STATE_CONSTANT) { |
|
emitConstant(); |
|
} else { |
|
scope('if(', STATE, '===', ATTRIB_STATE_POINTER, '){'); |
|
emitBuffer(); |
|
scope('}else{'); |
|
emitConstant(); |
|
scope('}'); |
|
} |
|
} |
|
|
|
attributes.forEach(function (attribute) { |
|
var name = attribute.name; |
|
var arg = args.attributes[name]; |
|
var record; |
|
if (arg) { |
|
if (!filter(arg)) { |
|
return |
|
} |
|
record = arg.append(env, scope); |
|
} else { |
|
if (!filter(SCOPE_DECL)) { |
|
return |
|
} |
|
var scopeAttrib = env.scopeAttrib(name); |
|
check$1.optional(function () { |
|
env.assert(scope, |
|
scopeAttrib + '.state', |
|
'missing attribute ' + name); |
|
}); |
|
record = {}; |
|
Object.keys(new AttributeRecord()).forEach(function (key) { |
|
record[key] = scope.def(scopeAttrib, '.', key); |
|
}); |
|
} |
|
emitBindAttribute( |
|
env.link(attribute), typeLength(attribute.info.type), record); |
|
}); |
|
} |
|
|
|
function emitUniforms (env, scope, args, uniforms, filter) { |
|
var shared = env.shared; |
|
var GL = shared.gl; |
|
|
|
var infix; |
|
for (var i = 0; i < uniforms.length; ++i) { |
|
var uniform = uniforms[i]; |
|
var name = uniform.name; |
|
var type = uniform.info.type; |
|
var arg = args.uniforms[name]; |
|
var UNIFORM = env.link(uniform); |
|
var LOCATION = UNIFORM + '.location'; |
|
|
|
var VALUE; |
|
if (arg) { |
|
if (!filter(arg)) { |
|
continue |
|
} |
|
if (isStatic(arg)) { |
|
var value = arg.value; |
|
check$1.command( |
|
value !== null && typeof value !== 'undefined', |
|
'missing uniform "' + name + '"', env.commandStr); |
|
if (type === GL_SAMPLER_2D || type === GL_SAMPLER_CUBE) { |
|
check$1.command( |
|
typeof value === 'function' && |
|
((type === GL_SAMPLER_2D && |
|
(value._reglType === 'texture2d' || |
|
value._reglType === 'framebuffer')) || |
|
(type === GL_SAMPLER_CUBE && |
|
(value._reglType === 'textureCube' || |
|
value._reglType === 'framebufferCube'))), |
|
'invalid texture for uniform ' + name, env.commandStr); |
|
var TEX_VALUE = env.link(value._texture || value.color[0]._texture); |
|
scope(GL, '.uniform1i(', LOCATION, ',', TEX_VALUE + '.bind());'); |
|
scope.exit(TEX_VALUE, '.unbind();'); |
|
} else if ( |
|
type === GL_FLOAT_MAT2 || |
|
type === GL_FLOAT_MAT3 || |
|
type === GL_FLOAT_MAT4) { |
|
check$1.optional(function () { |
|
check$1.command(isArrayLike(value), |
|
'invalid matrix for uniform ' + name, env.commandStr); |
|
check$1.command( |
|
(type === GL_FLOAT_MAT2 && value.length === 4) || |
|
(type === GL_FLOAT_MAT3 && value.length === 9) || |
|
(type === GL_FLOAT_MAT4 && value.length === 16), |
|
'invalid length for matrix uniform ' + name, env.commandStr); |
|
}); |
|
var MAT_VALUE = env.global.def('new Float32Array([' + |
|
Array.prototype.slice.call(value) + '])'); |
|
var dim = 2; |
|
if (type === GL_FLOAT_MAT3) { |
|
dim = 3; |
|
} else if (type === GL_FLOAT_MAT4) { |
|
dim = 4; |
|
} |
|
scope( |
|
GL, '.uniformMatrix', dim, 'fv(', |
|
LOCATION, ',false,', MAT_VALUE, ');'); |
|
} else { |
|
switch (type) { |
|
case GL_FLOAT$7: |
|
check$1.commandType(value, 'number', 'uniform ' + name, env.commandStr); |
|
infix = '1f'; |
|
break |
|
case GL_FLOAT_VEC2: |
|
check$1.command( |
|
isArrayLike(value) && value.length === 2, |
|
'uniform ' + name, env.commandStr); |
|
infix = '2f'; |
|
break |
|
case GL_FLOAT_VEC3: |
|
check$1.command( |
|
isArrayLike(value) && value.length === 3, |
|
'uniform ' + name, env.commandStr); |
|
infix = '3f'; |
|
break |
|
case GL_FLOAT_VEC4: |
|
check$1.command( |
|
isArrayLike(value) && value.length === 4, |
|
'uniform ' + name, env.commandStr); |
|
infix = '4f'; |
|
break |
|
case GL_BOOL: |
|
check$1.commandType(value, 'boolean', 'uniform ' + name, env.commandStr); |
|
infix = '1i'; |
|
break |
|
case GL_INT$3: |
|
check$1.commandType(value, 'number', 'uniform ' + name, env.commandStr); |
|
infix = '1i'; |
|
break |
|
case GL_BOOL_VEC2: |
|
check$1.command( |
|
isArrayLike(value) && value.length === 2, |
|
'uniform ' + name, env.commandStr); |
|
infix = '2i'; |
|
break |
|
case GL_INT_VEC2: |
|
check$1.command( |
|
isArrayLike(value) && value.length === 2, |
|
'uniform ' + name, env.commandStr); |
|
infix = '2i'; |
|
break |
|
case GL_BOOL_VEC3: |
|
check$1.command( |
|
isArrayLike(value) && value.length === 3, |
|
'uniform ' + name, env.commandStr); |
|
infix = '3i'; |
|
break |
|
case GL_INT_VEC3: |
|
check$1.command( |
|
isArrayLike(value) && value.length === 3, |
|
'uniform ' + name, env.commandStr); |
|
infix = '3i'; |
|
break |
|
case GL_BOOL_VEC4: |
|
check$1.command( |
|
isArrayLike(value) && value.length === 4, |
|
'uniform ' + name, env.commandStr); |
|
infix = '4i'; |
|
break |
|
case GL_INT_VEC4: |
|
check$1.command( |
|
isArrayLike(value) && value.length === 4, |
|
'uniform ' + name, env.commandStr); |
|
infix = '4i'; |
|
break |
|
} |
|
scope(GL, '.uniform', infix, '(', LOCATION, ',', |
|
isArrayLike(value) ? Array.prototype.slice.call(value) : value, |
|
');'); |
|
} |
|
continue |
|
} else { |
|
VALUE = arg.append(env, scope); |
|
} |
|
} else { |
|
if (!filter(SCOPE_DECL)) { |
|
continue |
|
} |
|
VALUE = scope.def(shared.uniforms, '[', stringStore.id(name), ']'); |
|
} |
|
|
|
if (type === GL_SAMPLER_2D) { |
|
scope( |
|
'if(', VALUE, '&&', VALUE, '._reglType==="framebuffer"){', |
|
VALUE, '=', VALUE, '.color[0];', |
|
'}'); |
|
} else if (type === GL_SAMPLER_CUBE) { |
|
scope( |
|
'if(', VALUE, '&&', VALUE, '._reglType==="framebufferCube"){', |
|
VALUE, '=', VALUE, '.color[0];', |
|
'}'); |
|
} |
|
|
|
// perform type validation |
|
check$1.optional(function () { |
|
function check (pred, message) { |
|
env.assert(scope, pred, |
|
'bad data or missing for uniform "' + name + '". ' + message); |
|
} |
|
|
|
function checkType (type) { |
|
check( |
|
'typeof ' + VALUE + '==="' + type + '"', |
|
'invalid type, expected ' + type); |
|
} |
|
|
|
function checkVector (n, type) { |
|
check( |
|
shared.isArrayLike + '(' + VALUE + ')&&' + VALUE + '.length===' + n, |
|
'invalid vector, should have length ' + n, env.commandStr); |
|
} |
|
|
|
function checkTexture (target) { |
|
check( |
|
'typeof ' + VALUE + '==="function"&&' + |
|
VALUE + '._reglType==="texture' + |
|
(target === GL_TEXTURE_2D$2 ? '2d' : 'Cube') + '"', |
|
'invalid texture type', env.commandStr); |
|
} |
|
|
|
switch (type) { |
|
case GL_INT$3: |
|
checkType('number'); |
|
break |
|
case GL_INT_VEC2: |
|
checkVector(2, 'number'); |
|
break |
|
case GL_INT_VEC3: |
|
checkVector(3, 'number'); |
|
break |
|
case GL_INT_VEC4: |
|
checkVector(4, 'number'); |
|
break |
|
case GL_FLOAT$7: |
|
checkType('number'); |
|
break |
|
case GL_FLOAT_VEC2: |
|
checkVector(2, 'number'); |
|
break |
|
case GL_FLOAT_VEC3: |
|
checkVector(3, 'number'); |
|
break |
|
case GL_FLOAT_VEC4: |
|
checkVector(4, 'number'); |
|
break |
|
case GL_BOOL: |
|
checkType('boolean'); |
|
break |
|
case GL_BOOL_VEC2: |
|
checkVector(2, 'boolean'); |
|
break |
|
case GL_BOOL_VEC3: |
|
checkVector(3, 'boolean'); |
|
break |
|
case GL_BOOL_VEC4: |
|
checkVector(4, 'boolean'); |
|
break |
|
case GL_FLOAT_MAT2: |
|
checkVector(4, 'number'); |
|
break |
|
case GL_FLOAT_MAT3: |
|
checkVector(9, 'number'); |
|
break |
|
case GL_FLOAT_MAT4: |
|
checkVector(16, 'number'); |
|
break |
|
case GL_SAMPLER_2D: |
|
checkTexture(GL_TEXTURE_2D$2); |
|
break |
|
case GL_SAMPLER_CUBE: |
|
checkTexture(GL_TEXTURE_CUBE_MAP$1); |
|
break |
|
} |
|
}); |
|
|
|
var unroll = 1; |
|
switch (type) { |
|
case GL_SAMPLER_2D: |
|
case GL_SAMPLER_CUBE: |
|
var TEX = scope.def(VALUE, '._texture'); |
|
scope(GL, '.uniform1i(', LOCATION, ',', TEX, '.bind());'); |
|
scope.exit(TEX, '.unbind();'); |
|
continue |
|
|
|
case GL_INT$3: |
|
case GL_BOOL: |
|
infix = '1i'; |
|
break |
|
|
|
case GL_INT_VEC2: |
|
case GL_BOOL_VEC2: |
|
infix = '2i'; |
|
unroll = 2; |
|
break |
|
|
|
case GL_INT_VEC3: |
|
case GL_BOOL_VEC3: |
|
infix = '3i'; |
|
unroll = 3; |
|
break |
|
|
|
case GL_INT_VEC4: |
|
case GL_BOOL_VEC4: |
|
infix = '4i'; |
|
unroll = 4; |
|
break |
|
|
|
case GL_FLOAT$7: |
|
infix = '1f'; |
|
break |
|
|
|
case GL_FLOAT_VEC2: |
|
infix = '2f'; |
|
unroll = 2; |
|
break |
|
|
|
case GL_FLOAT_VEC3: |
|
infix = '3f'; |
|
unroll = 3; |
|
break |
|
|
|
case GL_FLOAT_VEC4: |
|
infix = '4f'; |
|
unroll = 4; |
|
break |
|
|
|
case GL_FLOAT_MAT2: |
|
infix = 'Matrix2fv'; |
|
break |
|
|
|
case GL_FLOAT_MAT3: |
|
infix = 'Matrix3fv'; |
|
break |
|
|
|
case GL_FLOAT_MAT4: |
|
infix = 'Matrix4fv'; |
|
break |
|
} |
|
|
|
scope(GL, '.uniform', infix, '(', LOCATION, ','); |
|
if (infix.charAt(0) === 'M') { |
|
var matSize = Math.pow(type - GL_FLOAT_MAT2 + 2, 2); |
|
var STORAGE = env.global.def('new Float32Array(', matSize, ')'); |
|
scope( |
|
'false,(Array.isArray(', VALUE, ')||', VALUE, ' instanceof Float32Array)?', VALUE, ':(', |
|
loop(matSize, function (i) { |
|
return STORAGE + '[' + i + ']=' + VALUE + '[' + i + ']' |
|
}), ',', STORAGE, ')'); |
|
} else if (unroll > 1) { |
|
scope(loop(unroll, function (i) { |
|
return VALUE + '[' + i + ']' |
|
})); |
|
} else { |
|
scope(VALUE); |
|
} |
|
scope(');'); |
|
} |
|
} |
|
|
|
function emitDraw (env, outer, inner, args) { |
|
var shared = env.shared; |
|
var GL = shared.gl; |
|
var DRAW_STATE = shared.draw; |
|
|
|
var drawOptions = args.draw; |
|
|
|
function emitElements () { |
|
var defn = drawOptions.elements; |
|
var ELEMENTS; |
|
var scope = outer; |
|
if (defn) { |
|
if ((defn.contextDep && args.contextDynamic) || defn.propDep) { |
|
scope = inner; |
|
} |
|
ELEMENTS = defn.append(env, scope); |
|
} else { |
|
ELEMENTS = scope.def(DRAW_STATE, '.', S_ELEMENTS); |
|
} |
|
if (ELEMENTS) { |
|
scope( |
|
'if(' + ELEMENTS + ')' + |
|
GL + '.bindBuffer(' + GL_ELEMENT_ARRAY_BUFFER$1 + ',' + ELEMENTS + '.buffer.buffer);'); |
|
} |
|
return ELEMENTS |
|
} |
|
|
|
function emitCount () { |
|
var defn = drawOptions.count; |
|
var COUNT; |
|
var scope = outer; |
|
if (defn) { |
|
if ((defn.contextDep && args.contextDynamic) || defn.propDep) { |
|
scope = inner; |
|
} |
|
COUNT = defn.append(env, scope); |
|
check$1.optional(function () { |
|
if (defn.MISSING) { |
|
env.assert(outer, 'false', 'missing vertex count'); |
|
} |
|
if (defn.DYNAMIC) { |
|
env.assert(scope, COUNT + '>=0', 'missing vertex count'); |
|
} |
|
}); |
|
} else { |
|
COUNT = scope.def(DRAW_STATE, '.', S_COUNT); |
|
check$1.optional(function () { |
|
env.assert(scope, COUNT + '>=0', 'missing vertex count'); |
|
}); |
|
} |
|
return COUNT |
|
} |
|
|
|
var ELEMENTS = emitElements(); |
|
function emitValue (name) { |
|
var defn = drawOptions[name]; |
|
if (defn) { |
|
if ((defn.contextDep && args.contextDynamic) || defn.propDep) { |
|
return defn.append(env, inner) |
|
} else { |
|
return defn.append(env, outer) |
|
} |
|
} else { |
|
return outer.def(DRAW_STATE, '.', name) |
|
} |
|
} |
|
|
|
var PRIMITIVE = emitValue(S_PRIMITIVE); |
|
var OFFSET = emitValue(S_OFFSET); |
|
|
|
var COUNT = emitCount(); |
|
if (typeof COUNT === 'number') { |
|
if (COUNT === 0) { |
|
return |
|
} |
|
} else { |
|
inner('if(', COUNT, '){'); |
|
inner.exit('}'); |
|
} |
|
|
|
var INSTANCES, EXT_INSTANCING; |
|
if (extInstancing) { |
|
INSTANCES = emitValue(S_INSTANCES); |
|
EXT_INSTANCING = env.instancing; |
|
} |
|
|
|
var ELEMENT_TYPE = ELEMENTS + '.type'; |
|
|
|
var elementsStatic = drawOptions.elements && isStatic(drawOptions.elements); |
|
|
|
function emitInstancing () { |
|
function drawElements () { |
|
inner(EXT_INSTANCING, '.drawElementsInstancedANGLE(', [ |
|
PRIMITIVE, |
|
COUNT, |
|
ELEMENT_TYPE, |
|
OFFSET + '<<((' + ELEMENT_TYPE + '-' + GL_UNSIGNED_BYTE$7 + ')>>1)', |
|
INSTANCES |
|
], ');'); |
|
} |
|
|
|
function drawArrays () { |
|
inner(EXT_INSTANCING, '.drawArraysInstancedANGLE(', |
|
[PRIMITIVE, OFFSET, COUNT, INSTANCES], ');'); |
|
} |
|
|
|
if (ELEMENTS) { |
|
if (!elementsStatic) { |
|
inner('if(', ELEMENTS, '){'); |
|
drawElements(); |
|
inner('}else{'); |
|
drawArrays(); |
|
inner('}'); |
|
} else { |
|
drawElements(); |
|
} |
|
} else { |
|
drawArrays(); |
|
} |
|
} |
|
|
|
function emitRegular () { |
|
function drawElements () { |
|
inner(GL + '.drawElements(' + [ |
|
PRIMITIVE, |
|
COUNT, |
|
ELEMENT_TYPE, |
|
OFFSET + '<<((' + ELEMENT_TYPE + '-' + GL_UNSIGNED_BYTE$7 + ')>>1)' |
|
] + ');'); |
|
} |
|
|
|
function drawArrays () { |
|
inner(GL + '.drawArrays(' + [PRIMITIVE, OFFSET, COUNT] + ');'); |
|
} |
|
|
|
if (ELEMENTS) { |
|
if (!elementsStatic) { |
|
inner('if(', ELEMENTS, '){'); |
|
drawElements(); |
|
inner('}else{'); |
|
drawArrays(); |
|
inner('}'); |
|
} else { |
|
drawElements(); |
|
} |
|
} else { |
|
drawArrays(); |
|
} |
|
} |
|
|
|
if (extInstancing && (typeof INSTANCES !== 'number' || INSTANCES >= 0)) { |
|
if (typeof INSTANCES === 'string') { |
|
inner('if(', INSTANCES, '>0){'); |
|
emitInstancing(); |
|
inner('}else if(', INSTANCES, '<0){'); |
|
emitRegular(); |
|
inner('}'); |
|
} else { |
|
emitInstancing(); |
|
} |
|
} else { |
|
emitRegular(); |
|
} |
|
} |
|
|
|
function createBody (emitBody, parentEnv, args, program, count) { |
|
var env = createREGLEnvironment(); |
|
var scope = env.proc('body', count); |
|
check$1.optional(function () { |
|
env.commandStr = parentEnv.commandStr; |
|
env.command = env.link(parentEnv.commandStr); |
|
}); |
|
if (extInstancing) { |
|
env.instancing = scope.def( |
|
env.shared.extensions, '.angle_instanced_arrays'); |
|
} |
|
emitBody(env, scope, args, program); |
|
return env.compile().body |
|
} |
|
|
|
// =================================================== |
|
// =================================================== |
|
// DRAW PROC |
|
// =================================================== |
|
// =================================================== |
|
function emitDrawBody (env, draw, args, program) { |
|
injectExtensions(env, draw); |
|
emitAttributes(env, draw, args, program.attributes, function () { |
|
return true |
|
}); |
|
emitUniforms(env, draw, args, program.uniforms, function () { |
|
return true |
|
}); |
|
emitDraw(env, draw, draw, args); |
|
} |
|
|
|
function emitDrawProc (env, args) { |
|
var draw = env.proc('draw', 1); |
|
|
|
injectExtensions(env, draw); |
|
|
|
emitContext(env, draw, args.context); |
|
emitPollFramebuffer(env, draw, args.framebuffer); |
|
|
|
emitPollState(env, draw, args); |
|
emitSetOptions(env, draw, args.state); |
|
|
|
emitProfile(env, draw, args, false, true); |
|
|
|
var program = args.shader.progVar.append(env, draw); |
|
draw(env.shared.gl, '.useProgram(', program, '.program);'); |
|
|
|
if (args.shader.program) { |
|
emitDrawBody(env, draw, args, args.shader.program); |
|
} else { |
|
var drawCache = env.global.def('{}'); |
|
var PROG_ID = draw.def(program, '.id'); |
|
var CACHED_PROC = draw.def(drawCache, '[', PROG_ID, ']'); |
|
draw( |
|
env.cond(CACHED_PROC) |
|
.then(CACHED_PROC, '.call(this,a0);') |
|
.else( |
|
CACHED_PROC, '=', drawCache, '[', PROG_ID, ']=', |
|
env.link(function (program) { |
|
return createBody(emitDrawBody, env, args, program, 1) |
|
}), '(', program, ');', |
|
CACHED_PROC, '.call(this,a0);')); |
|
} |
|
|
|
if (Object.keys(args.state).length > 0) { |
|
draw(env.shared.current, '.dirty=true;'); |
|
} |
|
} |
|
|
|
// =================================================== |
|
// =================================================== |
|
// BATCH PROC |
|
// =================================================== |
|
// =================================================== |
|
|
|
function emitBatchDynamicShaderBody (env, scope, args, program) { |
|
env.batchId = 'a1'; |
|
|
|
injectExtensions(env, scope); |
|
|
|
function all () { |
|
return true |
|
} |
|
|
|
emitAttributes(env, scope, args, program.attributes, all); |
|
emitUniforms(env, scope, args, program.uniforms, all); |
|
emitDraw(env, scope, scope, args); |
|
} |
|
|
|
function emitBatchBody (env, scope, args, program) { |
|
injectExtensions(env, scope); |
|
|
|
var contextDynamic = args.contextDep; |
|
|
|
var BATCH_ID = scope.def(); |
|
var PROP_LIST = 'a0'; |
|
var NUM_PROPS = 'a1'; |
|
var PROPS = scope.def(); |
|
env.shared.props = PROPS; |
|
env.batchId = BATCH_ID; |
|
|
|
var outer = env.scope(); |
|
var inner = env.scope(); |
|
|
|
scope( |
|
outer.entry, |
|
'for(', BATCH_ID, '=0;', BATCH_ID, '<', NUM_PROPS, ';++', BATCH_ID, '){', |
|
PROPS, '=', PROP_LIST, '[', BATCH_ID, '];', |
|
inner, |
|
'}', |
|
outer.exit); |
|
|
|
function isInnerDefn (defn) { |
|
return ((defn.contextDep && contextDynamic) || defn.propDep) |
|
} |
|
|
|
function isOuterDefn (defn) { |
|
return !isInnerDefn(defn) |
|
} |
|
|
|
if (args.needsContext) { |
|
emitContext(env, inner, args.context); |
|
} |
|
if (args.needsFramebuffer) { |
|
emitPollFramebuffer(env, inner, args.framebuffer); |
|
} |
|
emitSetOptions(env, inner, args.state, isInnerDefn); |
|
|
|
if (args.profile && isInnerDefn(args.profile)) { |
|
emitProfile(env, inner, args, false, true); |
|
} |
|
|
|
if (!program) { |
|
var progCache = env.global.def('{}'); |
|
var PROGRAM = args.shader.progVar.append(env, inner); |
|
var PROG_ID = inner.def(PROGRAM, '.id'); |
|
var CACHED_PROC = inner.def(progCache, '[', PROG_ID, ']'); |
|
inner( |
|
env.shared.gl, '.useProgram(', PROGRAM, '.program);', |
|
'if(!', CACHED_PROC, '){', |
|
CACHED_PROC, '=', progCache, '[', PROG_ID, ']=', |
|
env.link(function (program) { |
|
return createBody( |
|
emitBatchDynamicShaderBody, env, args, program, 2) |
|
}), '(', PROGRAM, ');}', |
|
CACHED_PROC, '.call(this,a0[', BATCH_ID, '],', BATCH_ID, ');'); |
|
} else { |
|
emitAttributes(env, outer, args, program.attributes, isOuterDefn); |
|
emitAttributes(env, inner, args, program.attributes, isInnerDefn); |
|
emitUniforms(env, outer, args, program.uniforms, isOuterDefn); |
|
emitUniforms(env, inner, args, program.uniforms, isInnerDefn); |
|
emitDraw(env, outer, inner, args); |
|
} |
|
} |
|
|
|
function emitBatchProc (env, args) { |
|
var batch = env.proc('batch', 2); |
|
env.batchId = '0'; |
|
|
|
injectExtensions(env, batch); |
|
|
|
// Check if any context variables depend on props |
|
var contextDynamic = false; |
|
var needsContext = true; |
|
Object.keys(args.context).forEach(function (name) { |
|
contextDynamic = contextDynamic || args.context[name].propDep; |
|
}); |
|
if (!contextDynamic) { |
|
emitContext(env, batch, args.context); |
|
needsContext = false; |
|
} |
|
|
|
// framebuffer state affects framebufferWidth/height context vars |
|
var framebuffer = args.framebuffer; |
|
var needsFramebuffer = false; |
|
if (framebuffer) { |
|
if (framebuffer.propDep) { |
|
contextDynamic = needsFramebuffer = true; |
|
} else if (framebuffer.contextDep && contextDynamic) { |
|
needsFramebuffer = true; |
|
} |
|
if (!needsFramebuffer) { |
|
emitPollFramebuffer(env, batch, framebuffer); |
|
} |
|
} else { |
|
emitPollFramebuffer(env, batch, null); |
|
} |
|
|
|
// viewport is weird because it can affect context vars |
|
if (args.state.viewport && args.state.viewport.propDep) { |
|
contextDynamic = true; |
|
} |
|
|
|
function isInnerDefn (defn) { |
|
return (defn.contextDep && contextDynamic) || defn.propDep |
|
} |
|
|
|
// set webgl options |
|
emitPollState(env, batch, args); |
|
emitSetOptions(env, batch, args.state, function (defn) { |
|
return !isInnerDefn(defn) |
|
}); |
|
|
|
if (!args.profile || !isInnerDefn(args.profile)) { |
|
emitProfile(env, batch, args, false, 'a1'); |
|
} |
|
|
|
// Save these values to args so that the batch body routine can use them |
|
args.contextDep = contextDynamic; |
|
args.needsContext = needsContext; |
|
args.needsFramebuffer = needsFramebuffer; |
|
|
|
// determine if shader is dynamic |
|
var progDefn = args.shader.progVar; |
|
if ((progDefn.contextDep && contextDynamic) || progDefn.propDep) { |
|
emitBatchBody( |
|
env, |
|
batch, |
|
args, |
|
null); |
|
} else { |
|
var PROGRAM = progDefn.append(env, batch); |
|
batch(env.shared.gl, '.useProgram(', PROGRAM, '.program);'); |
|
if (args.shader.program) { |
|
emitBatchBody( |
|
env, |
|
batch, |
|
args, |
|
args.shader.program); |
|
} else { |
|
var batchCache = env.global.def('{}'); |
|
var PROG_ID = batch.def(PROGRAM, '.id'); |
|
var CACHED_PROC = batch.def(batchCache, '[', PROG_ID, ']'); |
|
batch( |
|
env.cond(CACHED_PROC) |
|
.then(CACHED_PROC, '.call(this,a0,a1);') |
|
.else( |
|
CACHED_PROC, '=', batchCache, '[', PROG_ID, ']=', |
|
env.link(function (program) { |
|
return createBody(emitBatchBody, env, args, program, 2) |
|
}), '(', PROGRAM, ');', |
|
CACHED_PROC, '.call(this,a0,a1);')); |
|
} |
|
} |
|
|
|
if (Object.keys(args.state).length > 0) { |
|
batch(env.shared.current, '.dirty=true;'); |
|
} |
|
} |
|
|
|
// =================================================== |
|
// =================================================== |
|
// SCOPE COMMAND |
|
// =================================================== |
|
// =================================================== |
|
function emitScopeProc (env, args) { |
|
var scope = env.proc('scope', 3); |
|
env.batchId = 'a2'; |
|
|
|
var shared = env.shared; |
|
var CURRENT_STATE = shared.current; |
|
|
|
emitContext(env, scope, args.context); |
|
|
|
if (args.framebuffer) { |
|
args.framebuffer.append(env, scope); |
|
} |
|
|
|
sortState(Object.keys(args.state)).forEach(function (name) { |
|
var defn = args.state[name]; |
|
var value = defn.append(env, scope); |
|
if (isArrayLike(value)) { |
|
value.forEach(function (v, i) { |
|
scope.set(env.next[name], '[' + i + ']', v); |
|
}); |
|
} else { |
|
scope.set(shared.next, '.' + name, value); |
|
} |
|
}); |
|
|
|
emitProfile(env, scope, args, true, true) |
|
|
|
;[S_ELEMENTS, S_OFFSET, S_COUNT, S_INSTANCES, S_PRIMITIVE].forEach( |
|
function (opt) { |
|
var variable = args.draw[opt]; |
|
if (!variable) { |
|
return |
|
} |
|
scope.set(shared.draw, '.' + opt, '' + variable.append(env, scope)); |
|
}); |
|
|
|
Object.keys(args.uniforms).forEach(function (opt) { |
|
scope.set( |
|
shared.uniforms, |
|
'[' + stringStore.id(opt) + ']', |
|
args.uniforms[opt].append(env, scope)); |
|
}); |
|
|
|
Object.keys(args.attributes).forEach(function (name) { |
|
var record = args.attributes[name].append(env, scope); |
|
var scopeAttrib = env.scopeAttrib(name); |
|
Object.keys(new AttributeRecord()).forEach(function (prop) { |
|
scope.set(scopeAttrib, '.' + prop, record[prop]); |
|
}); |
|
}); |
|
|
|
function saveShader (name) { |
|
var shader = args.shader[name]; |
|
if (shader) { |
|
scope.set(shared.shader, '.' + name, shader.append(env, scope)); |
|
} |
|
} |
|
saveShader(S_VERT); |
|
saveShader(S_FRAG); |
|
|
|
if (Object.keys(args.state).length > 0) { |
|
scope(CURRENT_STATE, '.dirty=true;'); |
|
scope.exit(CURRENT_STATE, '.dirty=true;'); |
|
} |
|
|
|
scope('a1(', env.shared.context, ',a0,', env.batchId, ');'); |
|
} |
|
|
|
function isDynamicObject (object) { |
|
if (typeof object !== 'object' || isArrayLike(object)) { |
|
return |
|
} |
|
var props = Object.keys(object); |
|
for (var i = 0; i < props.length; ++i) { |
|
if (dynamic.isDynamic(object[props[i]])) { |
|
return true |
|
} |
|
} |
|
return false |
|
} |
|
|
|
function splatObject (env, options, name) { |
|
var object = options.static[name]; |
|
if (!object || !isDynamicObject(object)) { |
|
return |
|
} |
|
|
|
var globals = env.global; |
|
var keys = Object.keys(object); |
|
var thisDep = false; |
|
var contextDep = false; |
|
var propDep = false; |
|
var objectRef = env.global.def('{}'); |
|
keys.forEach(function (key) { |
|
var value = object[key]; |
|
if (dynamic.isDynamic(value)) { |
|
if (typeof value === 'function') { |
|
value = object[key] = dynamic.unbox(value); |
|
} |
|
var deps = createDynamicDecl(value, null); |
|
thisDep = thisDep || deps.thisDep; |
|
propDep = propDep || deps.propDep; |
|
contextDep = contextDep || deps.contextDep; |
|
} else { |
|
globals(objectRef, '.', key, '='); |
|
switch (typeof value) { |
|
case 'number': |
|
globals(value); |
|
break |
|
case 'string': |
|
globals('"', value, '"'); |
|
break |
|
case 'object': |
|
if (Array.isArray(value)) { |
|
globals('[', value.join(), ']'); |
|
} |
|
break |
|
default: |
|
globals(env.link(value)); |
|
break |
|
} |
|
globals(';'); |
|
} |
|
}); |
|
|
|
function appendBlock (env, block) { |
|
keys.forEach(function (key) { |
|
var value = object[key]; |
|
if (!dynamic.isDynamic(value)) { |
|
return |
|
} |
|
var ref = env.invoke(block, value); |
|
block(objectRef, '.', key, '=', ref, ';'); |
|
}); |
|
} |
|
|
|
options.dynamic[name] = new dynamic.DynamicVariable(DYN_THUNK, { |
|
thisDep: thisDep, |
|
contextDep: contextDep, |
|
propDep: propDep, |
|
ref: objectRef, |
|
append: appendBlock |
|
}); |
|
delete options.static[name]; |
|
} |
|
|
|
// =========================================================================== |
|
// =========================================================================== |
|
// MAIN DRAW COMMAND |
|
// =========================================================================== |
|
// =========================================================================== |
|
function compileCommand (options, attributes, uniforms, context, stats) { |
|
var env = createREGLEnvironment(); |
|
|
|
// link stats, so that we can easily access it in the program. |
|
env.stats = env.link(stats); |
|
|
|
// splat options and attributes to allow for dynamic nested properties |
|
Object.keys(attributes.static).forEach(function (key) { |
|
splatObject(env, attributes, key); |
|
}); |
|
NESTED_OPTIONS.forEach(function (name) { |
|
splatObject(env, options, name); |
|
}); |
|
|
|
var args = parseArguments(options, attributes, uniforms, context, env); |
|
|
|
emitDrawProc(env, args); |
|
emitScopeProc(env, args); |
|
emitBatchProc(env, args); |
|
|
|
return env.compile() |
|
} |
|
|
|
// =========================================================================== |
|
// =========================================================================== |
|
// POLL / REFRESH |
|
// =========================================================================== |
|
// =========================================================================== |
|
return { |
|
next: nextState, |
|
current: currentState, |
|
procs: (function () { |
|
var env = createREGLEnvironment(); |
|
var poll = env.proc('poll'); |
|
var refresh = env.proc('refresh'); |
|
var common = env.block(); |
|
poll(common); |
|
refresh(common); |
|
|
|
var shared = env.shared; |
|
var GL = shared.gl; |
|
var NEXT_STATE = shared.next; |
|
var CURRENT_STATE = shared.current; |
|
|
|
common(CURRENT_STATE, '.dirty=false;'); |
|
|
|
emitPollFramebuffer(env, poll); |
|
emitPollFramebuffer(env, refresh, null, true); |
|
|
|
// Refresh updates all attribute state changes |
|
var extInstancing = gl.getExtension('angle_instanced_arrays'); |
|
var INSTANCING; |
|
if (extInstancing) { |
|
INSTANCING = env.link(extInstancing); |
|
} |
|
for (var i = 0; i < limits.maxAttributes; ++i) { |
|
var BINDING = refresh.def(shared.attributes, '[', i, ']'); |
|
var ifte = env.cond(BINDING, '.buffer'); |
|
ifte.then( |
|
GL, '.enableVertexAttribArray(', i, ');', |
|
GL, '.bindBuffer(', |
|
GL_ARRAY_BUFFER$1, ',', |
|
BINDING, '.buffer.buffer);', |
|
GL, '.vertexAttribPointer(', |
|
i, ',', |
|
BINDING, '.size,', |
|
BINDING, '.type,', |
|
BINDING, '.normalized,', |
|
BINDING, '.stride,', |
|
BINDING, '.offset);' |
|
).else( |
|
GL, '.disableVertexAttribArray(', i, ');', |
|
GL, '.vertexAttrib4f(', |
|
i, ',', |
|
BINDING, '.x,', |
|
BINDING, '.y,', |
|
BINDING, '.z,', |
|
BINDING, '.w);', |
|
BINDING, '.buffer=null;'); |
|
refresh(ifte); |
|
if (extInstancing) { |
|
refresh( |
|
INSTANCING, '.vertexAttribDivisorANGLE(', |
|
i, ',', |
|
BINDING, '.divisor);'); |
|
} |
|
} |
|
|
|
Object.keys(GL_FLAGS).forEach(function (flag) { |
|
var cap = GL_FLAGS[flag]; |
|
var NEXT = common.def(NEXT_STATE, '.', flag); |
|
var block = env.block(); |
|
block('if(', NEXT, '){', |
|
GL, '.enable(', cap, ')}else{', |
|
GL, '.disable(', cap, ')}', |
|
CURRENT_STATE, '.', flag, '=', NEXT, ';'); |
|
refresh(block); |
|
poll( |
|
'if(', NEXT, '!==', CURRENT_STATE, '.', flag, '){', |
|
block, |
|
'}'); |
|
}); |
|
|
|
Object.keys(GL_VARIABLES).forEach(function (name) { |
|
var func = GL_VARIABLES[name]; |
|
var init = currentState[name]; |
|
var NEXT, CURRENT; |
|
var block = env.block(); |
|
block(GL, '.', func, '('); |
|
if (isArrayLike(init)) { |
|
var n = init.length; |
|
NEXT = env.global.def(NEXT_STATE, '.', name); |
|
CURRENT = env.global.def(CURRENT_STATE, '.', name); |
|
block( |
|
loop(n, function (i) { |
|
return NEXT + '[' + i + ']' |
|
}), ');', |
|
loop(n, function (i) { |
|
return CURRENT + '[' + i + ']=' + NEXT + '[' + i + '];' |
|
}).join('')); |
|
poll( |
|
'if(', loop(n, function (i) { |
|
return NEXT + '[' + i + ']!==' + CURRENT + '[' + i + ']' |
|
}).join('||'), '){', |
|
block, |
|
'}'); |
|
} else { |
|
NEXT = common.def(NEXT_STATE, '.', name); |
|
CURRENT = common.def(CURRENT_STATE, '.', name); |
|
block( |
|
NEXT, ');', |
|
CURRENT_STATE, '.', name, '=', NEXT, ';'); |
|
poll( |
|
'if(', NEXT, '!==', CURRENT, '){', |
|
block, |
|
'}'); |
|
} |
|
refresh(block); |
|
}); |
|
|
|
return env.compile() |
|
})(), |
|
compile: compileCommand |
|
} |
|
} |
|
|
|
function stats () { |
|
return { |
|
bufferCount: 0, |
|
elementsCount: 0, |
|
framebufferCount: 0, |
|
shaderCount: 0, |
|
textureCount: 0, |
|
cubeCount: 0, |
|
renderbufferCount: 0, |
|
|
|
maxTextureUnits: 0 |
|
} |
|
} |
|
|
|
var GL_QUERY_RESULT_EXT = 0x8866; |
|
var GL_QUERY_RESULT_AVAILABLE_EXT = 0x8867; |
|
var GL_TIME_ELAPSED_EXT = 0x88BF; |
|
|
|
var createTimer = function (gl, extensions) { |
|
var extTimer = extensions.ext_disjoint_timer_query; |
|
|
|
if (!extTimer) { |
|
return null |
|
} |
|
|
|
// QUERY POOL BEGIN |
|
var queryPool = []; |
|
function allocQuery () { |
|
return queryPool.pop() || extTimer.createQueryEXT() |
|
} |
|
function freeQuery (query) { |
|
queryPool.push(query); |
|
} |
|
// QUERY POOL END |
|
|
|
var pendingQueries = []; |
|
function beginQuery (stats) { |
|
var query = allocQuery(); |
|
extTimer.beginQueryEXT(GL_TIME_ELAPSED_EXT, query); |
|
pendingQueries.push(query); |
|
pushScopeStats(pendingQueries.length - 1, pendingQueries.length, stats); |
|
} |
|
|
|
function endQuery () { |
|
extTimer.endQueryEXT(GL_TIME_ELAPSED_EXT); |
|
} |
|
|
|
// |
|
// Pending stats pool. |
|
// |
|
function PendingStats () { |
|
this.startQueryIndex = -1; |
|
this.endQueryIndex = -1; |
|
this.sum = 0; |
|
this.stats = null; |
|
} |
|
var pendingStatsPool = []; |
|
function allocPendingStats () { |
|
return pendingStatsPool.pop() || new PendingStats() |
|
} |
|
function freePendingStats (pendingStats) { |
|
pendingStatsPool.push(pendingStats); |
|
} |
|
// Pending stats pool end |
|
|
|
var pendingStats = []; |
|
function pushScopeStats (start, end, stats) { |
|
var ps = allocPendingStats(); |
|
ps.startQueryIndex = start; |
|
ps.endQueryIndex = end; |
|
ps.sum = 0; |
|
ps.stats = stats; |
|
pendingStats.push(ps); |
|
} |
|
|
|
// we should call this at the beginning of the frame, |
|
// in order to update gpuTime |
|
var timeSum = []; |
|
var queryPtr = []; |
|
function update () { |
|
var ptr, i; |
|
|
|
var n = pendingQueries.length; |
|
if (n === 0) { |
|
return |
|
} |
|
|
|
// Reserve space |
|
queryPtr.length = Math.max(queryPtr.length, n + 1); |
|
timeSum.length = Math.max(timeSum.length, n + 1); |
|
timeSum[0] = 0; |
|
queryPtr[0] = 0; |
|
|
|
// Update all pending timer queries |
|
var queryTime = 0; |
|
ptr = 0; |
|
for (i = 0; i < pendingQueries.length; ++i) { |
|
var query = pendingQueries[i]; |
|
if (extTimer.getQueryObjectEXT(query, GL_QUERY_RESULT_AVAILABLE_EXT)) { |
|
queryTime += extTimer.getQueryObjectEXT(query, GL_QUERY_RESULT_EXT); |
|
freeQuery(query); |
|
} else { |
|
pendingQueries[ptr++] = query; |
|
} |
|
timeSum[i + 1] = queryTime; |
|
queryPtr[i + 1] = ptr; |
|
} |
|
pendingQueries.length = ptr; |
|
|
|
// Update all pending stat queries |
|
ptr = 0; |
|
for (i = 0; i < pendingStats.length; ++i) { |
|
var stats = pendingStats[i]; |
|
var start = stats.startQueryIndex; |
|
var end = stats.endQueryIndex; |
|
stats.sum += timeSum[end] - timeSum[start]; |
|
var startPtr = queryPtr[start]; |
|
var endPtr = queryPtr[end]; |
|
if (endPtr === startPtr) { |
|
stats.stats.gpuTime += stats.sum / 1e6; |
|
freePendingStats(stats); |
|
} else { |
|
stats.startQueryIndex = startPtr; |
|
stats.endQueryIndex = endPtr; |
|
pendingStats[ptr++] = stats; |
|
} |
|
} |
|
pendingStats.length = ptr; |
|
} |
|
|
|
return { |
|
beginQuery: beginQuery, |
|
endQuery: endQuery, |
|
pushScopeStats: pushScopeStats, |
|
update: update, |
|
getNumPendingQueries: function () { |
|
return pendingQueries.length |
|
}, |
|
clear: function () { |
|
queryPool.push.apply(queryPool, pendingQueries); |
|
for (var i = 0; i < queryPool.length; i++) { |
|
extTimer.deleteQueryEXT(queryPool[i]); |
|
} |
|
pendingQueries.length = 0; |
|
queryPool.length = 0; |
|
}, |
|
restore: function () { |
|
pendingQueries.length = 0; |
|
queryPool.length = 0; |
|
} |
|
} |
|
}; |
|
|
|
var GL_COLOR_BUFFER_BIT = 16384; |
|
var GL_DEPTH_BUFFER_BIT = 256; |
|
var GL_STENCIL_BUFFER_BIT = 1024; |
|
|
|
var GL_ARRAY_BUFFER = 34962; |
|
|
|
var CONTEXT_LOST_EVENT = 'webglcontextlost'; |
|
var CONTEXT_RESTORED_EVENT = 'webglcontextrestored'; |
|
|
|
var DYN_PROP = 1; |
|
var DYN_CONTEXT = 2; |
|
var DYN_STATE = 3; |
|
|
|
function find (haystack, needle) { |
|
for (var i = 0; i < haystack.length; ++i) { |
|
if (haystack[i] === needle) { |
|
return i |
|
} |
|
} |
|
return -1 |
|
} |
|
|
|
function wrapREGL (args) { |
|
var config = parseArgs(args); |
|
if (!config) { |
|
return null |
|
} |
|
|
|
var gl = config.gl; |
|
var glAttributes = gl.getContextAttributes(); |
|
var contextLost = gl.isContextLost(); |
|
|
|
var extensionState = createExtensionCache(gl, config); |
|
if (!extensionState) { |
|
return null |
|
} |
|
|
|
var stringStore = createStringStore(); |
|
var stats$$1 = stats(); |
|
var extensions = extensionState.extensions; |
|
var timer = createTimer(gl, extensions); |
|
|
|
var START_TIME = clock(); |
|
var WIDTH = gl.drawingBufferWidth; |
|
var HEIGHT = gl.drawingBufferHeight; |
|
|
|
var contextState = { |
|
tick: 0, |
|
time: 0, |
|
viewportWidth: WIDTH, |
|
viewportHeight: HEIGHT, |
|
framebufferWidth: WIDTH, |
|
framebufferHeight: HEIGHT, |
|
drawingBufferWidth: WIDTH, |
|
drawingBufferHeight: HEIGHT, |
|
pixelRatio: config.pixelRatio |
|
}; |
|
var uniformState = {}; |
|
var drawState = { |
|
elements: null, |
|
primitive: 4, // GL_TRIANGLES |
|
count: -1, |
|
offset: 0, |
|
instances: -1 |
|
}; |
|
|
|
var limits = wrapLimits(gl, extensions); |
|
var bufferState = wrapBufferState(gl, stats$$1, config); |
|
var elementState = wrapElementsState(gl, extensions, bufferState, stats$$1); |
|
var attributeState = wrapAttributeState( |
|
gl, |
|
extensions, |
|
limits, |
|
bufferState, |
|
stringStore); |
|
var shaderState = wrapShaderState(gl, stringStore, stats$$1, config); |
|
var textureState = createTextureSet( |
|
gl, |
|
extensions, |
|
limits, |
|
function () { core.procs.poll(); }, |
|
contextState, |
|
stats$$1, |
|
config); |
|
var renderbufferState = wrapRenderbuffers(gl, extensions, limits, stats$$1, config); |
|
var framebufferState = wrapFBOState( |
|
gl, |
|
extensions, |
|
limits, |
|
textureState, |
|
renderbufferState, |
|
stats$$1); |
|
var core = reglCore( |
|
gl, |
|
stringStore, |
|
extensions, |
|
limits, |
|
bufferState, |
|
elementState, |
|
textureState, |
|
framebufferState, |
|
uniformState, |
|
attributeState, |
|
shaderState, |
|
drawState, |
|
contextState, |
|
timer, |
|
config); |
|
var readPixels = wrapReadPixels( |
|
gl, |
|
framebufferState, |
|
core.procs.poll, |
|
contextState, |
|
glAttributes, extensions); |
|
|
|
var nextState = core.next; |
|
var canvas = gl.canvas; |
|
|
|
var rafCallbacks = []; |
|
var lossCallbacks = []; |
|
var restoreCallbacks = []; |
|
var destroyCallbacks = [config.onDestroy]; |
|
|
|
var activeRAF = null; |
|
function handleRAF () { |
|
if (rafCallbacks.length === 0) { |
|
if (timer) { |
|
timer.update(); |
|
} |
|
activeRAF = null; |
|
return |
|
} |
|
|
|
// schedule next animation frame |
|
activeRAF = raf.next(handleRAF); |
|
|
|
// poll for changes |
|
poll(); |
|
|
|
// fire a callback for all pending rafs |
|
for (var i = rafCallbacks.length - 1; i >= 0; --i) { |
|
var cb = rafCallbacks[i]; |
|
if (cb) { |
|
cb(contextState, null, 0); |
|
} |
|
} |
|
|
|
// flush all pending webgl calls |
|
gl.flush(); |
|
|
|
// poll GPU timers *after* gl.flush so we don't delay command dispatch |
|
if (timer) { |
|
timer.update(); |
|
} |
|
} |
|
|
|
function startRAF () { |
|
if (!activeRAF && rafCallbacks.length > 0) { |
|
activeRAF = raf.next(handleRAF); |
|
} |
|
} |
|
|
|
function stopRAF () { |
|
if (activeRAF) { |
|
raf.cancel(handleRAF); |
|
activeRAF = null; |
|
} |
|
} |
|
|
|
function handleContextLoss (event) { |
|
event.preventDefault(); |
|
|
|
// set context lost flag |
|
contextLost = true; |
|
|
|
// pause request animation frame |
|
stopRAF(); |
|
|
|
// lose context |
|
lossCallbacks.forEach(function (cb) { |
|
cb(); |
|
}); |
|
} |
|
|
|
function handleContextRestored (event) { |
|
// clear error code |
|
gl.getError(); |
|
|
|
// clear context lost flag |
|
contextLost = false; |
|
|
|
// refresh state |
|
extensionState.restore(); |
|
shaderState.restore(); |
|
bufferState.restore(); |
|
textureState.restore(); |
|
renderbufferState.restore(); |
|
framebufferState.restore(); |
|
if (timer) { |
|
timer.restore(); |
|
} |
|
|
|
// refresh state |
|
core.procs.refresh(); |
|
|
|
// restart RAF |
|
startRAF(); |
|
|
|
// restore context |
|
restoreCallbacks.forEach(function (cb) { |
|
cb(); |
|
}); |
|
} |
|
|
|
if (canvas) { |
|
canvas.addEventListener(CONTEXT_LOST_EVENT, handleContextLoss, false); |
|
canvas.addEventListener(CONTEXT_RESTORED_EVENT, handleContextRestored, false); |
|
} |
|
|
|
function destroy () { |
|
rafCallbacks.length = 0; |
|
stopRAF(); |
|
|
|
if (canvas) { |
|
canvas.removeEventListener(CONTEXT_LOST_EVENT, handleContextLoss); |
|
canvas.removeEventListener(CONTEXT_RESTORED_EVENT, handleContextRestored); |
|
} |
|
|
|
shaderState.clear(); |
|
framebufferState.clear(); |
|
renderbufferState.clear(); |
|
textureState.clear(); |
|
elementState.clear(); |
|
bufferState.clear(); |
|
|
|
if (timer) { |
|
timer.clear(); |
|
} |
|
|
|
destroyCallbacks.forEach(function (cb) { |
|
cb(); |
|
}); |
|
} |
|
|
|
function compileProcedure (options) { |
|
check$1(!!options, 'invalid args to regl({...})'); |
|
check$1.type(options, 'object', 'invalid args to regl({...})'); |
|
|
|
function flattenNestedOptions (options) { |
|
var result = extend({}, options); |
|
delete result.uniforms; |
|
delete result.attributes; |
|
delete result.context; |
|
|
|
if ('stencil' in result && result.stencil.op) { |
|
result.stencil.opBack = result.stencil.opFront = result.stencil.op; |
|
delete result.stencil.op; |
|
} |
|
|
|
function merge (name) { |
|
if (name in result) { |
|
var child = result[name]; |
|
delete result[name]; |
|
Object.keys(child).forEach(function (prop) { |
|
result[name + '.' + prop] = child[prop]; |
|
}); |
|
} |
|
} |
|
merge('blend'); |
|
merge('depth'); |
|
merge('cull'); |
|
merge('stencil'); |
|
merge('polygonOffset'); |
|
merge('scissor'); |
|
merge('sample'); |
|
|
|
return result |
|
} |
|
|
|
function separateDynamic (object) { |
|
var staticItems = {}; |
|
var dynamicItems = {}; |
|
Object.keys(object).forEach(function (option) { |
|
var value = object[option]; |
|
if (dynamic.isDynamic(value)) { |
|
dynamicItems[option] = dynamic.unbox(value, option); |
|
} else { |
|
staticItems[option] = value; |
|
} |
|
}); |
|
return { |
|
dynamic: dynamicItems, |
|
static: staticItems |
|
} |
|
} |
|
|
|
// Treat context variables separate from other dynamic variables |
|
var context = separateDynamic(options.context || {}); |
|
var uniforms = separateDynamic(options.uniforms || {}); |
|
var attributes = separateDynamic(options.attributes || {}); |
|
var opts = separateDynamic(flattenNestedOptions(options)); |
|
|
|
var stats$$1 = { |
|
gpuTime: 0.0, |
|
cpuTime: 0.0, |
|
count: 0 |
|
}; |
|
|
|
var compiled = core.compile(opts, attributes, uniforms, context, stats$$1); |
|
|
|
var draw = compiled.draw; |
|
var batch = compiled.batch; |
|
var scope = compiled.scope; |
|
|
|
// FIXME: we should modify code generation for batch commands so this |
|
// isn't necessary |
|
var EMPTY_ARRAY = []; |
|
function reserve (count) { |
|
while (EMPTY_ARRAY.length < count) { |
|
EMPTY_ARRAY.push(null); |
|
} |
|
return EMPTY_ARRAY |
|
} |
|
|
|
function REGLCommand (args, body) { |
|
var i; |
|
if (contextLost) { |
|
check$1.raise('context lost'); |
|
} |
|
if (typeof args === 'function') { |
|
return scope.call(this, null, args, 0) |
|
} else if (typeof body === 'function') { |
|
if (typeof args === 'number') { |
|
for (i = 0; i < args; ++i) { |
|
scope.call(this, null, body, i); |
|
} |
|
return |
|
} else if (Array.isArray(args)) { |
|
for (i = 0; i < args.length; ++i) { |
|
scope.call(this, args[i], body, i); |
|
} |
|
return |
|
} else { |
|
return scope.call(this, args, body, 0) |
|
} |
|
} else if (typeof args === 'number') { |
|
if (args > 0) { |
|
return batch.call(this, reserve(args | 0), args | 0) |
|
} |
|
} else if (Array.isArray(args)) { |
|
if (args.length) { |
|
return batch.call(this, args, args.length) |
|
} |
|
} else { |
|
return draw.call(this, args) |
|
} |
|
} |
|
|
|
return extend(REGLCommand, { |
|
stats: stats$$1 |
|
}) |
|
} |
|
|
|
var setFBO = framebufferState.setFBO = compileProcedure({ |
|
framebuffer: dynamic.define.call(null, DYN_PROP, 'framebuffer') |
|
}); |
|
|
|
function clearImpl (_, options) { |
|
var clearFlags = 0; |
|
core.procs.poll(); |
|
|
|
var c = options.color; |
|
if (c) { |
|
gl.clearColor(+c[0] || 0, +c[1] || 0, +c[2] || 0, +c[3] || 0); |
|
clearFlags |= GL_COLOR_BUFFER_BIT; |
|
} |
|
if ('depth' in options) { |
|
gl.clearDepth(+options.depth); |
|
clearFlags |= GL_DEPTH_BUFFER_BIT; |
|
} |
|
if ('stencil' in options) { |
|
gl.clearStencil(options.stencil | 0); |
|
clearFlags |= GL_STENCIL_BUFFER_BIT; |
|
} |
|
|
|
check$1(!!clearFlags, 'called regl.clear with no buffer specified'); |
|
gl.clear(clearFlags); |
|
} |
|
|
|
function clear (options) { |
|
check$1( |
|
typeof options === 'object' && options, |
|
'regl.clear() takes an object as input'); |
|
if ('framebuffer' in options) { |
|
if (options.framebuffer && |
|
options.framebuffer_reglType === 'framebufferCube') { |
|
for (var i = 0; i < 6; ++i) { |
|
setFBO(extend({ |
|
framebuffer: options.framebuffer.faces[i] |
|
}, options), clearImpl); |
|
} |
|
} else { |
|
setFBO(options, clearImpl); |
|
} |
|
} else { |
|
clearImpl(null, options); |
|
} |
|
} |
|
|
|
function frame (cb) { |
|
check$1.type(cb, 'function', 'regl.frame() callback must be a function'); |
|
rafCallbacks.push(cb); |
|
|
|
function cancel () { |
|
// FIXME: should we check something other than equals cb here? |
|
// what if a user calls frame twice with the same callback... |
|
// |
|
var i = find(rafCallbacks, cb); |
|
check$1(i >= 0, 'cannot cancel a frame twice'); |
|
function pendingCancel () { |
|
var index = find(rafCallbacks, pendingCancel); |
|
rafCallbacks[index] = rafCallbacks[rafCallbacks.length - 1]; |
|
rafCallbacks.length -= 1; |
|
if (rafCallbacks.length <= 0) { |
|
stopRAF(); |
|
} |
|
} |
|
rafCallbacks[i] = pendingCancel; |
|
} |
|
|
|
startRAF(); |
|
|
|
return { |
|
cancel: cancel |
|
} |
|
} |
|
|
|
// poll viewport |
|
function pollViewport () { |
|
var viewport = nextState.viewport; |
|
var scissorBox = nextState.scissor_box; |
|
viewport[0] = viewport[1] = scissorBox[0] = scissorBox[1] = 0; |
|
contextState.viewportWidth = |
|
contextState.framebufferWidth = |
|
contextState.drawingBufferWidth = |
|
viewport[2] = |
|
scissorBox[2] = gl.drawingBufferWidth; |
|
contextState.viewportHeight = |
|
contextState.framebufferHeight = |
|
contextState.drawingBufferHeight = |
|
viewport[3] = |
|
scissorBox[3] = gl.drawingBufferHeight; |
|
} |
|
|
|
function poll () { |
|
contextState.tick += 1; |
|
contextState.time = now(); |
|
pollViewport(); |
|
core.procs.poll(); |
|
} |
|
|
|
function refresh () { |
|
pollViewport(); |
|
core.procs.refresh(); |
|
if (timer) { |
|
timer.update(); |
|
} |
|
} |
|
|
|
function now () { |
|
return (clock() - START_TIME) / 1000.0 |
|
} |
|
|
|
refresh(); |
|
|
|
function addListener (event, callback) { |
|
check$1.type(callback, 'function', 'listener callback must be a function'); |
|
|
|
var callbacks; |
|
switch (event) { |
|
case 'frame': |
|
return frame(callback) |
|
case 'lost': |
|
callbacks = lossCallbacks; |
|
break |
|
case 'restore': |
|
callbacks = restoreCallbacks; |
|
break |
|
case 'destroy': |
|
callbacks = destroyCallbacks; |
|
break |
|
default: |
|
check$1.raise('invalid event, must be one of frame,lost,restore,destroy'); |
|
} |
|
|
|
callbacks.push(callback); |
|
return { |
|
cancel: function () { |
|
for (var i = 0; i < callbacks.length; ++i) { |
|
if (callbacks[i] === callback) { |
|
callbacks[i] = callbacks[callbacks.length - 1]; |
|
callbacks.pop(); |
|
return |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
var regl = extend(compileProcedure, { |
|
// Clear current FBO |
|
clear: clear, |
|
|
|
// Short cuts for dynamic variables |
|
prop: dynamic.define.bind(null, DYN_PROP), |
|
context: dynamic.define.bind(null, DYN_CONTEXT), |
|
this: dynamic.define.bind(null, DYN_STATE), |
|
|
|
// executes an empty draw command |
|
draw: compileProcedure({}), |
|
|
|
// Resources |
|
buffer: function (options) { |
|
return bufferState.create(options, GL_ARRAY_BUFFER, false, false) |
|
}, |
|
elements: function (options) { |
|
return elementState.create(options, false) |
|
}, |
|
texture: textureState.create2D, |
|
cube: textureState.createCube, |
|
renderbuffer: renderbufferState.create, |
|
framebuffer: framebufferState.create, |
|
framebufferCube: framebufferState.createCube, |
|
|
|
// Expose context attributes |
|
attributes: glAttributes, |
|
|
|
// Frame rendering |
|
frame: frame, |
|
on: addListener, |
|
|
|
// System limits |
|
limits: limits, |
|
hasExtension: function (name) { |
|
return limits.extensions.indexOf(name.toLowerCase()) >= 0 |
|
}, |
|
|
|
// Read pixels |
|
read: readPixels, |
|
|
|
// Destroy regl and all associated resources |
|
destroy: destroy, |
|
|
|
// Direct GL state manipulation |
|
_gl: gl, |
|
_refresh: refresh, |
|
|
|
poll: function () { |
|
poll(); |
|
if (timer) { |
|
timer.update(); |
|
} |
|
}, |
|
|
|
// Current time |
|
now: now, |
|
|
|
// regl Statistics Information |
|
stats: stats$$1 |
|
}); |
|
|
|
config.onDone(null, regl); |
|
|
|
return regl |
|
} |
|
|
|
return wrapREGL; |
|
|
|
}))); |
|
//# sourceMappingURL=regl.js.map |
|
|
|
|
|
/***/ }), |
|
/* 47 */ |
|
/***/ (function(module, exports) { |
|
|
|
// shim for using process in browser |
|
var process = module.exports = {}; |
|
|
|
// cached from whatever global is present so that test runners that stub it |
|
// don't break things. But we need to wrap it in a try catch in case it is |
|
// wrapped in strict mode code which doesn't define any globals. It's inside a |
|
// function because try/catches deoptimize in certain engines. |
|
|
|
var cachedSetTimeout; |
|
var cachedClearTimeout; |
|
|
|
function defaultSetTimout() { |
|
throw new Error('setTimeout has not been defined'); |
|
} |
|
function defaultClearTimeout () { |
|
throw new Error('clearTimeout has not been defined'); |
|
} |
|
(function () { |
|
try { |
|
if (typeof setTimeout === 'function') { |
|
cachedSetTimeout = setTimeout; |
|
} else { |
|
cachedSetTimeout = defaultSetTimout; |
|
} |
|
} catch (e) { |
|
cachedSetTimeout = defaultSetTimout; |
|
} |
|
try { |
|
if (typeof clearTimeout === 'function') { |
|
cachedClearTimeout = clearTimeout; |
|
} else { |
|
cachedClearTimeout = defaultClearTimeout; |
|
} |
|
} catch (e) { |
|
cachedClearTimeout = defaultClearTimeout; |
|
} |
|
} ()) |
|
function runTimeout(fun) { |
|
if (cachedSetTimeout === setTimeout) { |
|
//normal enviroments in sane situations |
|
return setTimeout(fun, 0); |
|
} |
|
// if setTimeout wasn't available but was latter defined |
|
if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { |
|
cachedSetTimeout = setTimeout; |
|
return setTimeout(fun, 0); |
|
} |
|
try { |
|
// when when somebody has screwed with setTimeout but no I.E. maddness |
|
return cachedSetTimeout(fun, 0); |
|
} catch(e){ |
|
try { |
|
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally |
|
return cachedSetTimeout.call(null, fun, 0); |
|
} catch(e){ |
|
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error |
|
return cachedSetTimeout.call(this, fun, 0); |
|
} |
|
} |
|
|
|
|
|
} |
|
function runClearTimeout(marker) { |
|
if (cachedClearTimeout === clearTimeout) { |
|
//normal enviroments in sane situations |
|
return clearTimeout(marker); |
|
} |
|
// if clearTimeout wasn't available but was latter defined |
|
if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { |
|
cachedClearTimeout = clearTimeout; |
|
return clearTimeout(marker); |
|
} |
|
try { |
|
// when when somebody has screwed with setTimeout but no I.E. maddness |
|
return cachedClearTimeout(marker); |
|
} catch (e){ |
|
try { |
|
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally |
|
return cachedClearTimeout.call(null, marker); |
|
} catch (e){ |
|
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. |
|
// Some versions of I.E. have different rules for clearTimeout vs setTimeout |
|
return cachedClearTimeout.call(this, marker); |
|
} |
|
} |
|
|
|
|
|
|
|
} |
|
var queue = []; |
|
var draining = false; |
|
var currentQueue; |
|
var queueIndex = -1; |
|
|
|
function cleanUpNextTick() { |
|
if (!draining || !currentQueue) { |
|
return; |
|
} |
|
draining = false; |
|
if (currentQueue.length) { |
|
queue = currentQueue.concat(queue); |
|
} else { |
|
queueIndex = -1; |
|
} |
|
if (queue.length) { |
|
drainQueue(); |
|
} |
|
} |
|
|
|
function drainQueue() { |
|
if (draining) { |
|
return; |
|
} |
|
var timeout = runTimeout(cleanUpNextTick); |
|
draining = true; |
|
|
|
var len = queue.length; |
|
while(len) { |
|
currentQueue = queue; |
|
queue = []; |
|
while (++queueIndex < len) { |
|
if (currentQueue) { |
|
currentQueue[queueIndex].run(); |
|
} |
|
} |
|
queueIndex = -1; |
|
len = queue.length; |
|
} |
|
currentQueue = null; |
|
draining = false; |
|
runClearTimeout(timeout); |
|
} |
|
|
|
process.nextTick = function (fun) { |
|
var args = new Array(arguments.length - 1); |
|
if (arguments.length > 1) { |
|
for (var i = 1; i < arguments.length; i++) { |
|
args[i - 1] = arguments[i]; |
|
} |
|
} |
|
queue.push(new Item(fun, args)); |
|
if (queue.length === 1 && !draining) { |
|
runTimeout(drainQueue); |
|
} |
|
}; |
|
|
|
// v8 likes predictible objects |
|
function Item(fun, array) { |
|
this.fun = fun; |
|
this.array = array; |
|
} |
|
Item.prototype.run = function () { |
|
this.fun.apply(null, this.array); |
|
}; |
|
process.title = 'browser'; |
|
process.browser = true; |
|
process.env = {}; |
|
process.argv = []; |
|
process.version = ''; // empty string to avoid regexp issues |
|
process.versions = {}; |
|
|
|
function noop() {} |
|
|
|
process.on = noop; |
|
process.addListener = noop; |
|
process.once = noop; |
|
process.off = noop; |
|
process.removeListener = noop; |
|
process.removeAllListeners = noop; |
|
process.emit = noop; |
|
process.prependListener = noop; |
|
process.prependOnceListener = noop; |
|
|
|
process.listeners = function (name) { return [] } |
|
|
|
process.binding = function (name) { |
|
throw new Error('process.binding is not supported'); |
|
}; |
|
|
|
process.cwd = function () { return '/' }; |
|
process.chdir = function (dir) { |
|
throw new Error('process.chdir is not supported'); |
|
}; |
|
process.umask = function() { return 0; }; |
|
|
|
|
|
/***/ }), |
|
/* 48 */ |
|
/***/ (function(module, exports, __webpack_require__) { |
|
|
|
module.exports = __webpack_require__(6); |
|
|
|
|
|
/***/ }) |
|
/******/ ]); |