From 9261b7ca5e3492b39333b86800e00b325b5539ee Mon Sep 17 00:00:00 2001 From: Jeremy Hu Date: Fri, 26 Jul 2019 14:15:33 +0930 Subject: [PATCH] Add THREE.Vector3 and THREE.Ququaternion from three.js --- ACKNOWLEDGEMENTS.html | 25 + resources.qrc | 1 + src/scriptrunner.cpp | 18 + thirdparty/three.js/LICENSE | 21 + thirdparty/three.js/README.md | 1 + thirdparty/three.js/dust3d.three.js | 1455 +++++++++++++++++++++++++++ 6 files changed, 1521 insertions(+) create mode 100644 thirdparty/three.js/LICENSE create mode 100644 thirdparty/three.js/README.md create mode 100644 thirdparty/three.js/dust3d.three.js diff --git a/ACKNOWLEDGEMENTS.html b/ACKNOWLEDGEMENTS.html index 1f89812f..72111eb2 100644 --- a/ACKNOWLEDGEMENTS.html +++ b/ACKNOWLEDGEMENTS.html @@ -1170,3 +1170,28 @@ https://www.reddit.com/r/gamedev/comments/5iuf3h/i_am_writting_a_3d_monster_mode # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. + +

three.js

+
+    The MIT License
+
+    Copyright © 2010-2019 three.js authors
+
+    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.
+
\ No newline at end of file diff --git a/resources.qrc b/resources.qrc index 94b59616..2f8d5a95 100644 --- a/resources.qrc +++ b/resources.qrc @@ -25,6 +25,7 @@ shaders/default.core.frag shaders/pbr-qt.frag shaders/pbr-joey.frag + thirdparty/three.js/dust3d.three.js languages/dust3d_zh_CN.qm ACKNOWLEDGEMENTS.html AUTHORS diff --git a/src/scriptrunner.cpp b/src/scriptrunner.cpp index ae778a64..a387fe50 100644 --- a/src/scriptrunner.cpp +++ b/src/scriptrunner.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "scriptrunner.h" #include "util.h" @@ -580,8 +581,25 @@ void ScriptRunner::run() JS_SetPropertyStr(context, console, "log", JS_NewCFunction(context, js_print, "log", 1)); + JS_SetPropertyStr(context, + console, "warn", + JS_NewCFunction(context, js_print, "warn", 1)); + JS_SetPropertyStr(context, + console, "error", + JS_NewCFunction(context, js_print, "error", 1)); JS_SetPropertyStr(context, globalObject, "console", console); + QFile file(":/thirdparty/three.js/dust3d.three.js"); + if (file.open(QIODevice::ReadOnly)) { + QByteArray fileContent = file.readAll(); + JSValue three = JS_NewObject(context); + JS_SetPropertyStr(context, globalObject, "THREE", three); + JSValue object = JS_Eval(context, (char *)fileContent.constData(), fileContent.size(), "", + JS_EVAL_TYPE_GLOBAL); + JS_FreeValue(context, object); + file.close(); + } + JS_FreeValue(context, globalObject); JSValue object = JS_Eval(context, buffer.constData(), buffer.size(), "", diff --git a/thirdparty/three.js/LICENSE b/thirdparty/three.js/LICENSE new file mode 100644 index 00000000..d3400897 --- /dev/null +++ b/thirdparty/three.js/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright © 2010-2019 three.js authors + +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. diff --git a/thirdparty/three.js/README.md b/thirdparty/three.js/README.md new file mode 100644 index 00000000..788179fc --- /dev/null +++ b/thirdparty/three.js/README.md @@ -0,0 +1 @@ +This is a modified version, which only includes limited 3D Math libraries for Dust3D, please check [three.js](https://threejs.org/) for full version. diff --git a/thirdparty/three.js/dust3d.three.js b/thirdparty/three.js/dust3d.three.js new file mode 100644 index 00000000..1e657dd6 --- /dev/null +++ b/thirdparty/three.js/dust3d.three.js @@ -0,0 +1,1455 @@ +var _Math = {}; +var Vector3 = {}; +var Quaternion = {}; + +_Math = { + + DEG2RAD: Math.PI / 180, + RAD2DEG: 180 / Math.PI, + + generateUUID: ( function () { + + // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136 + + var lut = []; + + for ( var i = 0; i < 256; i ++ ) { + + lut[ i ] = ( i < 16 ? '0' : '' ) + ( i ).toString( 16 ); + + } + + return function generateUUID() { + + var d0 = Math.random() * 0xffffffff | 0; + var d1 = Math.random() * 0xffffffff | 0; + var d2 = Math.random() * 0xffffffff | 0; + var d3 = Math.random() * 0xffffffff | 0; + var uuid = lut[ d0 & 0xff ] + lut[ d0 >> 8 & 0xff ] + lut[ d0 >> 16 & 0xff ] + lut[ d0 >> 24 & 0xff ] + '-' + + lut[ d1 & 0xff ] + lut[ d1 >> 8 & 0xff ] + '-' + lut[ d1 >> 16 & 0x0f | 0x40 ] + lut[ d1 >> 24 & 0xff ] + '-' + + lut[ d2 & 0x3f | 0x80 ] + lut[ d2 >> 8 & 0xff ] + '-' + lut[ d2 >> 16 & 0xff ] + lut[ d2 >> 24 & 0xff ] + + lut[ d3 & 0xff ] + lut[ d3 >> 8 & 0xff ] + lut[ d3 >> 16 & 0xff ] + lut[ d3 >> 24 & 0xff ]; + + // .toUpperCase() here flattens concatenated strings to save heap memory space. + return uuid.toUpperCase(); + + }; + + } )(), + + clamp: function ( value, min, max ) { + + return Math.max( min, Math.min( max, value ) ); + + }, + + // compute euclidian modulo of m % n + // https://en.wikipedia.org/wiki/Modulo_operation + + euclideanModulo: function ( n, m ) { + + return ( ( n % m ) + m ) % m; + + }, + + // Linear mapping from range to range + + mapLinear: function ( x, a1, a2, b1, b2 ) { + + return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); + + }, + + // https://en.wikipedia.org/wiki/Linear_interpolation + + lerp: function ( x, y, t ) { + + return ( 1 - t ) * x + t * y; + + }, + + // http://en.wikipedia.org/wiki/Smoothstep + + smoothstep: function ( x, min, max ) { + + if ( x <= min ) return 0; + if ( x >= max ) return 1; + + x = ( x - min ) / ( max - min ); + + return x * x * ( 3 - 2 * x ); + + }, + + smootherstep: function ( x, min, max ) { + + if ( x <= min ) return 0; + if ( x >= max ) return 1; + + x = ( x - min ) / ( max - min ); + + return x * x * x * ( x * ( x * 6 - 15 ) + 10 ); + + }, + + // Random integer from interval + + randInt: function ( low, high ) { + + return low + Math.floor( Math.random() * ( high - low + 1 ) ); + + }, + + // Random float from interval + + randFloat: function ( low, high ) { + + return low + Math.random() * ( high - low ); + + }, + + // Random float from <-range/2, range/2> interval + + randFloatSpread: function ( range ) { + + return range * ( 0.5 - Math.random() ); + + }, + + degToRad: function ( degrees ) { + + return degrees * _Math.DEG2RAD; + + }, + + radToDeg: function ( radians ) { + + return radians * _Math.RAD2DEG; + + }, + + isPowerOfTwo: function ( value ) { + + return ( value & ( value - 1 ) ) === 0 && value !== 0; + + }, + + ceilPowerOfTwo: function ( value ) { + + return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) ); + + }, + + floorPowerOfTwo: function ( value ) { + + return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) ); + + } + +}; + +////////////////////////////////////////////////////////////////////////////// + +Quaternion = function ( x, y, z, w ) { + + this._x = x || 0; + this._y = y || 0; + this._z = z || 0; + this._w = ( w !== undefined ) ? w : 1; + + this.slerp = function ( qa, qb, qm, t ) { + + return qm.copy( qa ).slerp( qb, t ); + + }, + + this.slerpFlat = function ( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) { + + // fuzz-free, array-based Quaternion SLERP operation + + var x0 = src0[ srcOffset0 + 0 ], + y0 = src0[ srcOffset0 + 1 ], + z0 = src0[ srcOffset0 + 2 ], + w0 = src0[ srcOffset0 + 3 ], + + x1 = src1[ srcOffset1 + 0 ], + y1 = src1[ srcOffset1 + 1 ], + z1 = src1[ srcOffset1 + 2 ], + w1 = src1[ srcOffset1 + 3 ]; + + if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) { + + var s = 1 - t, + + cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, + + dir = ( cos >= 0 ? 1 : - 1 ), + sqrSin = 1 - cos * cos; + + // Skip the Slerp for tiny steps to avoid numeric problems: + if ( sqrSin > Number.EPSILON ) { + + var sin = Math.sqrt( sqrSin ), + len = Math.atan2( sin, cos * dir ); + + s = Math.sin( s * len ) / sin; + t = Math.sin( t * len ) / sin; + + } + + var tDir = t * dir; + + x0 = x0 * s + x1 * tDir; + y0 = y0 * s + y1 * tDir; + z0 = z0 * s + z1 * tDir; + w0 = w0 * s + w1 * tDir; + + // Normalize in case we just did a lerp: + if ( s === 1 - t ) { + + var f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 ); + + x0 *= f; + y0 *= f; + z0 *= f; + w0 *= f; + + } + + } + + dst[ dstOffset ] = x0; + dst[ dstOffset + 1 ] = y0; + dst[ dstOffset + 2 ] = z0; + dst[ dstOffset + 3 ] = w0; + + }; + + this.isQuaternion = true; + + this.set = function ( x, y, z, w ) { + + this._x = x; + this._y = y; + this._z = z; + this._w = w; + + return this; + + }; + + this.clone = function () { + + return new this.constructor( this._x, this._y, this._z, this._w ); + + }; + + this.copy = function ( quaternion ) { + + this._x = quaternion.x; + this._y = quaternion.y; + this._z = quaternion.z; + this._w = quaternion.w; + + return this; + + }; + + this.setFromEuler = function ( euler, update ) { + + if ( ! ( euler && euler.isEuler ) ) { + + throw new Error( 'Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' ); + + } + + var x = euler._x, y = euler._y, z = euler._z, order = euler.order; + + // http://www.mathworks.com/matlabcentral/fileexchange/ + // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ + // content/SpinCalc.m + + var cos = Math.cos; + var sin = Math.sin; + + var c1 = cos( x / 2 ); + var c2 = cos( y / 2 ); + var c3 = cos( z / 2 ); + + var s1 = sin( x / 2 ); + var s2 = sin( y / 2 ); + var s3 = sin( z / 2 ); + + if ( order === 'XYZ' ) { + + this._x = s1 * c2 * c3 + c1 * s2 * s3; + this._y = c1 * s2 * c3 - s1 * c2 * s3; + this._z = c1 * c2 * s3 + s1 * s2 * c3; + this._w = c1 * c2 * c3 - s1 * s2 * s3; + + } else if ( order === 'YXZ' ) { + + this._x = s1 * c2 * c3 + c1 * s2 * s3; + this._y = c1 * s2 * c3 - s1 * c2 * s3; + this._z = c1 * c2 * s3 - s1 * s2 * c3; + this._w = c1 * c2 * c3 + s1 * s2 * s3; + + } else if ( order === 'ZXY' ) { + + this._x = s1 * c2 * c3 - c1 * s2 * s3; + this._y = c1 * s2 * c3 + s1 * c2 * s3; + this._z = c1 * c2 * s3 + s1 * s2 * c3; + this._w = c1 * c2 * c3 - s1 * s2 * s3; + + } else if ( order === 'ZYX' ) { + + this._x = s1 * c2 * c3 - c1 * s2 * s3; + this._y = c1 * s2 * c3 + s1 * c2 * s3; + this._z = c1 * c2 * s3 - s1 * s2 * c3; + this._w = c1 * c2 * c3 + s1 * s2 * s3; + + } else if ( order === 'YZX' ) { + + this._x = s1 * c2 * c3 + c1 * s2 * s3; + this._y = c1 * s2 * c3 + s1 * c2 * s3; + this._z = c1 * c2 * s3 - s1 * s2 * c3; + this._w = c1 * c2 * c3 - s1 * s2 * s3; + + } else if ( order === 'XZY' ) { + + this._x = s1 * c2 * c3 - c1 * s2 * s3; + this._y = c1 * s2 * c3 - s1 * c2 * s3; + this._z = c1 * c2 * s3 + s1 * s2 * c3; + this._w = c1 * c2 * c3 + s1 * s2 * s3; + + } + + return this; + + }; + + this.setFromAxisAngle = function ( axis, angle ) { + + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm + + // assumes axis is normalized + + var halfAngle = angle / 2, s = Math.sin( halfAngle ); + + this._x = axis.x * s; + this._y = axis.y * s; + this._z = axis.z * s; + this._w = Math.cos( halfAngle ); + + return this; + + }; + + this.setFromRotationMatrix = function ( m ) { + + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm + + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + + var te = m.elements, + + m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], + m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], + m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ], + + trace = m11 + m22 + m33, + s; + + if ( trace > 0 ) { + + s = 0.5 / Math.sqrt( trace + 1.0 ); + + this._w = 0.25 / s; + this._x = ( m32 - m23 ) * s; + this._y = ( m13 - m31 ) * s; + this._z = ( m21 - m12 ) * s; + + } else if ( m11 > m22 && m11 > m33 ) { + + s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); + + this._w = ( m32 - m23 ) / s; + this._x = 0.25 * s; + this._y = ( m12 + m21 ) / s; + this._z = ( m13 + m31 ) / s; + + } else if ( m22 > m33 ) { + + s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); + + this._w = ( m13 - m31 ) / s; + this._x = ( m12 + m21 ) / s; + this._y = 0.25 * s; + this._z = ( m23 + m32 ) / s; + + } else { + + s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); + + this._w = ( m21 - m12 ) / s; + this._x = ( m13 + m31 ) / s; + this._y = ( m23 + m32 ) / s; + this._z = 0.25 * s; + + } + + return this; + + }; + + this.setFromUnitVectors = function ( vFrom, vTo ) { + + // assumes direction vectors vFrom and vTo are normalized + + var EPS = 0.000001; + + var r = vFrom.dot( vTo ) + 1; + + if ( r < EPS ) { + + r = 0; + + if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { + + this._x = - vFrom.y; + this._y = vFrom.x; + this._z = 0; + this._w = r; + + } else { + + this._x = 0; + this._y = - vFrom.z; + this._z = vFrom.y; + this._w = r; + + } + + } else { + + // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3 + + this._x = vFrom.y * vTo.z - vFrom.z * vTo.y; + this._y = vFrom.z * vTo.x - vFrom.x * vTo.z; + this._z = vFrom.x * vTo.y - vFrom.y * vTo.x; + this._w = r; + + } + + return this.normalize(); + + }; + + this.angleTo = function ( q ) { + + return 2 * Math.acos( Math.abs( _Math.clamp( this.dot( q ), - 1, 1 ) ) ); + + }; + + this.rotateTowards = function ( q, step ) { + + var angle = this.angleTo( q ); + + if ( angle === 0 ) return this; + + var t = Math.min( 1, step / angle ); + + this.slerp( q, t ); + + return this; + + }; + + this.inverse = function () { + + // quaternion is assumed to have unit length + + return this.conjugate(); + + }; + + this.conjugate = function () { + + this._x *= - 1; + this._y *= - 1; + this._z *= - 1; + + return this; + + }; + + this.dot = function ( v ) { + + return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; + + }; + + this.lengthSq = function () { + + return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; + + }; + + this.length = function () { + + return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); + + }; + + this.normalize = function () { + + var l = this.length(); + + if ( l === 0 ) { + + this._x = 0; + this._y = 0; + this._z = 0; + this._w = 1; + + } else { + + l = 1 / l; + + this._x = this._x * l; + this._y = this._y * l; + this._z = this._z * l; + this._w = this._w * l; + + } + + return this; + + }; + + this.multiply = function ( q, p ) { + + if ( p !== undefined ) { + + console.warn( 'Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); + return this.multiplyQuaternions( q, p ); + + } + + return this.multiplyQuaternions( this, q ); + + }; + + this.premultiply = function ( q ) { + + return this.multiplyQuaternions( q, this ); + + }; + + this.multiplyQuaternions = function ( a, b ) { + + // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm + + var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; + var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; + + this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; + this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; + this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; + this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; + + return this; + + }; + + this.slerp = function ( qb, t ) { + + if ( t === 0 ) return this; + if ( t === 1 ) return this.copy( qb ); + + var x = this._x, y = this._y, z = this._z, w = this._w; + + // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ + + var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; + + if ( cosHalfTheta < 0 ) { + + this._w = - qb._w; + this._x = - qb._x; + this._y = - qb._y; + this._z = - qb._z; + + cosHalfTheta = - cosHalfTheta; + + } else { + + this.copy( qb ); + + } + + if ( cosHalfTheta >= 1.0 ) { + + this._w = w; + this._x = x; + this._y = y; + this._z = z; + + return this; + + } + + var sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta; + + if ( sqrSinHalfTheta <= Number.EPSILON ) { + + var s = 1 - t; + this._w = s * w + t * this._w; + this._x = s * x + t * this._x; + this._y = s * y + t * this._y; + this._z = s * z + t * this._z; + + this.normalize(); + + return this; + + } + + var sinHalfTheta = Math.sqrt( sqrSinHalfTheta ); + var halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta ); + var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, + ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; + + this._w = ( w * ratioA + this._w * ratioB ); + this._x = ( x * ratioA + this._x * ratioB ); + this._y = ( y * ratioA + this._y * ratioB ); + this._z = ( z * ratioA + this._z * ratioB ); + + return this; + + }; + + this.equals = function ( quaternion ) { + + return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); + + }; + + this.fromArray = function ( array, offset ) { + + if ( offset === undefined ) offset = 0; + + this._x = array[ offset ]; + this._y = array[ offset + 1 ]; + this._z = array[ offset + 2 ]; + this._w = array[ offset + 3 ]; + + return this; + + }; + + this.toArray = function ( array, offset ) { + + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; + + array[ offset ] = this._x; + array[ offset + 1 ] = this._y; + array[ offset + 2 ] = this._z; + array[ offset + 3 ] = this._w; + + return array; + + }; +}; + +Object.defineProperties( Quaternion.prototype, { + + x: { + + get: function () { + + return this._x; + + }, + + set: function ( value ) { + + this._x = value; + + } + + }, + + y: { + + get: function () { + + return this._y; + + }, + + set: function ( value ) { + + this._y = value; + + } + + }, + + z: { + + get: function () { + + return this._z; + + }, + + set: function ( value ) { + + this._z = value; + + } + + }, + + w: { + + get: function () { + + return this._w; + + }, + + set: function ( value ) { + + this._w = value; + + } + + } + +} ); + +/////////////////////////////////////////////////////////////// + +Vector3 = function( x, y, z ) { + + this.x = x || 0; + this.y = y || 0; + this.z = z || 0; + + this.isVector3 = true; + + this.set = function ( x, y, z ) { + + this.x = x; + this.y = y; + this.z = z; + + return this; + + }; + + this.setScalar = function ( scalar ) { + + this.x = scalar; + this.y = scalar; + this.z = scalar; + + return this; + + }; + + this.setX = function ( x ) { + + this.x = x; + + return this; + + }; + + this.setY = function ( y ) { + + this.y = y; + + return this; + + }; + + this.setZ = function ( z ) { + + this.z = z; + + return this; + + }; + + this.setComponent = function ( index, value ) { + + switch ( index ) { + + case 0: this.x = value; break; + case 1: this.y = value; break; + case 2: this.z = value; break; + default: throw new Error( 'index is out of range: ' + index ); + + } + + return this; + + }; + + this.getComponent = function ( index ) { + + switch ( index ) { + + case 0: return this.x; + case 1: return this.y; + case 2: return this.z; + default: throw new Error( 'index is out of range: ' + index ); + + } + + }; + + this.clone = function () { + + return new this.constructor( this.x, this.y, this.z ); + + }; + + this.copy = function ( v ) { + + this.x = v.x; + this.y = v.y; + this.z = v.z; + + return this; + + }; + + this.add = function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + return this.addVectors( v, w ); + + } + + this.x += v.x; + this.y += v.y; + this.z += v.z; + + return this; + + }; + + this.addScalar = function ( s ) { + + this.x += s; + this.y += s; + this.z += s; + + return this; + + }; + + this.addVectors = function ( a, b ) { + + this.x = a.x + b.x; + this.y = a.y + b.y; + this.z = a.z + b.z; + + return this; + + }; + + this.addScaledVector = function ( v, s ) { + + this.x += v.x * s; + this.y += v.y * s; + this.z += v.z * s; + + return this; + + }; + + this.sub = function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + return this.subVectors( v, w ); + + } + + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; + + return this; + + }; + + this.subScalar = function ( s ) { + + this.x -= s; + this.y -= s; + this.z -= s; + + return this; + + }; + + this.subVectors = function ( a, b ) { + + this.x = a.x - b.x; + this.y = a.y - b.y; + this.z = a.z - b.z; + + return this; + + }; + + this.multiply = function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' ); + return this.multiplyVectors( v, w ); + + } + + this.x *= v.x; + this.y *= v.y; + this.z *= v.z; + + return this; + + }; + + this.multiplyScalar = function ( scalar ) { + + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; + + return this; + + }; + + this.multiplyVectors = function ( a, b ) { + + this.x = a.x * b.x; + this.y = a.y * b.y; + this.z = a.z * b.z; + + return this; + + }; + + /* + this.applyEuler = function () { + + var quaternion = new Quaternion(); + + return function applyEuler( euler ) { + + if ( ! ( euler && euler.isEuler ) ) { + + console.error( 'Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.' ); + + } + + return this.applyQuaternion( quaternion.setFromEuler( euler ) ); + + }; + + }(); + + this.applyAxisAngle = function () { + + var quaternion = new Quaternion(); + + return function applyAxisAngle( axis, angle ) { + + return this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) ); + + }; + + }(); + */ + + this.applyMatrix3 = function ( m ) { + + var x = this.x, y = this.y, z = this.z; + var e = m.elements; + + this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z; + this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z; + this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z; + + return this; + + }; + + this.applyMatrix4 = function ( m ) { + + var x = this.x, y = this.y, z = this.z; + var e = m.elements; + + var w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); + + this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w; + this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w; + this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w; + + return this; + + }; + + this.applyQuaternion = function ( q ) { + + var x = this.x, y = this.y, z = this.z; + var qx = q.x, qy = q.y, qz = q.z, qw = q.w; + + // calculate quat * vector + + var ix = qw * x + qy * z - qz * y; + var iy = qw * y + qz * x - qx * z; + var iz = qw * z + qx * y - qy * x; + var iw = - qx * x - qy * y - qz * z; + + // calculate result * inverse quat + + this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy; + this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz; + this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx; + + return this; + + }; + + this.project = function ( camera ) { + + console.error( 'Vector3: .project() is not supported in modified version' ); + + return this; + + }; + + this.unproject = function ( camera ) { + + console.error( 'Vector3: .unproject() is not supported in modified version' ); + + return this; + + }; + + this.transformDirection = function ( m ) { + + // input: Matrix4 affine matrix + // vector interpreted as a direction + + var x = this.x, y = this.y, z = this.z; + var e = m.elements; + + this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z; + this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z; + this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z; + + return this.normalize(); + + }; + + this.divide = function ( v ) { + + this.x /= v.x; + this.y /= v.y; + this.z /= v.z; + + return this; + + }; + + this.divideScalar = function ( scalar ) { + + return this.multiplyScalar( 1 / scalar ); + + }; + + this.min = function ( v ) { + + this.x = Math.min( this.x, v.x ); + this.y = Math.min( this.y, v.y ); + this.z = Math.min( this.z, v.z ); + + return this; + + }; + + this.max = function ( v ) { + + this.x = Math.max( this.x, v.x ); + this.y = Math.max( this.y, v.y ); + this.z = Math.max( this.z, v.z ); + + return this; + + }; + + this.clamp = function ( min, max ) { + + // assumes min < max, componentwise + + this.x = Math.max( min.x, Math.min( max.x, this.x ) ); + this.y = Math.max( min.y, Math.min( max.y, this.y ) ); + this.z = Math.max( min.z, Math.min( max.z, this.z ) ); + + return this; + + }; + + this.clampScalar = function ( minVal, maxVal ) { + + this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); + this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); + this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); + + return this; + + }; + + this.clampLength = function ( min, max ) { + + var length = this.length(); + + return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); + + }; + + this.floor = function () { + + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + this.z = Math.floor( this.z ); + + return this; + + }; + + this.ceil = function () { + + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + this.z = Math.ceil( this.z ); + + return this; + + }; + + this.round = function () { + + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + this.z = Math.round( this.z ); + + return this; + + }; + + this.roundToZero = function () { + + this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); + this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); + this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); + + return this; + + }; + + this.negate = function () { + + this.x = - this.x; + this.y = - this.y; + this.z = - this.z; + + return this; + + }; + + this.dot = function ( v ) { + + return this.x * v.x + this.y * v.y + this.z * v.z; + + }; + + // TODO lengthSquared? + + this.lengthSq = function () { + + return this.x * this.x + this.y * this.y + this.z * this.z; + + }; + + this.length = function () { + + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); + + }; + + this.manhattanLength = function () { + + return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); + + }; + + this.normalize = function () { + + return this.divideScalar( this.length() || 1 ); + + }; + + this.setLength = function ( length ) { + + return this.normalize().multiplyScalar( length ); + + }; + + this.lerp = function ( v, alpha ) { + + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + this.z += ( v.z - this.z ) * alpha; + + return this; + + }; + + this.lerpVectors = function ( v1, v2, alpha ) { + + return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); + + }; + + this.cross = function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' ); + return this.crossVectors( v, w ); + + } + + return this.crossVectors( this, v ); + + }; + + this.crossVectors = function ( a, b ) { + + var ax = a.x, ay = a.y, az = a.z; + var bx = b.x, by = b.y, bz = b.z; + + this.x = ay * bz - az * by; + this.y = az * bx - ax * bz; + this.z = ax * by - ay * bx; + + return this; + + }; + + this.projectOnVector = function ( vector ) { + + var scalar = vector.dot( this ) / vector.lengthSq(); + + return this.copy( vector ).multiplyScalar( scalar ); + + }; + + /* + this.projectOnPlane = function () { + + var v1 = new Vector3(); + + return function projectOnPlane( planeNormal ) { + + v1.copy( this ).projectOnVector( planeNormal ); + + return this.sub( v1 ); + + }; + + }(); + */ + + /* + this.reflect = function () { + + // reflect incident vector off plane orthogonal to normal + // normal is assumed to have unit length + + var v1 = new Vector3(); + + return function reflect( normal ) { + + return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); + + }; + + }(); + */ + + this.angleTo = function ( v ) { + + var theta = this.dot( v ) / ( Math.sqrt( this.lengthSq() * v.lengthSq() ) ); + + // clamp, to handle numerical problems + + return Math.acos( _Math.clamp( theta, - 1, 1 ) ); + + }; + + this.distanceTo = function ( v ) { + + return Math.sqrt( this.distanceToSquared( v ) ); + + }; + + this.distanceToSquared = function ( v ) { + + var dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; + + return dx * dx + dy * dy + dz * dz; + + }; + + this.manhattanDistanceTo = function ( v ) { + + return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z ); + + }; + + this.setFromSpherical = function ( s ) { + + return this.setFromSphericalCoords( s.radius, s.phi, s.theta ); + + }; + + this.setFromSphericalCoords = function ( radius, phi, theta ) { + + var sinPhiRadius = Math.sin( phi ) * radius; + + this.x = sinPhiRadius * Math.sin( theta ); + this.y = Math.cos( phi ) * radius; + this.z = sinPhiRadius * Math.cos( theta ); + + return this; + + }; + + this.setFromCylindrical = function ( c ) { + + console.error( 'Vector3: .setFromCylindrical() is not supported in modified version' ); + + return this; + + }; + + this.setFromCylindricalCoords = function ( radius, theta, y ) { + + this.x = radius * Math.sin( theta ); + this.y = y; + this.z = radius * Math.cos( theta ); + + return this; + + }; + + this.setFromMatrixPosition = function ( m ) { + + var e = m.elements; + + this.x = e[ 12 ]; + this.y = e[ 13 ]; + this.z = e[ 14 ]; + + return this; + + }; + + this.setFromMatrixScale = function ( m ) { + + var sx = this.setFromMatrixColumn( m, 0 ).length(); + var sy = this.setFromMatrixColumn( m, 1 ).length(); + var sz = this.setFromMatrixColumn( m, 2 ).length(); + + this.x = sx; + this.y = sy; + this.z = sz; + + return this; + + }; + + this.setFromMatrixColumn = function ( m, index ) { + + return this.fromArray( m.elements, index * 4 ); + + }; + + this.equals = function ( v ) { + + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); + + }; + + this.fromArray = function ( array, offset ) { + + if ( offset === undefined ) offset = 0; + + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; + this.z = array[ offset + 2 ]; + + return this; + + }; + + this.toArray = function ( array, offset ) { + + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; + + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; + array[ offset + 2 ] = this.z; + + return array; + + }; + + this.fromBufferAttribute = function ( attribute, index, offset ) { + + if ( offset !== undefined ) { + + console.warn( 'Vector3: offset has been removed from .fromBufferAttribute().' ); + + } + + this.x = attribute.getX( index ); + this.y = attribute.getY( index ); + this.z = attribute.getZ( index ); + + return this; + + }; + +}; + +//////////////////////////////////////////////////////////////////// + +THREE._Math = _Math; +THREE.Vector3 = Vector3; +THREE.Quaternion = Quaternion;