Spaces:
Paused
Paused
| /* | |
| * Real3D FlipBook [https://real3dflipbook.com] | |
| * @author creativeinteractivemedia [https://codecanyon.net/user/creativeinteractivemedia/portfolio] | |
| * @version 4.10 | |
| * @date 2025-05-15 | |
| */ | |
| /** | |
| * MOD3 3D Modifier Library for JavaScript | |
| * port of AS3DMod ActionScript3 library (http://code.google.com/p/as3dmod/) | |
| * | |
| * @version 1.0.0 (2023-01-03 16:08:34) | |
| * https://github.com/foo123/MOD3 | |
| * | |
| **//** | |
| * MOD3 3D Modifier Library for JavaScript | |
| * port of AS3DMod ActionScript3 library (http://code.google.com/p/as3dmod/) | |
| * | |
| * @version 1.0.0 (2023-01-03 16:08:34) | |
| * https://github.com/foo123/MOD3 | |
| * | |
| **/ | |
| !function(root, name, factory) { | |
| ; | |
| if (('object' === typeof module) && module.exports) /* CommonJS */ | |
| (module.$deps = module.$deps||{}) && (module.exports = module.$deps[name] = factory.call(root)); | |
| else if (('function' === typeof define) && define.amd && ('function' === typeof require) && ('function' === typeof require.specified) && require.specified(name) /*&& !require.defined(name)*/) /* AMD */ | |
| define(name, ['module'], function(module) {factory.moduleUri = module.uri; return factory.call(root);}); | |
| else if (!(name in root)) /* Browser/WebWorker/.. */ | |
| (root[name] = factory.call(root)||1) && ('function' === typeof(define)) && define.amd && define(function() {return root[name];}); | |
| }( /* current root */ 'undefined' !== typeof self ? self : this, | |
| /* module name */ "MOD3", | |
| /* module factory */ function ModuleFactory__MOD3(undef) { | |
| ; | |
| var HAS = Object.prototype.hasOwnProperty, | |
| toString = Object.prototype.toString, | |
| def = Object.defineProperty, | |
| stdMath = Math, PI = stdMath.PI, | |
| TWO_PI = 2*PI, HALF_PI = PI/2, INV_PI = 1/PI, | |
| EMPTY_ARR = [], EMPTY_OBJ = {}, NOP = function() {}, | |
| isNode = ("undefined" !== typeof global) && ("[object global]" === toString.call(global)), | |
| isBrowser = ("undefined" !== typeof window) && ("[object Window]" === toString.call(window)) | |
| ; | |
| // basic backwards-compatible "class" construction | |
| function makeSuper(superklass) | |
| { | |
| var called = {}; | |
| return function $super(method, args) { | |
| var self = this, m = ':'+method, ret; | |
| if (1 === called[m]) return (superklass.prototype.$super || NOP).call(self, method, args); | |
| called[m] = 1; | |
| ret = ('constructor' === method ? superklass : (superklass.prototype[method] || NOP)).apply(self, args || []); | |
| called[m] = 0; | |
| return ret; | |
| }; | |
| } | |
| function makeClass(superklass, klass, statik) | |
| { | |
| if (arguments.length < 2) | |
| { | |
| klass = superklass; | |
| superklass = null; | |
| } | |
| var C = HAS.call(klass, 'constructor') ? klass.constructor : function() {}, p; | |
| if (superklass) | |
| { | |
| C.prototype = Object.create(superklass.prototype); | |
| C.prototype.$super = makeSuper(superklass); | |
| } | |
| else | |
| { | |
| C.prototype.$super = NOP; | |
| } | |
| C.prototype.constructor = C; | |
| for (p in klass) | |
| { | |
| if (HAS.call(klass, p) && ('constructor' !== p)) | |
| { | |
| C.prototype[p] = klass[p]; | |
| } | |
| } | |
| if (statik) | |
| { | |
| for (p in statik) | |
| { | |
| if (HAS.call(statik, p)) | |
| { | |
| C[p] = statik[p]; | |
| } | |
| } | |
| } | |
| return C; | |
| } | |
| var MOD3 = { | |
| VERSION: "1.0.0", | |
| Class: makeClass | |
| }; | |
| /** | |
| * MOD3 Constants and Auxilliary methods | |
| **/ | |
| MOD3.Constants = { | |
| // cache math constants for reference and optimization | |
| PI: PI, | |
| invPI: INV_PI, | |
| halfPI: HALF_PI, | |
| doublePI: TWO_PI, | |
| toRad: PI/180, | |
| toDeg: 180/PI | |
| }; | |
| MOD3.ModConstant = { | |
| NONE: 0, | |
| LEFT: -1, | |
| RIGHT: 1, | |
| X: 1, | |
| Y: 2, | |
| Z: 4, | |
| Xi: 0, | |
| Yi: 1, | |
| Zi: 2 | |
| }; | |
| MOD3.XYZi = [ | |
| null, | |
| 0, | |
| 1, | |
| null, | |
| 2 | |
| ]; | |
| MOD3.iXYZ = [ | |
| 1, | |
| 2, | |
| 4 | |
| ]; | |
| MOD3.xyz = [ | |
| "x", | |
| "y", | |
| "z" | |
| ]; | |
| MOD3.XYZ = [ | |
| "X", | |
| "Y", | |
| "Z" | |
| ]; | |
| // Typed Arrays Substitutes | |
| MOD3.Array32F = typeof Float32Array !== "undefined" ? Float32Array : Array; | |
| MOD3.Array64F = typeof Float64Array !== "undefined" ? Float64Array : Array; | |
| MOD3.Array8I = typeof Int8Array !== "undefined" ? Int8Array : Array; | |
| MOD3.Array16I = typeof Int16Array !== "undefined" ? Int16Array : Array; | |
| MOD3.Array32I = typeof Int32Array !== "undefined" ? Int32Array : Array; | |
| MOD3.Array8U = typeof Uint8Array !== "undefined" ? Uint8Array : Array; | |
| MOD3.Array16U = typeof Uint16Array !== "undefined" ? Uint16Array : Array; | |
| MOD3.Array32U = typeof Uint32Array !== "undefined" ? Uint32Array : Array; | |
| // vector typed-array | |
| MOD3.VecArray = MOD3.Array32F; | |
| /** | |
| * MOD3 Math Utilities Class | |
| **/ | |
| MOD3.XMath = { | |
| normalize: function(start, end, val) { | |
| var range = end - start; | |
| return 0 === range ? 1 : MOD3.XMath.trim(0, 1, (val - start)/end); | |
| }, | |
| toRange: function(start, end, normalized) { | |
| var range = end - start; | |
| return 0 === range ? 0 : (start + range*normalized); | |
| }, | |
| inRange: function(start, end, value, excluding) { | |
| return false !== excluding ? (value >= start && value <= end) : (value > start && value < end); | |
| }, | |
| sign: function(val, ifZero) { | |
| return 0 === val ? (ifZero || 0) : (val > 0 ? 1 : -1); | |
| }, | |
| trim: function(start, end, value) { | |
| return value < start ? start : (value > end ? end : value); | |
| }, | |
| wrap: function(start, end, value) { | |
| var r = end - start; | |
| return value < start ? (value + r) : (value >= end ? value - r : value); | |
| }, | |
| degToRad: function(deg) { | |
| return deg/180*PI; | |
| }, | |
| radToDeg: function(rad) { | |
| return rad/PI*180; | |
| }, | |
| presicion: function(number, precision) { | |
| var r = stdMath.pow(10, precision); | |
| return stdMath.round(number*r)/r; | |
| }, | |
| uceil: function(val) { | |
| return val < 0 ? stdMath.floor(val) : stdMath.ceil(val); | |
| } | |
| }; | |
| // alias | |
| MOD3.XMath.clamp = MOD3.XMath.trim; | |
| /** | |
| * MOD3 Range Auxilliary Class | |
| **/ | |
| MOD3.Range = MOD3.Class({ | |
| constructor: function Range(s, e) { | |
| var self = this; | |
| if (!(self instanceof Range)) return new Range(s, e); | |
| self.start = null != s ? s : 0; | |
| self.end = null != e ? e : 1; | |
| }, | |
| name: "Range", | |
| start: 0, | |
| end: 1, | |
| dispose: function() { | |
| var self = this; | |
| self.start = null; | |
| self.end = null; | |
| return self; | |
| }, | |
| getSize: function() { | |
| return this.end - this.start; | |
| }, | |
| move: function(amount) { | |
| this.start += amount; | |
| this.end += amount; | |
| }, | |
| isIn: function(n) { | |
| return (n >= this.start && n <= this.end); | |
| }, | |
| normalize: function(n) { | |
| return MOD3.XMath.normalize(this.start, this.end, n); | |
| }, | |
| toRange: function(n) { | |
| return MOD3.XMath.toRange(this.start, this.end, n); | |
| }, | |
| trim: function(n) { | |
| return MOD3.XMath.trim(this.start, this.end, n); | |
| }, | |
| interpolate: function(n, r) { | |
| return MOD3.XMath.toRange(this.start, this.end, r.normalize(n)); | |
| }, | |
| toString: function() { | |
| return "[" + this.start + " - " + this.end + "]"; | |
| } | |
| }); | |
| /** | |
| * MOD3 Phase Auxilliary Class | |
| **/ | |
| MOD3.Phase = MOD3.Class({ | |
| constructor: function Phase(v) { | |
| var self = this; | |
| if (!(self instanceof Phase)) return new Phase(v); | |
| self.value = v || 0; | |
| }, | |
| name: "Phase", | |
| value: 0, | |
| dispose: function() { | |
| this.value = null; | |
| return this; | |
| }, | |
| getPhasedValue: function() { | |
| return stdMath.sin(this.value); | |
| }, | |
| getAbsPhasedValue: function() { | |
| return stdMath.abs(stdMath.sin(this.value)); | |
| }, | |
| getNormValue: function() { | |
| return (stdMath.sin(this.value) + 1)*0.5; | |
| } | |
| }); | |
| /** | |
| * MOD3 2D Point Class | |
| **/ | |
| MOD3.Point = MOD3.Class({ | |
| constructor: function Point(x, y) { | |
| var self = this; | |
| if (!(self instanceof Point)) return new Point(x, y); | |
| self.x = x || 0; | |
| self.y = y || 0; | |
| }, | |
| name: "Point", | |
| x: 0, | |
| y: 0, | |
| dispose: function() { | |
| var self = this; | |
| self.x = null; | |
| self.y = null; | |
| return self; | |
| }, | |
| clone: function() { | |
| return new MOD3.Point(this.x, this.y); | |
| } | |
| }); | |
| /** | |
| * MOD3 2D Transform Matrix Class | |
| **/ | |
| MOD3.Matrix = MOD3.Class(null, { | |
| constructor: function Matrix(m11, m12, | |
| m21, m22) | |
| { | |
| var self = this; | |
| if (!(self instanceof Matrix)) return new Matrix(m11, m12, | |
| m21, m22); | |
| self.m = new MOD3.VecArray([ | |
| m11 == null ? 1 : m11, | |
| m12 == null ? 0 : m12, | |
| m21 == null ? 0 : m21, | |
| m22 == null ? 1 : m22 | |
| ]); | |
| }, | |
| name: "Matrix", | |
| m: null, | |
| dispose: function() { | |
| this.m = null; | |
| return this; | |
| }, | |
| reset: function() { | |
| var m = this.m; | |
| m[0] = 1; m[1] = 0; | |
| m[2] = 0; m[3] = 1; | |
| return this; | |
| }, | |
| rotate: function(angle) { | |
| var m = this.m, c = stdMath.cos(angle), s = stdMath.sin(angle); | |
| m[0] = c; m[1] = -s; | |
| m[2] = s; m[3] = c; | |
| return this; | |
| }, | |
| scale: function(sx, sy) { | |
| var m = this.m; | |
| m[0] = 1; m[1] = 0; | |
| m[2] = 0; m[3] = 1; | |
| if (sx != null) | |
| { | |
| m[0] = sx; | |
| m[3] = sx; | |
| } | |
| if (sy != null) | |
| { | |
| m[3] = sy; | |
| } | |
| return this; | |
| }, | |
| multiply: function(b) { | |
| return MOD3.Matrix.mult(this, b); | |
| }, | |
| transformPoint: function(p) { | |
| var xy = MOD3.Matrix.transform(this, [p.x, p.y]); | |
| return new MOD3.Point(xy[0], xy[1]); | |
| }, | |
| transformPointSelf: function(p) { | |
| var xy = MOD3.Matrix.transform(this, [p.x, p.y]); | |
| p.x = xy[0]; p.y = xy[1]; | |
| return p; | |
| }, | |
| clone: function() { | |
| var m = this.m; | |
| return new MOD3.Matrix(m[0], m[1], | |
| m[2], m[3]); | |
| } | |
| }, { | |
| transform: function(m2, xy) { | |
| var m = m2.m, x = xy[0], y = xy[1]; | |
| xy[0] = m[0]*x + m[1]*y; | |
| xy[1] = m[2]*x + m[3]*y; | |
| return xy; | |
| }, | |
| mult: function(m1, m2) { | |
| var a = m1.m, b = m2.m, a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; | |
| a[0] = a0*b[0] + a1*b[2]; | |
| a[1] = a0*b[1] + a1*b[3]; | |
| a[2] = a2*b[0] + a3*b[2]; | |
| a[3] = a2*b[1] + a3*b[3]; | |
| return m1; | |
| } | |
| }); | |
| /** | |
| * MOD3 Vector3 Class | |
| **/ | |
| MOD3.Vector3 = MOD3.Class(null, { | |
| constructor: function Vector3(x, y, z) { | |
| var self = this; | |
| if (!(self instanceof Vector3)) return new Vector3(x, y, z); | |
| // use an internal typed-array for speed | |
| var v = new MOD3.VecArray(3); | |
| if (x && (3 === x.length)) | |
| { | |
| // array passed | |
| v[0] = x[0] || 0; | |
| v[1] = x[1] || 0; | |
| v[2] = x[2] || 0; | |
| } | |
| else | |
| { | |
| // numbers passed | |
| v[0] = x || 0; | |
| v[1] = y || 0; | |
| v[2] = z || 0; | |
| } | |
| self.xyz = v; | |
| }, | |
| name: "Vector3", | |
| xyz: null, | |
| dispose: function() { | |
| this.xyz = null; | |
| return this; | |
| }, | |
| getXYZ: function() { | |
| // copy it | |
| return new MOD3.VecArray(this.xyz); | |
| }, | |
| getXYZRef: function() { | |
| return this.xyz; | |
| }, | |
| setXYZ: function(w) { | |
| var v = this.xyz; | |
| v[0] = w[0]; | |
| v[1] = w[1]; | |
| v[2] = w[2]; | |
| return this; | |
| }, | |
| setXYZRef: function(xyz) { | |
| this.xyz = xyz; | |
| return this; | |
| }, | |
| clone: function() { | |
| return new MOD3.Vector3(this.xyz); | |
| }, | |
| equalsSelf: function(b) { | |
| var v = this.xyz, w = b.xyz; | |
| return (v[0] === w[0]) && (v[1] === w[1]) && (v[2] === w[2]); | |
| }, | |
| zeroSelf: function() { | |
| var v = this.xyz; | |
| v[0] = 0; v[1] = 0; v[2] = 0; | |
| return this; | |
| }, | |
| negate: function() { | |
| var v = this.xyz; | |
| return new MOD3.Vector3(-v[0], -v[1], -v[2]); | |
| }, | |
| negateSelf: function() { | |
| var v = this.xyz; | |
| v[0] = -v[0]; v[1] = -v[1]; v[2] = -v[2]; | |
| return this; | |
| }, | |
| add: function(b) { | |
| var v = this.xyz, w = b.xyz; | |
| return new MOD3.Vector3(v[0] + w[0], v[1] + w[1], v[2] + w[2]); | |
| }, | |
| addSelf: function(b) { | |
| var v = this.xyz, w = b.xyz; | |
| v[0] += w[0]; v[1] += w[1]; v[2] += w[2]; | |
| return this; | |
| }, | |
| subtract: function(b) { | |
| var v = this.xyz, w = b.xyz; | |
| return new MOD3.Vector3(v[0] - w[0], v[1] - w[1], v[2] - w[2]); | |
| }, | |
| subtractSelf: function(b) { | |
| var v = this.xyz, w = b.xyz; | |
| v[0] -= w[0]; v[1] -= w[1]; v[2] -= w[2]; | |
| return this; | |
| }, | |
| multiplyScalar: function(s) { | |
| var v = this.xyz; | |
| return new MOD3.Vector3(v[0]*s, v[1]*s, v[2]*s); | |
| }, | |
| multiplyScalarSelf: function(s) { | |
| var v = this.xyz; | |
| v[0] *= s; v[1] *= s; v[2] *= s; | |
| return this; | |
| }, | |
| multiply: function(b) { | |
| var v = this.xyz, w = b.xyz; | |
| return new MOD3.Vector3(v[0] * w[0], v[1] * w[1], v[2] * w[2]); | |
| }, | |
| multiplySelf: function(b) { | |
| var v = this.xyz, w = b.xyz; | |
| v[0] *= w[0]; v[1] *= w[1]; v[2] *= w[2]; | |
| return this; | |
| }, | |
| divide: function(s) { | |
| var v = this.xyz; | |
| return new MOD3.Vector3(v[0] / s, v[1] / s, v[2] / s); | |
| }, | |
| divideSelf: function(s) { | |
| var v = this.xyz; | |
| v[0] /= s; v[1] /= s; v[2] /= s; | |
| return this; | |
| }, | |
| normalize: function() { | |
| var v = this.xyz, | |
| x = v[0], y = v[1], z = v[2], | |
| m = x * x + y * y + z * z, n; | |
| if (0 < m) | |
| { | |
| n = stdMath.sqrt(m); | |
| x /= n; | |
| y /= n; | |
| z /= n; | |
| } | |
| return new MOD3.Vector3(x, y, z); | |
| }, | |
| normalizeSelf: function() { | |
| var v = this.xyz, | |
| x = v[0], y = v[1], z = v[2], | |
| m = x * x + y * y + z * z, n; | |
| if (0 < m) | |
| { | |
| n = stdMath.sqrt(m); | |
| x /= n; | |
| y /= n; | |
| z /= n; | |
| } | |
| v[0] = x; v[1] = y; v[2] = z; | |
| return this; | |
| }, | |
| getMagnitude: function() { | |
| var v = this.xyz, x = v[0], y = v[1], z = v[2]; | |
| return stdMath.sqrt(x*x + y*y + z*z); | |
| }, | |
| setMagnitude: function(m) { | |
| this.normalizeSelf(); | |
| var v = this.xyz; | |
| v[0] *= m; v[1] *= m; v[2] *= m; | |
| return this; | |
| }, | |
| dot: function(b) { | |
| var v = this.xyz, w = b.xyz; | |
| return v[0]*w[0] + v[1]*w[1] + v[2]*w[2]; | |
| }, | |
| cross: function(b) { | |
| var v = this.xyz, w = b.xyz, | |
| x1 = v[0], y1 = v[1], z1 = v[2], | |
| x2 = w[0], y2 = w[1], z2 = w[2]; | |
| return new MOD3.Vector3(y1 * z2 - z1 * y2, z1 * x2 - x1 * z2, x1 * y2 - y1 * x2); | |
| }, | |
| crossSelf: function(v) { | |
| var v = this.xyz, w = b.xyz, | |
| x1 = v[0], y1 = v[1], z1 = v[2], | |
| x2 = w[0], y2 = w[1], z2 = w[2]; | |
| v[0] = y1 * z2 - z1 * y2; | |
| v[1] = z1 * x2 - x1 * z2; | |
| v[2] = x1 * y2 - y1 * x2; | |
| return this; | |
| }, | |
| distance: function(b) { | |
| var v = this.xyz, w = b.xyz, | |
| dx = v[0] - w[0], | |
| dy = v[1] - w[1], | |
| dz = v[2] - w[2]; | |
| return stdMath.sqrt(dx*dx + dy*dy + dz*dz); | |
| }, | |
| toString: function() { | |
| var v = this.xyz; | |
| return "[" + v[0] + " , " + v[1] + " , " + v[2] + "]"; | |
| } | |
| }, { | |
| ZERO: function() { | |
| return new MOD3.Vector3(0, 0, 0); | |
| }, | |
| X: function(direct_or_complement) { | |
| return false === direct_or_complement ? new MOD3.Vector3(0, 1, 1) : new MOD3.Vector3(1, 0, 0); | |
| }, | |
| Y: function(direct_or_complement) { | |
| return false === direct_or_complement ? new MOD3.Vector3(1, 0, 1) : new MOD3.Vector3(0, 1, 0); | |
| }, | |
| Z: function(direct_or_complement) { | |
| return false === direct_or_complement ? new MOD3.Vector3(1, 1, 0) : new MOD3.Vector3(0, 0, 1); | |
| }, | |
| dot: function(v, w) { | |
| return v[0]*w[0] + v[1]*w[1] + v[2]*w[2]; | |
| }, | |
| equals: function(v, w) { | |
| return (v[0] === w[0]) && (v[1] === w[1]) && (v[2] === w[2]); | |
| }, | |
| cross: function(v, w) { | |
| var vw = new MOD3.VecArray(3); | |
| vw[0] = v[1] * w[2] - v[2] * w[1]; | |
| vw[1] = v[2] * w[0] - v[0] * w[2]; | |
| vw[2] = v[0] * w[1] - v[1] * w[0]; | |
| return vw; | |
| }, | |
| mod: function(v) { | |
| var x = v[0], y = v[1], z = v[2]; | |
| return stdMath.sqrt(x*x + y*y + z*z); | |
| }, | |
| dist: function(v, w) { | |
| var dx = v[0] - w[0], | |
| dy = v[1] - w[1], | |
| dz = v[2] - w[2]; | |
| return stdMath.sqrt(dx*dx + dy*dy + dz*dz); | |
| }, | |
| add: function(v, w) { | |
| v[0] += w[0]; | |
| v[1] += w[1]; | |
| v[2] += w[2]; | |
| return v; | |
| }, | |
| sub: function(v, w) { | |
| v[0] -= w[0]; | |
| v[1] -= w[1]; | |
| v[2] -= w[2]; | |
| return v; | |
| }, | |
| mul: function(v, w) { | |
| v[0] *= w[0]; | |
| v[1] *= w[1]; | |
| v[2] *= w[2]; | |
| return v; | |
| }, | |
| muls: function(v, m) { | |
| v[0] *= m; | |
| v[1] *= m; | |
| v[2] *= m; | |
| return v; | |
| }, | |
| norm: function(v) { | |
| var x = v[0], y = v[1], z = v[2], | |
| m = x*x + y*y + z*z, n; | |
| if (0 < m) | |
| { | |
| n = stdMath.sqrt(m); | |
| x /= n; | |
| y /= n; | |
| z /= n; | |
| } | |
| v[0] = x; v[1] = y; v[2] = z; | |
| return v; | |
| } | |
| }); | |
| // alaises | |
| MOD3.Vector3.modulo = MOD3.Vector3.mod; | |
| MOD3.Vector3.distance = MOD3.Vector3.dist; | |
| MOD3.Vector3.prototype.dotSelf = MOD3.Vector3.prototype.dot; | |
| MOD3.Vector3.prototype.distanceSelf = MOD3.Vector3.prototype.distance; | |
| /** | |
| * MOD3 3D Transform Matrix Class | |
| **/ | |
| MOD3.Matrix4 = MOD3.Class(null, { | |
| constructor: function Matrix4(n11, n12, n13, n14, | |
| n21, n22, n23, n24, | |
| n31, n32, n33, n34, | |
| n41, n42, n43, n44) | |
| { | |
| var self = this; | |
| if (!(self instanceof Matrix4)) return new Matrix4(n11, n12, n13, n14, | |
| n21, n22, n23, n24, | |
| n31, n32, n33, n34, | |
| n41, n42, n43, n44); | |
| self.m = new MOD3.VecArray([ | |
| n11 == null ? 1 : n11, | |
| n12 == null ? 0 : n12, | |
| n13 == null ? 0 : n13, | |
| n14 == null ? 0 : n14, | |
| n21 == null ? 0 : n21, | |
| n22 == null ? 1 : n22, | |
| n23 == null ? 0 : n23, | |
| n24 == null ? 0 : n24, | |
| n31 == null ? 0 : n31, | |
| n32 == null ? 0 : n32, | |
| n33 == null ? 1 : n33, | |
| n34 == null ? 0 : n34, | |
| n41 == null ? 0 : n41, | |
| n42 == null ? 0 : n42, | |
| n43 == null ? 0 : n43, | |
| n44 == null ? 1 : n44 | |
| ]); | |
| }, | |
| name: "Matrix4", | |
| m: null, | |
| dispose: function() { | |
| this.m = null; | |
| return this; | |
| }, | |
| reset: function() { | |
| var m = this.m; | |
| m[0 ] = 1; m[1 ] = 0; m[2 ] = 0; m[3 ] = 0; | |
| m[4 ] = 0; m[5 ] = 1; m[6 ] = 0; m[7 ] = 0; | |
| m[8 ] = 0; m[9 ] = 0; m[10] = 1; m[11] = 0; | |
| m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1; | |
| return this; | |
| }, | |
| translate: function(tx, ty, tz, reset) { | |
| var m = this.m; | |
| if (true === reset) this.reset(); | |
| m[3 ] = tx; | |
| m[7 ] = ty; | |
| m[11] = tz; | |
| return this; | |
| }, | |
| scale: function(sx, sy, sz, reset) { | |
| var m = this.m; | |
| if (true === reset) this.reset(); | |
| m[0 ] = sx; | |
| m[5 ] = sy; | |
| m[10] = sz; | |
| return this; | |
| }, | |
| rotate: function(rx, ry, rz, theta, reset) { | |
| var m = this.m, | |
| nCos = stdMath.cos(theta), nSin = stdMath.sin(theta), scos = 1 - nCos, | |
| sxy = rx*ry*scos, syz = ry*rz*scos, sxz = rx*rz*scos, | |
| sz = nSin*rz, sy = nSin*ry, sx = nSin*rx | |
| ; | |
| if (true === reset) this.reset(); | |
| m[0 ] = nCos + rx*rx*scos; | |
| m[1 ] = -sz + sxy; | |
| m[2 ] = sy + sxz; | |
| m[3 ] = 0; | |
| m[4 ] = sz + sxy; | |
| m[5 ] = nCos + ry*ry*scos; | |
| m[6 ] = -sx + syz; | |
| m[7 ] = 0; | |
| m[8 ] = -sy + sxz; | |
| m[9 ] = sx + syz; | |
| m[10] = nCos + rz*rz*scos; | |
| m[11] = 0; | |
| return this; | |
| }, | |
| translateFromVector: function(v, reset) { | |
| return this.translate(v.xyz[0], v.xyz[1], v.xyz[2], reset); | |
| }, | |
| scaleFromVector: function(v, reset) { | |
| return this.scale(v.xyz[0], v.xyz[1], v.xyz[2], reset); | |
| }, | |
| rotateFromVector: function(v, theta, reset) { | |
| return this.rotate(v.xyz[0], v.xyz[1], v.xyz[2], theta, reset); | |
| }, | |
| multiply: function(b) { | |
| return MOD3.Matrix4.mult(this, b); | |
| }, | |
| multiplyVector: function(v) { | |
| MOD3.Matrix4.multXYZ(this, v.xyz); | |
| return v; | |
| } | |
| }, { | |
| multXYZ: function(m4, v) { | |
| var m = m4.m, x = v[0], y = v[1], z = v[2]; | |
| v[0] = x*m[0 ] + y*m[1 ] + z*m[2 ] + m[3 ]; | |
| v[1] = x*m[4 ] + y*m[5 ] + z*m[6 ] + m[7 ]; | |
| v[2] = x*m[8 ] + y*m[9 ] + z*m[10] + m[11]; | |
| return v; | |
| }, | |
| mult: function(m1, m2) { | |
| var a = m1.m, b = m2.m, | |
| a11 = a[0 ], b11 = b[0 ], | |
| a21 = a[4 ], b21 = b[4 ], | |
| a31 = a[8 ], b31 = b[8 ], | |
| a12 = a[1 ], b12 = b[1 ], | |
| a22 = a[5 ], b22 = b[5 ], | |
| a32 = a[9 ], b32 = b[9 ], | |
| a13 = a[2 ], b13 = b[2 ], | |
| a23 = a[6 ], b23 = b[6 ], | |
| a33 = a[10], b33 = b[10], | |
| a14 = a[3 ], b14 = b[3 ], | |
| a24 = a[7 ], b24 = b[7 ], | |
| a34 = a[11], b34 = b[11]; | |
| a[0 ] = a11*b11 + a12*b21 + a13*b31; | |
| a[1 ] = a11*b12 + a12*b22 + a13*b32; | |
| a[2 ] = a11*b13 + a12*b23 + a13*b33; | |
| a[3 ] = a11*b14 + a12*b24 + a13*b34 + a14; | |
| a[4 ] = a21*b11 + a22*b21 + a23*b31; | |
| a[5 ] = a21*b12 + a22*b22 + a23*b32; | |
| a[6 ] = a21*b13 + a22*b23 + a23*b33; | |
| a[7 ] = a21*b14 + a22*b24 + a23*b34 + a24; | |
| a[8 ] = a31*b11 + a32*b21 + a33*b31; | |
| a[9 ] = a31*b12 + a32*b22 + a33*b32; | |
| a[10] = a31*b13 + a32*b23 + a33*b33; | |
| a[11] = a31*b14 + a32*b24 + a33*b34 + a34; | |
| return m1; | |
| } | |
| }); | |
| // aliases | |
| MOD3.Matrix4.prototype.translationMatrix = MOD3.Matrix4.prototype.translate; | |
| MOD3.Matrix4.prototype.scaleMatrix = MOD3.Matrix4.prototype.scale; | |
| MOD3.Matrix4.prototype.rotationMatrix = MOD3.Matrix4.prototype.rotate; | |
| MOD3.Matrix4.prototype.translationMatrixFromVector = MOD3.Matrix4.prototype.translateFromVector; | |
| MOD3.Matrix4.prototype.scaleMatrixFromVector = MOD3.Matrix4.prototype.scaleFromVector; | |
| MOD3.Matrix4.prototype.rotationMatrixFromVector = MOD3.Matrix4.prototype.rotateFromVector; | |
| // fast list utilities | |
| MOD3.List = { | |
| operate: function operate(x, F, F0, i0, i1, reverse) { | |
| var len = x.length; | |
| if (arguments.length < 5) i1 = len-1; | |
| if (0 > i1) i1 += len; | |
| if (arguments.length < 4) i0 = 0; | |
| if (i0 > i1) return F0; | |
| if (true === reverse) | |
| { | |
| var i, k, l=i1-i0+1, l1=l-1, r=l&15, q=r&1, lr=l1-r, Fv=q?F(F0,x[i1],i1):F0; | |
| for (i=l1-q; i>lr; i-=2) { k = i0+i; Fv = F(F(Fv,x[k],k),x[k-1],k-1); } | |
| for (i=lr; i>=0; i-=16) { k = i0+i; Fv = F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(Fv,x[k],k),x[k-1],k-1),x[k-2],k-2),x[k-3],k-3),x[k-4],k-4),x[k-5],k-5),x[k-6],k-6),x[k-7],k-7),x[k-8],k-8),x[k-9],k-9),x[k-10],k-10),x[k-11],k-11),x[k-12],k-12),x[k-13],k-13),x[k-14],k-14),x[k-15],k-15); } | |
| } | |
| else | |
| { | |
| var i, k, l=i1-i0+1, r=l&15, q=r&1, Fv=q?F(F0,x[i0],i0):F0; | |
| for (i=q; i<r; i+=2) { k = i0+i; Fv = F(F(Fv,x[k],k),x[k+1],k+1); } | |
| for (i=r; i<l; i+=16) { k = i0+i; Fv = F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(Fv,x[k],k),x[k+1],k+1),x[k+2],k+2),x[k+3],k+3),x[k+4],k+4),x[k+5],k+5),x[k+6],k+6),x[k+7],k+7),x[k+8],k+8),x[k+9],k+9),x[k+10],k+10),x[k+11],k+11),x[k+12],k+12),x[k+13],k+13),x[k+14],k+14),x[k+15],k+15); } | |
| } | |
| return Fv; | |
| } | |
| ,each: function each(x, F, i0, i1, reverse) { | |
| if (null == x || !x.length) return x; | |
| var len = x.length; | |
| if (arguments.length < 4) i1 = len-1; | |
| if (0 > i1) i1 += len; | |
| if (arguments.length < 3) i0 = 0; | |
| if (i0 > i1) return x; | |
| var i, k, l=i1-i0+1, l1, lr, r, q; | |
| if (true === reverse) | |
| { | |
| l1=l-1; r=l&15; q=r&1; lr=l1-r; | |
| if (q) F(x[i1]); | |
| for (i=l1-q; i>lr; i-=2) | |
| { | |
| k = i0+i; | |
| F(x[k ]); | |
| F(x[k-1]); | |
| } | |
| for (i=lr; i>=0; i-=16) | |
| { | |
| k = i0+i; | |
| F(x[k ] ); | |
| F(x[k-1] ); | |
| F(x[k-2] ); | |
| F(x[k-3] ); | |
| F(x[k-4] ); | |
| F(x[k-5] ); | |
| F(x[k-6] ); | |
| F(x[k-7] ); | |
| F(x[k-8] ); | |
| F(x[k-9] ); | |
| F(x[k-10]); | |
| F(x[k-11]); | |
| F(x[k-12]); | |
| F(x[k-13]); | |
| F(x[k-14]); | |
| F(x[k-15]); | |
| } | |
| } | |
| else | |
| { | |
| r=l&15; q=r&1; | |
| if (q) F(x[i0]); | |
| for (i=q; i<r; i+=2) | |
| { | |
| k = i0+i; | |
| F(x[k ]); | |
| F(x[k+1]); | |
| } | |
| for (i=r; i<l; i+=16) | |
| { | |
| k = i0+i; | |
| F(x[k ] ); | |
| F(x[k+1] ); | |
| F(x[k+2] ); | |
| F(x[k+3] ); | |
| F(x[k+4] ); | |
| F(x[k+5] ); | |
| F(x[k+6] ); | |
| F(x[k+7] ); | |
| F(x[k+8] ); | |
| F(x[k+9] ); | |
| F(x[k+10]); | |
| F(x[k+11]); | |
| F(x[k+12]); | |
| F(x[k+13]); | |
| F(x[k+14]); | |
| F(x[k+15]); | |
| } | |
| } | |
| return x; | |
| } | |
| }; | |
| /** | |
| * MOD3 MeshProxy Super Class | |
| **/ | |
| function dispose(o) | |
| { | |
| o.dispose(); | |
| } | |
| function reset(o) | |
| { | |
| o.reset(); | |
| } | |
| function collapse(o) | |
| { | |
| o.collapse(); | |
| } | |
| MOD3.FaceProxy = MOD3.Class(null, { | |
| constructor: function FaceProxy() { | |
| this.vertices = []; | |
| }, | |
| name: "FaceProxy", | |
| vertices: null, | |
| dispose: function() { | |
| var self = this; | |
| self.vertices = null; | |
| return self; | |
| }, | |
| addVertex: function(v) { | |
| this.vertices.push(v); | |
| }, | |
| getVertices: function() { | |
| return this.vertices; | |
| } | |
| }); | |
| MOD3.VertexProxy = MOD3.Class(null, { | |
| constructor: function VertexProxy(vertex, mesh) { | |
| var self = this; | |
| self.mesh = mesh || null; | |
| // use internal typed-arrays for speed | |
| self.original = new MOD3.VecArray([0,0,0]); | |
| self.ratio = new MOD3.VecArray([0,0,0]); | |
| // vertex can be zero | |
| if (null != vertex) self.setVertex(vertex); | |
| }, | |
| name: "VertexProxy", | |
| mesh: null, | |
| vertex: null, | |
| original: null, | |
| ratio: null, | |
| dispose: function() { | |
| var self = this; | |
| self.mesh = null; | |
| self.vertex = null; | |
| self.original = null; | |
| self.ratio = null; | |
| return self; | |
| }, | |
| setVertex: function(vt) { | |
| // override | |
| var self = this; | |
| self.vertex = vt; | |
| return self; | |
| }, | |
| getRatioVector: function() { | |
| var r = this.ratio, rv = new MOD3.VecArray(3); | |
| rv[0] = r[0]; rv[1] = r[1]; rv[2] = r[2]; | |
| return rv; | |
| }, | |
| getRatio: function(axis) { | |
| return this.ratio[MOD3.XYZi[axis]] || 0; | |
| }, | |
| setRatios: function(rx, ry, rz) { | |
| var r = this.ratio; | |
| r[0] = rx || 0; | |
| r[1] = ry || 0; | |
| r[2] = rz || 0; | |
| return this; | |
| }, | |
| getOriginalValue: function(axis) { | |
| return this.original[MOD3.XYZi[axis]] || 0; | |
| }, | |
| setOriginalPosition: function(ox, oy, oz) { | |
| var o = this.original; | |
| o[0] = ox || 0; | |
| o[1] = oy || 0; | |
| o[2] = oz || 0; | |
| return this; | |
| }, | |
| getXYZ: function() { | |
| // override | |
| return new MOD3.VecArray([0,0,0]); | |
| }, | |
| getX: function() { | |
| // override | |
| return 0; | |
| }, | |
| getY: function() { | |
| // override | |
| return 0; | |
| }, | |
| getZ: function() { | |
| // override | |
| return 0; | |
| }, | |
| getValue: function(axis) { | |
| var self = this; | |
| // override | |
| return MOD3.ModConstant.X === axis | |
| ? self.getX() | |
| : (MOD3.ModConstant.Y === axis | |
| ? self.getY() | |
| : (MOD3.ModConstant.Z === axis | |
| ? self.getZ() | |
| : 0)) | |
| ; | |
| }, | |
| setXYZ: function(xyz) { | |
| // override | |
| return this; | |
| }, | |
| setX: function(vo) { | |
| // override | |
| return this; | |
| }, | |
| setY: function(vo) { | |
| // override | |
| return this; | |
| }, | |
| setZ: function(vo) { | |
| // override | |
| return this; | |
| }, | |
| setValue: function(axis, vo) { | |
| var self = this; | |
| // override | |
| if (MOD3.ModConstant.X === axis) self.setX(vo); | |
| else if (MOD3.ModConstant.Y === axis) self.setY(vo); | |
| else if (MOD3.ModConstant.Z === axis) self.setZ(vo); | |
| return self; | |
| }, | |
| reset: function() { | |
| // override | |
| var self = this; | |
| self.setXYZ(self.original); | |
| return self; | |
| }, | |
| collapse: function() { | |
| // override | |
| var self = this, xyz = self.getXYZ(), o = self.original; | |
| o[0] = xyz[0]; o[1] = xyz[1]; o[2] = xyz[2]; | |
| return self; | |
| } | |
| }); | |
| MOD3.MeshProxy = MOD3.Class(null, { | |
| constructor: function MeshProxy(mesh) { | |
| var self = this; | |
| self.maxX = 0; | |
| self.maxY = 0; | |
| self.maxZ = 0; | |
| self.minX = 0; | |
| self.minY = 0; | |
| self.minZ = 0; | |
| self.maxAxis = 0; | |
| self.midAxis = 0; | |
| self.minAxis = 0; | |
| self.width = 0; | |
| self.height = 0; | |
| self.depth = 0; | |
| self.vertices = null; | |
| self.faces = null; | |
| self.mesh = null; | |
| if (null != mesh) self.setMesh(mesh); | |
| }, | |
| name: "MeshProxy", | |
| maxX: 0, | |
| maxY: 0, | |
| maxZ: 0, | |
| minX: 0, | |
| minY: 0, | |
| minZ: 0, | |
| maxAxis: 0, | |
| midAxis: 0, | |
| minAxis: 0, | |
| width: 0, | |
| height: 0, | |
| depth: 0, | |
| vertices : null, | |
| faces : null, | |
| mesh : null, | |
| v: null, | |
| dispose: function() { | |
| var self = this; | |
| self.maxX = null; | |
| self.maxY = null; | |
| self.maxZ = null; | |
| self.minX = null; | |
| self.minY = null; | |
| self.minZ = null; | |
| self.maxAxis = null; | |
| self.midAxis = null; | |
| self.minAxis = null; | |
| self.width = null; | |
| self.height = null; | |
| self.depth = null; | |
| self.disposeFaces(); | |
| self.disposeVertices(); | |
| self.mesh = null; | |
| self.v = null; | |
| return self; | |
| }, | |
| disposeVertices: function() { | |
| var self = this; | |
| if (self.vertices) MOD3.List.each(self.vertices, dispose); | |
| self.vertices = null; | |
| return self; | |
| }, | |
| disposeFaces: function() { | |
| var self = this; | |
| if (self.faces) MOD3.List.each(self.faces, dispose); | |
| self.faces = null; | |
| return self; | |
| }, | |
| init: function(mesh) { | |
| var self = this; | |
| self.mesh = mesh; | |
| //self.vertices = []; | |
| // not used | |
| //self.faces = []; | |
| return self; | |
| }, | |
| setMesh: function(mesh) { | |
| var self = this; | |
| self.init(mesh); | |
| self.preApply(); | |
| self.analyzeGeometry() | |
| self.postApply(); | |
| return self; | |
| }, | |
| getVertices: function() { | |
| return this.vertices; | |
| }, | |
| getFaces: function() { | |
| return this.faces; | |
| }, | |
| applyModifiers: function(modStack) { | |
| var self = this, sl, i; | |
| for (i=0,sl=modStack.length; i<sl; ++i) | |
| { | |
| modStack[i].enabled && modStack[i].apply(self); | |
| } | |
| return self; | |
| }, | |
| analyzeGeometry: function() { | |
| var self = this, | |
| vertices = self.vertices, | |
| minX = 0, minY = 0, minZ = 0, | |
| maxX = 0, maxY = 0, maxZ = 0, | |
| width = 0, height = 0, depth = 0, | |
| maxe, mine, w | |
| ; | |
| if (!vertices || !vertices.length) return self; | |
| w = vertices[0].getXYZ(); | |
| minX = w[0]; | |
| minY = w[1]; | |
| minZ = w[2]; | |
| maxX = w[0]; | |
| maxY = w[1]; | |
| maxZ = w[2]; | |
| MOD3.List.each(vertices, function(v) { | |
| var xyz = v.getXYZ(), x = xyz[0], y = xyz[1], z = xyz[2]; | |
| minX = stdMath.min(minX, x); | |
| minY = stdMath.min(minY, y); | |
| minZ = stdMath.min(minZ, z); | |
| maxX = stdMath.max(maxX, x); | |
| maxY = stdMath.max(maxY, y); | |
| maxZ = stdMath.max(maxZ, z); | |
| v.setOriginalPosition(x, y, z); | |
| }); | |
| width = maxX - minX; | |
| height = maxY - minY; | |
| depth = maxZ - minZ; | |
| self.width = width; | |
| self.height = height; | |
| self.depth = depth; | |
| self.minX = minX; | |
| self.maxX = maxX; | |
| self.minY = minY; | |
| self.maxY = maxY; | |
| self.minZ = minZ; | |
| self.maxZ = maxZ; | |
| maxe = stdMath.max(width, height, depth); | |
| mine = stdMath.min(width, height, depth); | |
| if ((maxe === width) && (mine === height)) | |
| { | |
| self.minAxis = MOD3.ModConstant.Y; | |
| self.midAxis = MOD3.ModConstant.Z; | |
| self.maxAxis = MOD3.ModConstant.X; | |
| } | |
| else if ((maxe === width) && (mine === depth)) | |
| { | |
| self.minAxis = MOD3.ModConstant.Z; | |
| self.midAxis = MOD3.ModConstant.Y; | |
| self.maxAxis = MOD3.ModConstant.X; | |
| } | |
| else if ((maxe === height) && (mine === width)) | |
| { | |
| self.minAxis = MOD3.ModConstant.X; | |
| self.midAxis = MOD3.ModConstant.Z; | |
| self.maxAxis = MOD3.ModConstant.Y; | |
| } | |
| else if ((maxe === height) && (mine === depth)) | |
| { | |
| self.minAxis = MOD3.ModConstant.Z; | |
| self.midAxis = MOD3.ModConstant.X; | |
| self.maxAxis = MOD3.ModConstant.Y; | |
| } | |
| else if ((maxe === depth) && (mine === width)) | |
| { | |
| self.minAxis = MOD3.ModConstant.X; | |
| self.midAxis = MOD3.ModConstant.Y; | |
| self.maxAxis = MOD3.ModConstant.Z; | |
| } | |
| else if ((maxe === depth) && (mine === height)) | |
| { | |
| self.minAxis = MOD3.ModConstant.Y; | |
| self.midAxis = MOD3.ModConstant.X; | |
| self.maxAxis = MOD3.ModConstant.Z; | |
| } | |
| MOD3.List.each(vertices, function(v) { | |
| var xyz = v.getXYZ(); | |
| v.setRatios(width > 0 ? (xyz[0] - minX) / width : 0, height > 0 ? (xyz[1] - minY) / height : 0, depth > 0 ? (xyz[2] - minZ) / depth : 0); | |
| }); | |
| return self; | |
| }, | |
| resetGeometry: function() { | |
| var self = this; | |
| MOD3.List.each(self.vertices, reset); | |
| return self; | |
| }, | |
| collapseGeometry: function() { | |
| var self = this; | |
| MOD3.List.each(self.vertices, collapse); | |
| self.analyzeGeometry(); | |
| return self; | |
| }, | |
| getMin: function(axis) { | |
| var self = this; | |
| return MOD3.ModConstant.X === axis | |
| ? self.minX | |
| : (MOD3.ModConstant.Y === axis | |
| ? self.minY | |
| : (MOD3.ModConstant.Z === axis | |
| ? self.minZ | |
| : -1)) | |
| ; | |
| }, | |
| getMax: function(axis) { | |
| var self = this; | |
| return MOD3.ModConstant.X === axis | |
| ? self.maxX | |
| : (MOD3.ModConstant.Y === axis | |
| ? self.maxY | |
| : (MOD3.ModConstant.Z === axis | |
| ? self.maxZ | |
| : -1)) | |
| ; | |
| }, | |
| getSize: function(axis) { | |
| var self = this; | |
| return MOD3.ModConstant.X === axis | |
| ? self.width | |
| : (MOD3.ModConstant.Y === axis | |
| ? self.height | |
| : (MOD3.ModConstant.Z === axis | |
| ? self.depth | |
| : -1)) | |
| ; | |
| }, | |
| update: function() { | |
| // do nothing | |
| return this; | |
| }, | |
| preApply: function() { | |
| // do nothing | |
| return this; | |
| }, | |
| postApply: function() { | |
| // do nothing | |
| return this; | |
| }, | |
| updateMeshPosition: function(p) { | |
| // do nothing | |
| return this; | |
| } | |
| }); | |
| MOD3.Library3d = { | |
| id : "Library3d", | |
| Mesh : MOD3.MeshProxy, | |
| Vertex : MOD3.VertexProxy | |
| }; | |
| MOD3.Factory = { | |
| getLibrary: function(json) { | |
| if (json && json.library && MOD3[json.library]) return MOD3[json.library]; | |
| // dummy, default | |
| return MOD3.Library3d; | |
| } | |
| ,getMeshProxy: function(lib3D) { | |
| if (arguments.length) return lib3D.Mesh ? new lib3D.Mesh() : null; | |
| return null; | |
| } | |
| ,getModifier: function(json) { | |
| if (json && json.modifier && MOD3[json.modifier]) return new MOD3[json.modifier](); | |
| return null; | |
| } | |
| /* | |
| ,getMesh: function(json) { | |
| if (json && json.mesh && MOD3[json.mesh] ) return new MOD3.MeshProxy().unserialize(json); | |
| // dummy, default | |
| return new MOD3.MeshProxy(); | |
| } | |
| ,getVertex: function(json) { | |
| if (json && json.vertex && MOD3[json.vertex]) return new MOD3.VertexProxy().unserialize(json); | |
| // dummy, default | |
| return new MOD3.VertexProxy(); | |
| }*/ | |
| }; | |
| /** | |
| * MOD3 Modifier & ModifierStack Classes | |
| **/ | |
| var _modCount = 0; | |
| MOD3.Modifier = MOD3.Class({ | |
| constructor: function Modifier() { | |
| var self = this; | |
| self.id = ++_modCount; | |
| self.name = 'Modifier'; | |
| self.axes = MOD3.ModConstant.NONE; | |
| self.constraint = MOD3.ModConstant.NONE; | |
| self.enabled = true; | |
| }, | |
| id: null, | |
| name: 'Modifier', | |
| axes: null, | |
| constraint: null, | |
| enabled: true, | |
| dispose: function() { | |
| var self = this; | |
| self.name = null; | |
| self.axes = null; | |
| self.constraint = null; | |
| return self; | |
| }, | |
| enable: function(enabled) { | |
| if (arguments.length) | |
| { | |
| this.enabled = !!enabled; | |
| return this; | |
| } | |
| return this.enabled; | |
| }, | |
| constraintAxes: function(axes) { | |
| this.axes = axes || MOD3.ModConstant.NONE; | |
| return this; | |
| }, | |
| setConstraint: function(c) { | |
| this.constraint = c || MOD3.ModConstant.NONE; | |
| return this; | |
| }, | |
| // override | |
| apply: function(modifiable) { | |
| return this; | |
| }, | |
| toString: function() { | |
| return '[Modifier '+this.name+']'; | |
| } | |
| }); | |
| MOD3.ModifierStack = MOD3.Class({ | |
| constructor: function ModifierStack(lib3d, mesh) { | |
| var self = this; | |
| if (!(self instanceof ModifierStack)) return new ModifierStack(lib3d, mesh); | |
| self.stack = []; | |
| self.setModifiable(MOD3.Factory.getMeshProxy(lib3d), mesh); | |
| }, | |
| name: "ModifierStack", | |
| modifiable: null, | |
| stack: null, | |
| dispose: function(withModifiers) { | |
| var self = this; | |
| if (withModifiers && self.stack) while (self.stack.length) self.stack.pop().dispose(); | |
| if (self.modifiable) self.modifiable.dispose(); | |
| self.stack = null; | |
| self.modifiable = null; | |
| return self; | |
| }, | |
| getModifiable: function() { | |
| return this.modifiable; | |
| }, | |
| setModifiable: function(modifiable, mesh) { | |
| var self = this; | |
| self.modifiable = modifiable; | |
| if (mesh) self.modifiable.setMesh(mesh); | |
| return self; | |
| }, | |
| add: function(modifier) { | |
| var self = this; | |
| if (modifier) self.stack.push(modifier); | |
| return self; | |
| }, | |
| apply: function() { | |
| var self = this, modifiable = self.modifiable, stack = self.stack; | |
| if (modifiable && stack && stack.length) | |
| modifiable | |
| .preApply() | |
| .resetGeometry() | |
| .applyModifiers(stack) | |
| .postApply() | |
| .update() | |
| ; | |
| return self; | |
| }, | |
| collapse: function() { | |
| var self = this, modifiable = self.modifiable, stack = self.stack; | |
| if (modifiable && stack && stack.length) | |
| { | |
| modifiable | |
| .preApply() | |
| .resetGeometry() | |
| .applyModifiers(stack) | |
| .collapseGeometry() | |
| .postApply() | |
| .update() | |
| ; | |
| stack.length = 0; | |
| } | |
| return self; | |
| }, | |
| clear: function() { | |
| var self = this; | |
| if (self.stack) self.stack.length = 0; | |
| return self; | |
| } | |
| }); | |
| // aliases | |
| MOD3.ModifierStack.prototype.getMeshInfo = MOD3.ModifierStack.prototype.getModifiable; | |
| MOD3.ModifierStack.prototype.addModifier = MOD3.ModifierStack.prototype.add; | |
| !function(MOD3) { | |
| ; | |
| /** | |
| * MOD3 Pivot Modifier | |
| **/ | |
| /**[DOC_MD] | |
| * ### Pivot modifier | |
| * | |
| * Allows to move the pivot point of a 3D mesh. | |
| * | |
| * @author Bartek Drozdz | |
| * | |
| [/DOC_MD]**/ | |
| MOD3.Pivot = MOD3.Class(MOD3.Modifier, { | |
| constructor: function Pivot(x, y, z) { | |
| var self = this; | |
| if (!(self instanceof Pivot)) return new Pivot(x, y, z); | |
| self.$super('constructor'); | |
| self.name = 'Pivot'; | |
| self.vector = new MOD3.Vector3(x||0, y||0, z||0); | |
| }, | |
| vector: null, | |
| dispose: function() { | |
| var self = this; | |
| self.vector.dispose(); | |
| self.vector = null; | |
| self.$super('dispose'); | |
| return self; | |
| }, | |
| setMeshCenter: function(modifiable) { | |
| var self = this; | |
| self.vector = new MOD3.Vector3( | |
| -(modifiable.minX + 0.5*modifiable.width), | |
| -(modifiable.minY + 0.5*modifiable.height), | |
| -(modifiable.minZ + 0.5*modifiable.depth) | |
| ); | |
| return self; | |
| }, | |
| apply: function(modifiable) { | |
| var self = this, pivot = self.vector, pv = pivot.xyz; | |
| MOD3.List.each(modifiable.vertices, function(v) { | |
| v.setXYZ(MOD3.Vector3.add(v.getXYZ(), pv)); | |
| }); | |
| modifiable.updateMeshPosition(pivot.negate()); | |
| return self; | |
| } | |
| }); | |
| }(MOD3);!function(MOD3) { | |
| ; | |
| /** | |
| * MOD3 Bend Modifier | |
| **/ | |
| /**[DOC_MD] | |
| * ### Bend modifier | |
| * | |
| * Bends an object along an axis. | |
| * | |
| * @author Bartek Drozdz | |
| * | |
| [/DOC_MD]**/ | |
| var stdMath = Math, PI = stdMath.PI, | |
| TWO_PI = 2*PI, HALF_PI = PI/2; | |
| MOD3.Bend = MOD3.Class(MOD3.Modifier, { | |
| constructor: function Bend(force, offset, angle) { | |
| var self = this; | |
| if (!(self instanceof Bend)) return new Bend(force, offset, angle); | |
| self.$super('constructor'); | |
| self.name = 'Bend'; | |
| self.constraint = MOD3.ModConstant.NONE; | |
| self.switchAxes = false; | |
| self.force = force || 0; | |
| self.offset = offset || 0; | |
| self.angle = angle || 0; | |
| }, | |
| force: 0, | |
| offset: 0, | |
| angle: 0, | |
| switchAxes: false, | |
| dispose: function() { | |
| var self = this; | |
| self.force = null; | |
| self.offset = null; | |
| self.angle = null; | |
| self.switchAxes = null; | |
| self.$super('dispose'); | |
| return self; | |
| }, | |
| apply: function(modifiable) { | |
| var self = this; | |
| if (0 === self.force) return self; | |
| var constraint = self.constraint, switchAxes = self.switchAxes, | |
| force = self.force, offset = stdMath.min(1, stdMath.max(0, self.offset)), a = self.angle, | |
| max = switchAxes ? modifiable.midAxis : modifiable.maxAxis, | |
| min = modifiable.minAxis, | |
| mid = switchAxes ? modifiable.maxAxis : modifiable.midAxis, | |
| width = modifiable.getSize(max), | |
| height = modifiable.getSize(mid), | |
| origin = modifiable.getMin(max), | |
| //diagAngle = stdMath.atan2(height, width), | |
| m1 = new MOD3.Matrix().rotate(a), | |
| m2 = new MOD3.Matrix().rotate(-a), | |
| distance = origin + width * offset, | |
| radius = width / PI / force, | |
| bendAngle = TWO_PI * (width / (radius * TWO_PI)) | |
| ; | |
| MOD3.List.each(modifiable.vertices, function(v) { | |
| var xyz = v.getXYZ(), | |
| vmax = xyz[MOD3.XYZi[max]], | |
| vmid = xyz[MOD3.XYZi[mid]], | |
| vmin = xyz[MOD3.XYZi[min]], | |
| np = MOD3.Matrix.transform(m1, [vmax, vmid]), | |
| p, fa, op, ow, np2 | |
| ; | |
| vmax = np[0]; vmid = np[1]; | |
| p = (vmax - origin) / width; | |
| if ( | |
| ((MOD3.ModConstant.LEFT === constraint) && (p <= offset)) || | |
| ((MOD3.ModConstant.RIGHT === constraint) && (p >= offset)) | |
| ) | |
| { | |
| /* do nothing */ | |
| } | |
| else | |
| { | |
| fa = (HALF_PI - bendAngle * offset) + (bendAngle * p); | |
| op = stdMath.sin(fa) * (radius + vmin); | |
| ow = stdMath.cos(fa) * (radius + vmin); | |
| vmin = op - radius; | |
| vmax = distance - ow; | |
| } | |
| np2 = MOD3.Matrix.transform(m2, [vmax, vmid]); | |
| vmax = np2[0]; vmid = np2[1]; | |
| xyz[MOD3.XYZi[max]] = vmax; | |
| xyz[MOD3.XYZi[mid]] = vmid; | |
| xyz[MOD3.XYZi[min]] = vmin; | |
| v.setXYZ(xyz); | |
| }); | |
| return self; | |
| } | |
| }); | |
| }(MOD3);!function(MOD3) { | |
| ; | |
| /** | |
| * MOD3 Bloat Modifier | |
| **/ | |
| /**[DOC_MD] | |
| * ### Bloat modifier | |
| * | |
| * Bloats a mesh by forcing vertices out of specified sphere | |
| * | |
| * @author makc | |
| * | |
| [/DOC_MD]**/ | |
| var stdMath = Math; | |
| MOD3.Bloat = MOD3.Class(MOD3.Modifier, { | |
| constructor: function Bloat(radius, a, center) { | |
| var self = this; | |
| if (!(self instanceof Bloat)) return new Bloat(radius, a, center); | |
| self.$super('constructor'); | |
| self.name = 'Bloat'; | |
| self.radius = radius || 0; | |
| self.a = null == a ? 0.01 : a; | |
| self.center = center || MOD3.Vector3.ZERO(); | |
| //self.u = MOD3.Vector3.ZERO(); | |
| }, | |
| radius: 0, | |
| a: 0.01, | |
| center: null, | |
| //u: null, | |
| dispose: function() { | |
| var self = this; | |
| self.center.dispose(); | |
| self.center = null; | |
| self.radius = null; | |
| self.a = null; | |
| self.$super('dispose'); | |
| return self; | |
| }, | |
| apply: function(modifiable) { | |
| var self = this, center = self.center.xyz, | |
| radius = stdMath.max(0, self.radius), a = stdMath.max(0, self.a); | |
| MOD3.List.each(modifiable.vertices, function(v) { | |
| // get a vector towards vertex | |
| // change norm to norm + r * exp (-a * norm) | |
| var uu = MOD3.Vector3.sub(v.getXYZ(), center), magn = MOD3.Vector3.mod(uu); | |
| MOD3.Vector3.muls(MOD3.Vector3.norm(uu), magn + radius * stdMath.exp(- magn * a)); | |
| // move vertex accordingly | |
| v.setXYZ(MOD3.Vector3.add(uu, center)); | |
| // ?? needed?? | |
| //self.u=uu; | |
| }); | |
| return self; | |
| } | |
| }); | |
| }(MOD3);!function(MOD3) { | |
| ; | |
| /** | |
| * MOD3 Twist Modifier | |
| **/ | |
| /**[DOC_MD] | |
| * ### Twist modifier | |
| * | |
| * Twist mesh along an axis | |
| * Adapted from the Twist modifier for PV3D | |
| * | |
| [/DOC_MD]**/ | |
| MOD3.Twist = MOD3.Class(MOD3.Modifier, { | |
| constructor: function Twist(angle, vector, center) { | |
| var self = this; | |
| if (!(self instanceof Twist)) return new Twist(angle, vector, center); | |
| self.$super('constructor'); | |
| self.name = 'Twist'; | |
| self.angle = angle || 0; | |
| self.vector = vector || MOD3.Vector3.Y(); | |
| self.center = center || MOD3.Vector3.ZERO(); | |
| }, | |
| angle: 0, | |
| vector: null, | |
| center: null, | |
| dispose: function() { | |
| var self = this; | |
| self.vector.dispose(); | |
| self.vector = null; | |
| self.angle = null; | |
| self.center.dispose(); | |
| self.center = null; | |
| self.$super('dispose'); | |
| return self; | |
| }, | |
| apply: function(modifiable) { | |
| var self = this, | |
| tvec = self.vector.normalizeSelf().xyz, angle = self.angle, center = self.center.xyz, | |
| modulo = MOD3.Vector3.mod([0.5*modifiable.maxX, 0.5*modifiable.maxY, 0.5*modifiable.maxZ]), | |
| d = -MOD3.Vector3.dot(tvec, center), | |
| m1 = new MOD3.Matrix4(), m2 = new MOD3.Matrix4() | |
| ; | |
| MOD3.List.each(modifiable.vertices, function(v) { | |
| var xyz = v.getXYZ(), | |
| a = (MOD3.Vector3.dot(xyz, tvec) + d) * angle / modulo, | |
| m = MOD3.Matrix4.mult( | |
| m2.rotate(tvec[0], tvec[1], tvec[2], a, true), | |
| m1.translate(xyz[0], xyz[1], xyz[2], true) | |
| ) | |
| ; | |
| v.setXYZ([m.m[3], m.m[7], m.m[11]]); | |
| }); | |
| return self; | |
| } | |
| }); | |
| }(MOD3);!function(MOD3) { | |
| ; | |
| /** | |
| * MOD3 Skew Modifier | |
| **/ | |
| /**[DOC_MD] | |
| * ### Skew modifier | |
| * | |
| * Skew mesh along an axis | |
| * | |
| * @author Bartek Drozdz | |
| * | |
| [/DOC_MD]**/ | |
| var stdMath = Math; | |
| MOD3.Skew = MOD3.Class(MOD3.Modifier, { | |
| constructor: function Skew(force, offset, power, falloff) { | |
| var self = this; | |
| if (!(self instanceof Skew)) return new Skew(force, offset, power, falloff); | |
| self.$super('constructor'); | |
| self.name = 'Skew'; | |
| self.constraint = MOD3.ModConstant.NONE; | |
| self.force = force != null ? force : 0; | |
| self.offset = offset != null ? offset : 0.5; | |
| self.power = power != null ? power : 1; | |
| self.falloff = falloff != null ? falloff : 1; | |
| self.inverseFalloff = false; | |
| self.oneSide = false; | |
| self.swapAxes = false; | |
| self.skewAxis = 0; | |
| }, | |
| force: 0, | |
| skewAxis: 0, | |
| offset: 0.5, | |
| power: 1, | |
| falloff: 1, | |
| inverseFalloff: false, | |
| oneSide: false, | |
| swapAxes: false, | |
| dispose: function() { | |
| var self = this; | |
| self.force = null; | |
| self.skewAxis = null; | |
| self.offset = null; | |
| self.power = null; | |
| self.falloff = null; | |
| self.inverseFalloff = null; | |
| self.oneSide = null; | |
| self.swapAxes = null; | |
| self.$super('dispose'); | |
| return self; | |
| }, | |
| apply: function(modifiable) { | |
| var self = this, | |
| constraint = self.constraint, | |
| skewAxis = self.skewAxis || modifiable.maxAxis, | |
| swapAxes = self.swapAxes, | |
| offset = stdMath.min(1, stdMath.max(0, self.offset)), | |
| oneSide = self.oneSide, | |
| inverseFalloff = !!self.inverseFalloff, | |
| falloff = stdMath.min(1, stdMath.max(0, self.falloff)), | |
| mirrorfalloff = 1-falloff, | |
| power = self.power, | |
| force = self.force, | |
| displaceAxis = MOD3.ModConstant.X === skewAxis | |
| ? (swapAxes ? MOD3.ModConstant.Z : MOD3.ModConstant.Y) | |
| : (MOD3.ModConstant.Y === skewAxis | |
| ? (swapAxes ? MOD3.ModConstant.Z : MOD3.ModConstant.X) | |
| : (MOD3.ModConstant.Z === skewAxis | |
| ? (swapAxes ? MOD3.ModConstant.Y : MOD3.ModConstant.X) | |
| : 0)) | |
| ; | |
| MOD3.List.each(modifiable.vertices, function(v) { | |
| var r, dr, f, p, vRatio; | |
| vRatio = v.getRatio(skewAxis); | |
| if ((MOD3.ModConstant.LEFT === constraint) && (vRatio <= offset)) return; | |
| if ((MOD3.ModConstant.RIGHT === constraint) && (vRatio > offset)) return; | |
| r = vRatio - offset; | |
| if (oneSide && (0 > r)) r = -r; | |
| dr = v.getRatio(displaceAxis); | |
| if (inverseFalloff) dr = 1 - dr; | |
| f = falloff + dr * mirrorfalloff; | |
| p = (0 > r ? -1 : 1) * stdMath.pow(stdMath.abs(r), power); | |
| v.setValue(displaceAxis, v.getValue(displaceAxis) + force * p * f); | |
| }); | |
| return self; | |
| }, | |
| }); | |
| }(MOD3);!function(MOD3) { | |
| ; | |
| /** | |
| * MOD3 Taper Modifier | |
| **/ | |
| /**[DOC_MD] | |
| * ### Taper modifier | |
| * | |
| * The taper modifier displaces the vertices on two axes proportionally to their position on the third axis. | |
| * | |
| * @author Bartek Drozdz | |
| * | |
| [/DOC_MD]**/ | |
| var stdMath = Math; | |
| MOD3.Taper = MOD3.Class(MOD3.Modifier, { | |
| constructor: function Taper(force, power, v1, v2) { | |
| var self = this; | |
| if (!(self instanceof Taper)) return new Taper(force, power, v1, v2); | |
| self.$super('constructor'); | |
| self.name = 'Taper'; | |
| /*self.start = 0; | |
| self.end = 1;*/ | |
| self.force = force != null ? force : 0; | |
| self.power = power != null ? power : 1; | |
| self.vector = v1 || MOD3.Vector3.Y(false); | |
| self.vector2 = v2 || MOD3.Vector3.Y(); | |
| }, | |
| force: 0, | |
| power: 1, | |
| /*start: 0, | |
| end: 1,*/ | |
| vector: null, | |
| vector2: null, | |
| /*setFalloff : function(start, end) { | |
| this.start = (start!==undef) ? start : 0; | |
| this.end = (end!==undef) ? end : 1; | |
| return this; | |
| },*/ | |
| dispose: function() { | |
| var self = this; | |
| self.vector.dispose(); | |
| self.vector2.dispose(); | |
| self.vector = null; | |
| self.vector2 = null; | |
| self.force = null; | |
| self.power = null; | |
| self.$super('dispose'); | |
| return self; | |
| }, | |
| apply: function(modifiable) { | |
| var self = this, | |
| vec = self.vector.xyz, vec2 = self.vector2.xyz, | |
| force = self.force, power = self.power, m = new MOD3.Matrix4(); | |
| MOD3.List.each(modifiable.vertices, 1 !== power | |
| ? function(v) { | |
| var ar = MOD3.Vector3.mod(MOD3.Vector3.mul(v.getRatioVector(), vec2)), sc = force * stdMath.pow(ar, power); | |
| v.setXYZ(MOD3.Matrix4.multXYZ(m.scale(1 + sc * vec[0], 1 + sc * vec[1], 1 + sc * vec[2]), v.getXYZ())); | |
| } | |
| : function(v) { | |
| var ar = MOD3.Vector3.mod(MOD3.Vector3.mul(v.getRatioVector(), vec2)), sc = force * ar; | |
| v.setXYZ(MOD3.Matrix4.multXYZ(m.scale(1 + sc * vec[0], 1 + sc * vec[1], 1 + sc * vec[2]), v.getXYZ())); | |
| } | |
| ); | |
| return self; | |
| } | |
| }); | |
| }(MOD3);!function(MOD3) { | |
| ; | |
| /** | |
| * MOD3 Wheel Modifier | |
| **/ | |
| /**[DOC_MD] | |
| * ### Wheel modifier | |
| * | |
| * Use it with vehicle models for wheels. | |
| * | |
| * The usual problem with a 3d wheel in a vahicle is that it is | |
| * supposed to turn (steer) and roll in the same time. | |
| * So, this code: | |
| * | |
| * ```javascript | |
| * wheel.rotationY = 10; // Steer 10deg to the left | |
| * wheel.rotationZ += 5; // Roll with a speed of 5 | |
| * ``` | |
| * This will make the wheel roll incorectly. | |
| * | |
| * A usual way to solve this problem is to put the wheel in another DisplayObject3D/Mesh, | |
| * turn the parent and roll the child, like that: | |
| * ```javascript | |
| * steer.rotationY = 10; // Steer 10deg to the left | |
| * steer.wheel.rotationZ += 5; // Roll with a speed of 5 | |
| * ``` | |
| * That will make the wheel behave correctly. But it can be uncomfortanble to apply, especially | |
| * to imported complex Collada models. | |
| * | |
| * The Wheel modifier elegantly solves this problem by doind the proper math in order to steer and roll | |
| * a single mesh at the same time. The only thing you need to do is to specify a steer vector and | |
| * roll vector - usually it will be 2 of the cardinal axes. The default value is: | |
| * | |
| * * steer - along the Y axis / new Vector3(0, 1, 0) | |
| * * roll - along the Z axis / new Vector3(0, 0, 1) | |
| * | |
| * | |
| * It should work with most car models imported from 3D editors as this is the natural position of a wheel. | |
| * | |
| * *Please note, that Papervision primitive cylinder, which may also be used as wheel, will require different axes | |
| * (Y for roll and Z or X for steer).* | |
| * | |
| * @author Bartek Drozdz | |
| * | |
| [/DOC_MD]**/ | |
| MOD3.Wheel = MOD3.Class(MOD3.Modifier, { | |
| constructor: function Wheel(speed, turn, roll, steerVector, rollVector) { | |
| var self = this; | |
| if (!(self instanceof Wheel)) return new Wheel(speed, turn, roll, steerVector, rollVector); | |
| self.$super('constructor'); | |
| self.name = 'Wheel'; | |
| self.speed = speed || 0; | |
| self.turn = turn || 0; | |
| self.roll = roll || 0; | |
| self.steerVector = steerVector || MOD3.Vector3.Y(); | |
| self.rollVector = rollVector || MOD3.Vector3.Z(); | |
| }, | |
| speed: 0, | |
| turn: 0, | |
| roll: 0, | |
| steerVector: null, | |
| rollVector: null, | |
| dispose: function() { | |
| var self = this; | |
| self.speed = null; | |
| self.turn = null; | |
| self.roll = null; | |
| self.steerVector.dispose(); | |
| self.rollVector.dispose(); | |
| self.steerVector = null; | |
| self.rollVector = null; | |
| self.$super('dispose'); | |
| return self; | |
| }, | |
| apply: function(modifiable) { | |
| var self = this, | |
| steerVector = self.steerVector.normalizeSelf(), | |
| rollVector = self.rollVector.normalizeSelf(), | |
| turn = self.turn, roll = self.roll, | |
| //radius = 0.5*modifiable.width, | |
| //step = radius * self.speed / PI, | |
| //perimeter = radius * TWO_PI, | |
| ms = null, mt = null | |
| ; | |
| self.roll += self.speed; | |
| if (turn) | |
| { | |
| mt = new MOD3.Matrix4().rotateFromVector(steerVector, turn); | |
| ms = new MOD3.Matrix4().rotateFromVector(mt.multiplyVector(rollVector.clone()), roll); | |
| } | |
| else | |
| { | |
| ms = new MOD3.Matrix4().rotateFromVector(rollVector, roll); | |
| } | |
| MOD3.List.each(modifiable.vertices, mt | |
| ? function(v) { | |
| v.setXYZ(MOD3.Matrix4.multXYZ(ms, MOD3.Matrix4.multXYZ(mt, v.getXYZ()))); | |
| } | |
| : function(v) { | |
| v.setXYZ(MOD3.Matrix4.multXYZ(ms, v.getXYZ())); | |
| } | |
| ); | |
| return self; | |
| } | |
| }); | |
| }(MOD3);!function(MOD3) { | |
| ; | |
| /** | |
| * MOD3 Break Modifier | |
| **/ | |
| /**[DOC_MD] | |
| * ### Break modifier | |
| * | |
| * Allow to break a mesh | |
| * | |
| * @author Bartek Drozdz | |
| * | |
| [/DOC_MD]**/ | |
| var stdMath = Math; | |
| MOD3.Break = MOD3.Class(MOD3.Modifier, { | |
| constructor: function Break(offset, angle, vector) { | |
| var self = this; | |
| if (!(self instanceof Break)) return new Break(offset, angle, vector); | |
| self.$super('constructor'); | |
| self.name = 'Break'; | |
| self.offset = offset || 0; | |
| self.angle = angle || 0; | |
| self.vector = vector || MOD3.Vector3.Y(); | |
| self.range = new MOD3.Range(0, 1); | |
| }, | |
| offset: 0, | |
| angle: 0, | |
| vector: null, | |
| range: null, | |
| dispose: function() { | |
| var self = this; | |
| self.vector.dispose(); | |
| self.range.dispose(); | |
| self.vector = null; | |
| self.range = null; | |
| self.offset = null; | |
| self.angle = null; | |
| self.$super('dispose'); | |
| return self; | |
| }, | |
| apply: function(modifiable) { | |
| var self = this, | |
| offset = stdMath.min(1, stdMath.max(0, self.offset)), range = self.range, angle = self.angle, | |
| bv = self.vector.normalizeSelf().xyz, pv, rm; | |
| pv = modifiable.minZ + modifiable.depth*offset; | |
| rm = new MOD3.Matrix4().rotate(bv[0], bv[1], bv[2], angle); | |
| MOD3.List.each(modifiable.vertices, function(v) { | |
| var c = v.getXYZ(); | |
| c[2] -= pv; | |
| if ((0 <= c[2]) && range.isIn(v.ratio[1])) MOD3.Matrix4.multXYZ(rm, c); | |
| c[2] += pv; | |
| v.setXYZ(c); | |
| }); | |
| return self; | |
| } | |
| }); | |
| }(MOD3);!function(MOD3) { | |
| ; | |
| /** | |
| * MOD3 Noise Modifier | |
| **/ | |
| /**[DOC_MD] | |
| * ### Noise modifier | |
| * | |
| * Randomly displaces each vertex in all 3 axes | |
| * | |
| * | |
| [/DOC_MD]**/ | |
| var stdMath = Math; | |
| MOD3.Noise = MOD3.Class(MOD3.Modifier, { | |
| constructor: function Noise(force) { | |
| var self = this; | |
| if (!(self instanceof Noise)) return new Noise(force); | |
| self.$super('constructor'); | |
| self.name = 'Noise'; | |
| self.force = force || 0; | |
| self.start = 0; | |
| self.end = 1; | |
| self.axes = MOD3.ModConstant.X | MOD3.ModConstant.Y | MOD3.ModConstant.Z; | |
| }, | |
| force: 0, | |
| start: 0, | |
| end: 1, | |
| dispose: function() { | |
| var self = this; | |
| self.force = null; | |
| self.start = null; | |
| self.end = null; | |
| self.$super('dispose'); | |
| return self; | |
| }, | |
| setFalloff: function(start, end) { | |
| var self = this; | |
| self.start = start != null ? start : 0; | |
| self.end = end != null ? end : 1; | |
| return self; | |
| }, | |
| apply: function(modifiable) { | |
| var self = this, | |
| axes = self.axes, start = self.start, end = self.end, | |
| force = self.force, halfforce = 0.5*force, | |
| maxAxis = modifiable.maxAxis; | |
| if ((0 == axes) || (0 == force)) return self; | |
| MOD3.List.each(modifiable.vertices, function(v) { | |
| var r = stdMath.random() * force - halfforce, | |
| p = v.getRatio(maxAxis), rp, xyz; | |
| if (start < end) | |
| { | |
| if (p < start) p = 0; | |
| else if (p > end) p = 1; | |
| } | |
| else if (start > end) | |
| { | |
| p = 1 - p; | |
| if (p > start) p = 0; | |
| else if (p < end) p = 1; | |
| } | |
| else | |
| { | |
| p = 1; | |
| } | |
| rp = r * p; | |
| xyz = v.getXYZ(); | |
| v.setXYZ([ | |
| xyz[0] + (axes & MOD3.ModConstant.X ? rp : 0), | |
| xyz[1] + (axes & MOD3.ModConstant.Y ? rp : 0), | |
| xyz[2] + (axes & MOD3.ModConstant.Z ? rp : 0) | |
| ]); | |
| }); | |
| return self; | |
| } | |
| }); | |
| }(MOD3);!function(MOD3) { | |
| ; | |
| /** | |
| * MOD3 DisplaceMap (BitmapDisplacement) Modifier | |
| **/ | |
| /**[DOC_MD] | |
| * ### DisplaceMap (BitmapDisplacement) Modifier | |
| * | |
| * Displaces vertices based on RGB values of bitmapData pixels. | |
| * | |
| * BitmapDisplacement is inspired by both the AS3 built-in DisplacementMapFilter. It allows | |
| * to use color values for each channels of a bitmap to modify the position of vertices in a mesh. | |
| * | |
| * The displacement takes place along the cardinal axes, and each axis is mapped to a | |
| * channel in the bitmap: X for Red, Y for Green and Z for Blue. | |
| * | |
| * @author Bartek Drozdz | |
| * | |
| [/DOC_MD]**/ | |
| MOD3.DisplaceMap = MOD3.Class(MOD3.Modifier, { | |
| constructor: function DisplaceMap(bmp, force, offset) { | |
| var self = this; | |
| if (!(self instanceof DisplaceMap)) return new DisplaceMap(bmp, force, offset); | |
| self.$super('constructor'); | |
| self.name = 'DisplaceMap'; | |
| if (+bmp === bmp) // number | |
| { | |
| self.force = bmp || 1; | |
| self.offset = null == force ? 127 : force;// 0x7F; | |
| } | |
| else | |
| { | |
| self.setBitmap(bmp); | |
| self.force = force || 1; | |
| self.offset = null == offset ? 127 : offset;// 0x7F; | |
| } | |
| self.axes = MOD3.ModConstant.X | MOD3.ModConstant.Y | MOD3.ModConstant.Z; | |
| }, | |
| width: null, | |
| height: null, | |
| bmpData: null, | |
| force: 1, | |
| offset: 127, | |
| dispose: function() { | |
| var self = this; | |
| self.bmpData = null; | |
| self.width = null; | |
| self.height = null; | |
| self.force = null; | |
| self.offset = null; | |
| self.$super('dispose'); | |
| return self; | |
| }, | |
| setBitmap: function(bmpData) { | |
| var self = this; | |
| self.bmpData = bmpData ? bmpData.data : null; | |
| self.width = bmpData ? bmpData.width : 0; | |
| self.height = bmpData ? bmpData.height : 0; | |
| return self; | |
| }, | |
| apply: function(modifiable) { | |
| var self = this, | |
| axes = self.axes, | |
| w = self.width, h = self.height, bmp = self.bmpData, | |
| force = self.force, offset = self.offset; | |
| if (!axes || !bmp) return self; | |
| MOD3.List.each(modifiable.vertices, function(v) { | |
| var uv, uu, vv, xyz = v.getXYZ(); | |
| uu = ~~((w - 1) * v.ratio[0]/* X */); | |
| vv = ~~((h - 1) * v.ratio[2]/* Z */); | |
| uv = (vv * w + uu) << 2; | |
| v.setXYZ([ | |
| xyz[0] + (axes & MOD3.ModConstant.X ? ((bmp[uv] & 0xff) - offset) * force : 0), | |
| xyz[1] + (axes & MOD3.ModConstant.Y ? ((bmp[uv+1] & 0xff) - offset) * force : 0), | |
| xyz[2] + (axes & MOD3.ModConstant.Z ? ((bmp[uv+2] & 0xff) - offset) * force : 0) | |
| ]); | |
| }); | |
| return self; | |
| } | |
| }); | |
| }(MOD3);!function(MOD3) { | |
| ; | |
| /** | |
| * MOD3 Perlin/Simplex Noise Modifier | |
| **/ | |
| /**[DOC_MD] | |
| * ### Perlin modifier | |
| * | |
| * Displaces vertices based on a perlin/simplex noise source. | |
| * | |
| * Accepts a perlin/simplex noise data (with width and height information) and displaces vertices | |
| * based on the value of each point of the noise map. | |
| * | |
| * @author Bartek Drozdz | |
| * | |
| * @uses: https://github.com/josephg/noisejs for JavaScript | |
| * | |
| [/DOC_MD]**/ | |
| function cyclic_shift(a, w, h, dX, dY) | |
| { | |
| var size = w*h, b = new MOD3.VecArray(size), i, j, i2, j2, index; | |
| if (dX < 0) dX += w; | |
| if (dY < 0) dY += h; | |
| dX = ~~dX; dY = ~~dY; | |
| for (i=0,j=0,index=0; index<size; ++index,++i) | |
| { | |
| if (i >= w) {i = 0; ++j;} | |
| i2 = (i + dX) % w; j2 = (j + dY) % h; | |
| b[index] = a[i2 + j2 * w]; | |
| } | |
| return b; | |
| } | |
| /*function generate2d(perlinNoise2d, w, h) | |
| { | |
| var size = w*h, a = new MOD3.VecArray(size), i, j, index; | |
| for (i=0,j=0,index=0; index<size; ++index,++i) | |
| { | |
| if (i >= w) {i = 0; ++j;} | |
| a[index] = perlinNoise2d(i/w, j/h); | |
| } | |
| return a; | |
| }*/ | |
| MOD3.Perlin = MOD3.Class(MOD3.Modifier, { | |
| constructor: function Perlin(force, noise, autoRun) { | |
| var self = this; | |
| if (!(self instanceof Perlin)) return new Perlin(force, noise, autoRun); | |
| self.$super('constructor'); | |
| self.name = 'Perlin'; | |
| self.force = null != force ? force : 1; | |
| self.perlin = noise; | |
| self.autoRun = null != autoRun ? !!autoRun : true; | |
| self.axes = MOD3.ModConstant.X | MOD3.ModConstant.Y | MOD3.ModConstant.Z; | |
| }, | |
| speedX: 1, | |
| speedY: 1, | |
| perlin: null, | |
| force: 1, | |
| offset: 0, | |
| autoRun: true, | |
| dispose: function() { | |
| var self = this; | |
| self.perlin = null; | |
| self.speedX = null; | |
| self.speedY = null; | |
| self.force = null; | |
| self.offset = null; | |
| self.autoRun = null; | |
| self.$super('dispose'); | |
| return self; | |
| }, | |
| setSpeed: function(dX, dY) { | |
| var self = this; | |
| self.speedX = dX; | |
| self.speedY = dY; | |
| return self; | |
| }, | |
| apply: function(modifiable) { | |
| var self = this, | |
| axes = self.axes, force = self.force, | |
| offset = self.offset, pn = self.perlin, | |
| w, h; | |
| if (!axes || !pn) return self; | |
| w = pn.width; h = pn.height; | |
| if (self.autoRun) | |
| { | |
| pn = self.perlin = cyclic_shift(pn, w, h, self.speedX, self.speedY); | |
| pn.width = w; pn.height = h; | |
| } | |
| MOD3.List.each(modifiable.vertices, function(v) { | |
| var xyz = v.getXYZ(), | |
| uu = ~~((w - 1) * v.ratio[0]/* u */), | |
| vv = ~~((h - 1) * v.ratio[2]/* v */), | |
| uv = uu + vv * w; | |
| v.setXYZ([ | |
| xyz[0] + (axes & MOD3.ModConstant.X ? (pn[uv] - offset) * force : 0), | |
| xyz[1] + (axes & MOD3.ModConstant.Y ? (pn[uv/*+1*/] - offset) * force : 0), | |
| xyz[2] + (axes & MOD3.ModConstant.Z ? (pn[uv/*+2*/] - offset) * force : 0) | |
| ]); | |
| }); | |
| return self; | |
| } | |
| }); | |
| }(MOD3);// export it | |
| return MOD3; | |
| }); | |