diff --git a/core/Dispatch.js b/core/Dispatch.js index 2352f82d..c6bc8b5f 100644 --- a/core/Dispatch.js +++ b/core/Dispatch.js @@ -158,13 +158,26 @@ Dispatch.prototype.dismount = function dismount (path) { if (node.isMounted()) { if (node.onDismount) node.onDismount(path); - for (i = 0, len = children.length ; i < len ; i++) - if (children[i] && children[i].dismount) children[i].dismount(); - else if (children[i]) this.dismount(path + '/' + i); + // NOTE! Traverse the list backwards as the child will be removed from the list and the list is shrunk in the back per dismount. This avoids a bug where only half the elements would get removed! + for (i = children.length - 1 ; i >= 0 ; i--) + { + if (children[i] && children[i].dismount) + { + children[i].dismount(); + } + else if (children[i]) + { + this.dismount(path + '/' + i); + } + } for (i = 0, len = components.length ; i < len ; i++) - if (components[i] && components[i].onDismount) - components[i].onDismount(); + { + if (components[i] && components[i].onDismount) + { + components[i].onDismount(); + } + } node._setMounted(false); node._setParent(null); diff --git a/core/FamousEngine.js b/core/FamousEngine.js index e75cfa88..f9f90782 100644 --- a/core/FamousEngine.js +++ b/core/FamousEngine.js @@ -159,7 +159,9 @@ FamousEngine.prototype._update = function _update () { SizeSystem.update(); TransformSystem.update(); + if (stats) stats.ProfileStart("osUp") OpacitySystem.update(); + if (stats) stats.ProfileEnd("osUp") while (nextQueue.length) queue.unshift(nextQueue.pop()); diff --git a/core/Opacity.js b/core/Opacity.js index 83fb1bcf..a333d7e4 100644 --- a/core/Opacity.js +++ b/core/Opacity.js @@ -31,6 +31,8 @@ function Opacity (parent) { this.parent = parent ? parent : null; this.breakPoint = false; this.calculatingWorldOpacity = false; + this.refresh = false; + this.childs = []; } Opacity.WORLD_CHANGED = 1; @@ -41,8 +43,26 @@ Opacity.prototype.reset = function reset () { this.breakPoint = false; }; -Opacity.prototype.setParent = function setParent (parent) { - this.parent = parent; +Opacity.prototype.setParent = function setParent(parent) +{ + if (this.parent) + { + // Remove as child. + var index = this.parent.childs.indexOf(this, 0); + if (index != undefined) + { + this.parent.childs.splice(index, 1); + } + } + + this.parent = parent; + + if (parent) + { + parent.childs.push(this); + this._refresh(); + } + }; Opacity.prototype.getParent = function getParent () { @@ -52,6 +72,7 @@ Opacity.prototype.getParent = function getParent () { Opacity.prototype.setBreakPoint = function setBreakPoint () { this.breakPoint = true; this.calculatingWorldOpacity = true; + this._refresh(); }; /** @@ -89,8 +110,32 @@ Opacity.prototype.getOpacity = function getOpacity () { return this.opacity; }; +Opacity.prototype._refresh = function _refresh(opacity) +{ + if (!this.refresh) + { + this.refresh = true; + + // Tell all it's children. + for (var i = 0, len = this.childs.length ; i < len ; i++) + { + if (!this.childs[i].refresh) + { + this.childs[i]._refresh(); + } + } + } +} + Opacity.prototype.setOpacity = function setOpacity (opacity) { - this.opacity = opacity; + var changed = this.opacity !== opacity; + this.opacity = opacity; + + if (changed) + { + this._refresh(); + } + }; Opacity.prototype.calculateWorldOpacity = function calculateWorldOpacity () { diff --git a/core/OpacitySystem.js b/core/OpacitySystem.js index 219fed04..5e062e1c 100644 --- a/core/OpacitySystem.js +++ b/core/OpacitySystem.js @@ -71,7 +71,11 @@ OpacitySystem.prototype.registerOpacityAtPath = function registerOpacityAtPath ( * * @param {String} path at which to register the opacity */ -OpacitySystem.prototype.deregisterOpacityAtPath = function deregisterOpacityAtPath (path) { +OpacitySystem.prototype.deregisterOpacityAtPath = function deregisterOpacityAtPath(path) +{ + var op = this.pathStore.get(path); + op.setParent(null); + this.pathStore.remove(path); }; @@ -140,17 +144,25 @@ OpacitySystem.prototype.update = function update () { var node; var components; - for (var i = 0, len = opacities.length ; i < len ; i++) { - node = Dispatch.getNode(paths[i]); - if (!node) continue; - components = node.getComponents(); - opacity = opacities[i]; - - if ((changed = opacity.calculate())) { - opacityChanged(node, components, opacity); - if (changed & Opacity.LOCAL_CHANGED) localOpacityChanged(node, components, opacity.getLocalOpacity()); - if (changed & Opacity.WORLD_CHANGED) worldOpacityChanged(node, components, opacity.getWorldOpacity()); - } + for (var i = 0, len = opacities.length ; i < len ; i++) + { + opacity = opacities[i]; + if (opacity.refresh) + { + opacity.refresh = false; + + node = Dispatch.getNode(paths[i]); + if (node) + { + if ((changed = opacity.calculate())) + { + components = node.getComponents(); + opacityChanged(node, components, opacity); + if (changed & Opacity.LOCAL_CHANGED) localOpacityChanged(node, components, opacity.getLocalOpacity()); + if (changed & Opacity.WORLD_CHANGED) worldOpacityChanged(node, components, opacity.getWorldOpacity()); + } + } + } } }; diff --git a/core/Size.js b/core/Size.js index 9a6071af..731f67ad 100644 --- a/core/Size.js +++ b/core/Size.js @@ -54,6 +54,8 @@ function Size (parent) { this.renderSizeChanged = false; this.parent = parent != null ? parent : null; + + this.refresh = false; } // an enumeration of the different types of size modes @@ -170,8 +172,9 @@ Size.prototype.setSizeMode = function setSizeMode (x, y, z) { if (x != null) x = resolveSizeMode(x); if (y != null) y = resolveSizeMode(y); if (z != null) z = resolveSizeMode(z); - this.sizeModeChanged = setVec(this.sizeMode, x, y, z); - return this; + var ch = setVec(this.sizeMode, x, y, z); + this.sizeModeChanged = ch; + this.refresh |= ch; }; /** @@ -197,8 +200,10 @@ Size.prototype.getSizeMode = function getSizeMode () { * @return {Size} this */ Size.prototype.setAbsolute = function setAbsolute (x, y, z) { - this.absoluteSizeChanged = setVec(this.absoluteSize, x, y, z); - return this; + var ch = setVec(this.absoluteSize, x, y, z); + this.absoluteSizeChanged = ch; + this.refresh |= ch; + return this; }; /** @@ -224,8 +229,10 @@ Size.prototype.getAbsolute = function getAbsolute () { * @return {Size} this */ Size.prototype.setProportional = function setProportional (x, y, z) { - this.proportionalSizeChanged = setVec(this.proportionalSize, x, y, z); - return this; + var ch = setVec(this.proportionalSize, x, y, z); + this.proportionalSizeChanged = ch; + this.refresh |= ch; + return this; }; /** @@ -251,7 +258,9 @@ Size.prototype.getProportional = function getProportional () { * @return {Size} this */ Size.prototype.setDifferential = function setDifferential (x, y, z) { - this.differentialSizeChanged = setVec(this.differentialSize, x, y, z); + var ch = setVec(this.differentialSize, x, y, z); + this.differentialSizeChanged = ch; + this.refresh |= ch; return this; }; @@ -324,7 +333,9 @@ Size.prototype.fromComponents = function fromComponents (components) { } changed = changed || prev !== target[i]; } - this.sizeChanged = changed; + var ch = changed; + this.sizeChanged = ch; + this.refresh |= ch; return changed; }; diff --git a/core/SizeSystem.js b/core/SizeSystem.js index d8f2fb88..aa94f598 100644 --- a/core/SizeSystem.js +++ b/core/SizeSystem.js @@ -99,7 +99,10 @@ SizeSystem.prototype.get = function get (path) { * * @return {undefined} undefined */ -SizeSystem.prototype.update = function update () { +SizeSystem.prototype.update = function update() +{ + if (stats) stats.ProfileStart("ssUp") + var sizes = this.pathStore.getItems(); var paths = this.pathStore.getPaths(); var node; @@ -108,18 +111,28 @@ SizeSystem.prototype.update = function update () { var len; var components; - for (i = 0, len = sizes.length ; i < len ; i++) { - node = Dispatch.getNode(paths[i]); - components = node.getComponents(); - if (!node) continue; - size = sizes[i]; - if (size.sizeModeChanged) sizeModeChanged(node, components, size); - if (size.absoluteSizeChanged) absoluteSizeChanged(node, components, size); - if (size.proportionalSizeChanged) proportionalSizeChanged(node, components, size); - if (size.differentialSizeChanged) differentialSizeChanged(node, components, size); - if (size.renderSizeChanged) renderSizeChanged(node, components, size); - if (size.fromComponents(components)) sizeChanged(node, components, size); + for (i = 0, len = sizes.length ; i < len ; i++) + { + size = sizes[i]; + if (size.refresh) + { + size.refresh = false; + + node = Dispatch.getNode(paths[i]); + if (node) + { + components = node.getComponents(); + if (size.sizeModeChanged) sizeModeChanged(node, components, size); + if (size.absoluteSizeChanged) absoluteSizeChanged(node, components, size); + if (size.proportionalSizeChanged) proportionalSizeChanged(node, components, size); + if (size.differentialSizeChanged) differentialSizeChanged(node, components, size); + if (size.renderSizeChanged) renderSizeChanged(node, components, size); + if (size.fromComponents(components)) sizeChanged(node, components, size); + } + } } + + if (stats) stats.ProfileEnd("ssUp") }; // private methods diff --git a/core/Transform.js b/core/Transform.js index 53146fc0..abda5cb3 100644 --- a/core/Transform.js +++ b/core/Transform.js @@ -35,30 +35,34 @@ var ONES = [1, 1, 1]; * * @param {Transform} parent the parent Transform */ -function Transform (parent) { - this.local = new Float32Array(Transform.IDENT); - this.global = new Float32Array(Transform.IDENT); - this.offsets = { - align: new Float32Array(3), - alignChanged: false, - mountPoint: new Float32Array(3), - mountPointChanged: false, - origin: new Float32Array(3), - originChanged: false - }; - this.vectors = { - position: new Float32Array(3), - positionChanged: false, - rotation: new Float32Array(QUAT), - rotationChanged: false, - scale: new Float32Array(ONES), - scaleChanged: false - }; - this._lastEulerVals = [0, 0, 0]; - this._lastEuler = false; - this.parent = parent ? parent : null; - this.breakPoint = false; - this.calculatingWorldMatrix = false; +function Transform(parent) +{ + this.local = new Float32Array(Transform.IDENT); + this.global = new Float32Array(Transform.IDENT); + this.offsets = { + align: new Float32Array(3), + alignChanged: false, + mountPoint: new Float32Array(3), + mountPointChanged: false, + origin: new Float32Array(3), + originChanged: false + }; + this.vectors = { + position: new Float32Array(3), + positionChanged: false, + rotation: new Float32Array(QUAT), + rotationChanged: false, + scale: new Float32Array(ONES), + scaleChanged: false + }; + this._lastEulerVals = [0, 0, 0]; + this._lastEuler = false; + this.parent = parent ? parent : null; + this.breakPoint = false; + this.calculatingWorldMatrix = false; + + this.refresh = false; // The idea is that this changes to true if anything in the component needs to update. This allows us to early out in the update loop instead of trashng cache to check each sub objects changed state. + this.childs = []; } Transform.IDENT = [ 1, 0, 0, 0, @@ -92,10 +96,45 @@ Transform.prototype.reset = function reset () { * * @return {undefined} undefined */ -Transform.prototype.setParent = function setParent (parent) { - this.parent = parent; +Transform.prototype.setParent = function setParent(parent) +{ + if (this.parent) + { + // Remove as child. + var index = this.parent.childs.indexOf(this, 0); + if (index != undefined) + { + this.parent.childs.splice(index, 1); + } + } + + this.parent = parent; + + if (parent) + { + parent.childs.push(this); + this._refresh(); + } }; +Transform.prototype._refresh = function _refresh() +{ + // Refresh all if needed. + if (!this.refresh) + { + this.refresh = true; + + // Tell all it's children. + for (var i = 0, len = this.childs.length ; i < len ; i++) + { + if (!this.childs[i].refresh) + { + this.childs[i]._refresh(); + } + } + } +} + /** * returns the parent of this transform * @@ -118,7 +157,7 @@ Transform.prototype.getParent = function getParent () { */ Transform.prototype.setBreakPoint = function setBreakPoint () { this.breakPoint = true; - this.calculatingWorldMatrix = true; +// this.calculatingWorldMatrix = true; // NOTE: COMMENTED OUT AS IT HAD NO EFFECT IN MY USAGE OF THE ENGINE. THIS AVOIDS US RECALCULATING ALL WORLD MATRIX EVERY FRAME! }; /** @@ -253,7 +292,12 @@ Transform.prototype.getPosition = function getPosition () { * @return {undefined} undefined */ Transform.prototype.setPosition = function setPosition (x, y, z) { - this.vectors.positionChanged = setVec(this.vectors.position, x, y, z); + var ch = setVec(this.vectors.position, x, y, z); + this.vectors.positionChanged = ch; + if (ch) + { + this._refresh(); + } }; /** @@ -344,7 +388,12 @@ Transform.prototype.setRotation = function setRotation (x, y, z, w) { this._lastEulerVals[2] = z; } - this.vectors.rotationChanged = setVec(quat, qx, qy, qz, qw); + var ch = setVec(quat, qx, qy, qz, qw); + this.vectors.rotationChanged = ch; + if (ch) + { + this._refresh(); + } }; /** @@ -370,7 +419,12 @@ Transform.prototype.getScale = function getScale () { * @return {undefined} undefined */ Transform.prototype.setScale = function setScale (x, y, z) { - this.vectors.scaleChanged = setVec(this.vectors.scale, x, y, z); + var ch = setVec(this.vectors.scale, x, y, z); + this.vectors.scaleChanged = ch; + if (ch) + { + this._refresh(); + } }; /** @@ -396,7 +450,12 @@ Transform.prototype.getAlign = function getAlign () { * @return {undefined} undefined */ Transform.prototype.setAlign = function setAlign (x, y, z) { - this.offsets.alignChanged = setVec(this.offsets.align, x, y, z != null ? z - 0.5 : z); + var ch = setVec(this.offsets.align, x, y, z != null ? z - 0.5 : z); + this.offsets.alignChanged = ch; + if (ch) + { + this._refresh(); + } }; /** @@ -422,7 +481,12 @@ Transform.prototype.getMountPoint = function getMountPoint () { * @return {undefined} undefined */ Transform.prototype.setMountPoint = function setMountPoint (x, y, z) { - this.offsets.mountPointChanged = setVec(this.offsets.mountPoint, x, y, z != null ? z - 0.5 : z); + var ch = setVec(this.offsets.mountPoint, x, y, z != null ? z - 0.5 : z); + this.offsets.mountPointChanged = ch; + if (ch) + { + this._refresh(); + } }; /** @@ -448,7 +512,12 @@ Transform.prototype.getOrigin = function getOrigin () { * @return {undefined} undefined */ Transform.prototype.setOrigin = function setOrigin (x, y, z) { - this.offsets.originChanged = setVec(this.offsets.origin, x, y, z != null ? z - 0.5 : z); + var ch = setVec(this.offsets.origin, x, y, z != null ? z - 0.5 : z); + this.offsets.originChanged = ch; + if (ch) + { + this._refresh(); + } }; /** @@ -717,64 +786,64 @@ function multiply (out, a, b) { // Cache only the current line of the second matrix var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; - res = b0*a00 + b1*a10 + b2*a20 + b3*a30; - changed = changed ? changed : out[0] === res; + res = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + changed = changed ? changed : (out[0] !== res && !nearlyEqual(out[0], res)); out[0] = res; - res = b0*a01 + b1*a11 + b2*a21 + b3*a31; - changed = changed ? changed : out[1] === res; + res = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + changed = changed ? changed : (out[1] !== res && !nearlyEqual(out[1], res)); out[1] = res; - res = b0*a02 + b1*a12 + b2*a22 + b3*a32; - changed = changed ? changed : out[2] === res; + res = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + changed = changed ? changed : (out[2] !== res && !nearlyEqual(out[2], res)); out[2] = res; out[3] = 0; b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; - res = b0*a00 + b1*a10 + b2*a20 + b3*a30; - changed = changed ? changed : out[4] === res; + res = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + changed = changed ? changed : (out[4] !== res && !nearlyEqual(out[4], res)); out[4] = res; - res = b0*a01 + b1*a11 + b2*a21 + b3*a31; - changed = changed ? changed : out[5] === res; + res = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + changed = changed ? changed : (out[5] !== res && !nearlyEqual(out[5], res)); out[5] = res; - res = b0*a02 + b1*a12 + b2*a22 + b3*a32; - changed = changed ? changed : out[6] === res; + res = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + changed = changed ? changed : (out[6] !== res && !nearlyEqual(out[6], res)); out[6] = res; out[7] = 0; b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; - res = b0*a00 + b1*a10 + b2*a20 + b3*a30; - changed = changed ? changed : out[8] === res; + res = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + changed = changed ? changed : (out[8] !== res && !nearlyEqual(out[8], res)); out[8] = res; - res = b0*a01 + b1*a11 + b2*a21 + b3*a31; - changed = changed ? changed : out[9] === res; + res = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + changed = changed ? changed : (out[9] !== res && !nearlyEqual(out[9], res)); out[9] = res; - res = b0*a02 + b1*a12 + b2*a22 + b3*a32; - changed = changed ? changed : out[10] === res; + res = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + changed = changed ? changed : (out[10] !== res && !nearlyEqual(out[10], res)); out[10] = res; out[11] = 0; b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; - res = b0*a00 + b1*a10 + b2*a20 + b3*a30; - changed = changed ? changed : out[12] === res; + res = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + changed = changed ? changed : (out[12] !== res && !nearlyEqual(out[12], res)); out[12] = res; - res = b0*a01 + b1*a11 + b2*a21 + b3*a31; - changed = changed ? changed : out[13] === res; + res = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + changed = changed ? changed : (out[13] !== res && !nearlyEqual(out[13], res)); out[13] = res; - res = b0*a02 + b1*a12 + b2*a22 + b3*a32; - changed = changed ? changed : out[14] === res; + res = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + changed = changed ? changed : (out[14] !== res && !nearlyEqual(out[14], res)); out[14] = res; out[15] = 1; @@ -782,4 +851,13 @@ function multiply (out, a, b) { return changed; } +function nearlyEqual(a, b) +{ + var diff = Math.abs(a - b); + + // Note: Should be good enough for the needs here. + return diff < 0.01; +} + + module.exports = Transform; diff --git a/core/TransformSystem.js b/core/TransformSystem.js index f74daa6d..d8b4ef2f 100644 --- a/core/TransformSystem.js +++ b/core/TransformSystem.js @@ -36,7 +36,7 @@ var PathStore = require('./PathStore'); * @constructor {TransformSystem} */ function TransformSystem () { - this.pathStore = new PathStore(); + this.pathStore = new PathStore(); } /** @@ -49,327 +49,349 @@ function TransformSystem () { * @param {String} path for the transform to be registered to. * @param {Transform | undefined} transform optional transform to register. */ -TransformSystem.prototype.registerTransformAtPath = function registerTransformAtPath (path, transform) { - if (!PathUtils.depth(path)) - return this.pathStore.insert(path, transform ? transform : new Transform()); +TransformSystem.prototype.registerTransformAtPath = function registerTransformAtPath(path, transform) +{ + if (!PathUtils.depth(path)) + return this.pathStore.insert(path, transform ? transform : new Transform()); - var parent = this.pathStore.get(PathUtils.parent(path)); + var parent = this.pathStore.get(PathUtils.parent(path)); - if (!parent) throw new Error( + if (!parent) throw new Error( 'No parent transform registered at expected path: ' + PathUtils.parent(path) ); - if (transform) transform.setParent(parent); + if (transform) transform.setParent(parent); - this.pathStore.insert(path, transform ? transform : new Transform(parent)); + this.pathStore.insert(path, transform ? transform : new Transform(parent)); }; /** - * deregisters a transform registered at the given path. - * - * @method deregisterTransformAtPath - * @return {void} - * - * @param {String} path at which to register the transform - */ -TransformSystem.prototype.deregisterTransformAtPath = function deregisterTransformAtPath (path) { - this.pathStore.remove(path); + * deregisters a transform registered at the given path. + * + * @method deregisterTransformAtPath + * @return {void} + * + * @param {String} path at which to register the transform + */ +TransformSystem.prototype.deregisterTransformAtPath = function deregisterTransformAtPath(path) +{ + var transform = this.pathStore.get(path); + if (transform) + { + // Just to be sure. + transform.node = null; + } + + this.pathStore.remove(path); }; /** - * Method which will make the transform currently stored at the given path a breakpoint. - * A transform being a breakpoint means that both a local and world transform will be calculated - * for that point. The local transform being the concatinated transform of all ancestor transforms up - * until the nearest breakpoint, and the world being the concatinated transform of all ancestor transforms. - * This method throws if no transform is at the provided path. - * - * @method - * - * @param {String} path The path at which to turn the transform into a breakpoint - * - * @return {undefined} undefined - */ + * Method which will make the transform currently stored at the given path a breakpoint. + * A transform being a breakpoint means that both a local and world transform will be calculated + * for that point. The local transform being the concatinated transform of all ancestor transforms up + * until the nearest breakpoint, and the world being the concatinated transform of all ancestor transforms. + * This method throws if no transform is at the provided path. + * + * @method + * + * @param {String} path The path at which to turn the transform into a breakpoint + * + * @return {undefined} undefined + */ TransformSystem.prototype.makeBreakPointAt = function makeBreakPointAt (path) { - var transform = this.pathStore.get(path); - if (!transform) throw new Error('No transform Registered at path: ' + path); - transform.setBreakPoint(); + var transform = this.pathStore.get(path); + if (!transform) throw new Error('No transform Registered at path: ' + path); + transform.setBreakPoint(); }; /** - * Method that will make the transform at this location calculate a world matrix. - * - * @method - * - * @param {String} path The path at which to make the transform calculate a world matrix - * - * @return {undefined} undefined - */ + * Method that will make the transform at this location calculate a world matrix. + * + * @method + * + * @param {String} path The path at which to make the transform calculate a world matrix + * + * @return {undefined} undefined + */ TransformSystem.prototype.makeCalculateWorldMatrixAt = function makeCalculateWorldMatrixAt (path) { - var transform = this.pathStore.get(path); - if (!transform) throw new Error('No transform Registered at path: ' + path); - transform.setCalculateWorldMatrix(); + var transform = this.pathStore.get(path); + if (!transform) throw new Error('No transform Registered at path: ' + path); + transform.setCalculateWorldMatrix(); }; /** - * Returns the instance of the transform class associated with the given path, - * or undefined if no transform is associated. - * - * @method - * - * @param {String} path The path to lookup - * - * @return {Transform | undefined} the transform at that path is available, else undefined. - */ + * Returns the instance of the transform class associated with the given path, + * or undefined if no transform is associated. + * + * @method + * + * @param {String} path The path to lookup + * + * @return {Transform | undefined} the transform at that path is available, else undefined. + */ TransformSystem.prototype.get = function get (path) { - return this.pathStore.get(path); + return this.pathStore.get(path); }; /** - * update is called when the transform system requires an update. - * It traverses the transform array and evaluates the necessary transforms - * in the scene graph with the information from the corresponding node - * in the scene graph - * - * @method update - * - * @return {undefined} undefined - */ -TransformSystem.prototype.update = function update () { - var transforms = this.pathStore.getItems(); - var paths = this.pathStore.getPaths(); - var transform; - var changed; - var node; - var vectors; - var offsets; - var components; + * update is called when the transform system requires an update. + * It traverses the transform array and evaluates the necessary transforms + * in the scene graph with the information from the corresponding node + * in the scene graph + * + * @method update + * + * @return {undefined} undefined + */ +TransformSystem.prototype.update = function update() +{ + if (stats) stats.ProfileStart("trUp") + + var transforms = this.pathStore.getItems(); + var paths = this.pathStore.getPaths(); + var transform; + var changed; + var node; + var vectors; + var offsets; + var components; - for (var i = 0, len = transforms.length ; i < len ; i++) { - node = Dispatch.getNode(paths[i]); - if (!node) continue; - components = node.getComponents(); - transform = transforms[i]; - vectors = transform.vectors; - offsets = transform.offsets; - if (offsets.alignChanged) alignChanged(node, components, offsets); - if (offsets.mountPointChanged) mountPointChanged(node, components, offsets); - if (offsets.originChanged) originChanged(node, components, offsets); - if (vectors.positionChanged) positionChanged(node, components, vectors); - if (vectors.rotationChanged) rotationChanged(node, components, vectors); - if (vectors.scaleChanged) scaleChanged(node, components, vectors); - if ((changed = transform.calculate(node))) { - transformChanged(node, components, transform); - if (changed & Transform.LOCAL_CHANGED) localTransformChanged(node, components, transform.getLocalTransform()); - if (changed & Transform.WORLD_CHANGED) worldTransformChanged(node, components, transform.getWorldTransform()); - } - } + for (var i = 0, len = transforms.length ; i < len ; i++) + { + transform = transforms[i]; + if (transform.refresh) + { + transform.refresh = false; + + node = Dispatch.getNode(paths[i]); + if (node) + { + components = node.getComponents(); + vectors = transform.vectors; + offsets = transform.offsets; + if (offsets.alignChanged) alignChanged(node, components, offsets); + if (offsets.mountPointChanged) mountPointChanged(node, components, offsets); + if (offsets.originChanged) originChanged(node, components, offsets); + if (vectors.positionChanged) positionChanged(node, components, vectors); + if (vectors.rotationChanged) rotationChanged(node, components, vectors); + if (vectors.scaleChanged) scaleChanged(node, components, vectors); + if ((changed = transform.calculate(node))) { + transformChanged(node, components, transform); + if (changed & Transform.LOCAL_CHANGED) localTransformChanged(node, components, transform.getLocalTransform()); + if (changed & Transform.WORLD_CHANGED) worldTransformChanged(node, components, transform.getWorldTransform()); + } + } + } + } + + if(stats) stats.ProfileEnd("trUp") }; // private methods /** - * Private method to call when align changes. Triggers 'onAlignChange' methods - * on the node and all of the node's components - * - * @method - * @private - * - * @param {Node} node the node on which to call onAlignChange if necessary - * @param {Array} components the components on which to call onAlignChange if necessary - * @param {Object} offsets the set of offsets from the transform - * - * @return {undefined} undefined - */ + * Private method to call when align changes. Triggers 'onAlignChange' methods + * on the node and all of the node's components + * + * @method + * @private + * + * @param {Node} node the node on which to call onAlignChange if necessary + * @param {Array} components the components on which to call onAlignChange if necessary + * @param {Object} offsets the set of offsets from the transform + * + * @return {undefined} undefined + */ function alignChanged (node, components, offsets) { - var x = offsets.align[0]; - var y = offsets.align[1]; - var z = offsets.align[2]; - if (node.onAlignChange) node.onAlignChange(x, y, z); - for (var i = 0, len = components.length ; i < len ; i++) - if (components[i] && components[i].onAlignChange) - components[i].onAlignChange(x, y, z); - offsets.alignChanged = false; + var x = offsets.align[0]; + var y = offsets.align[1]; + var z = offsets.align[2]; + if (node.onAlignChange) node.onAlignChange(x, y, z); + for (var i = 0, len = components.length ; i < len ; i++) + if (components[i] && components[i].onAlignChange) + components[i].onAlignChange(x, y, z); + offsets.alignChanged = false; } /** - * Private method to call when MountPoint changes. Triggers 'onMountPointChange' methods - * on the node and all of the node's components - * - * @method - * @private - * - * @param {Node} node the node on which to trigger a change event if necessary - * @param {Array} components the components on which to trigger a change event if necessary - * @param {Object} offsets the set of offsets from the transform - * - * @return {undefined} undefined - */ + * Private method to call when MountPoint changes. Triggers 'onMountPointChange' methods + * on the node and all of the node's components + * + * @method + * @private + * + * @param {Node} node the node on which to trigger a change event if necessary + * @param {Array} components the components on which to trigger a change event if necessary + * @param {Object} offsets the set of offsets from the transform + * + * @return {undefined} undefined + */ function mountPointChanged (node, components, offsets) { - var x = offsets.mountPoint[0]; - var y = offsets.mountPoint[1]; - var z = offsets.mountPoint[2]; - if (node.onMountPointChange) node.onMountPointChange(x, y, z); - for (var i = 0, len = components.length ; i < len ; i++) - if (components[i] && components[i].onMountPointChange) - components[i].onMountPointChange(x, y, z); - offsets.mountPointChanged = false; + var x = offsets.mountPoint[0]; + var y = offsets.mountPoint[1]; + var z = offsets.mountPoint[2]; + if (node.onMountPointChange) node.onMountPointChange(x, y, z); + for (var i = 0, len = components.length ; i < len ; i++) + if (components[i] && components[i].onMountPointChange) + components[i].onMountPointChange(x, y, z); + offsets.mountPointChanged = false; } /** - * Private method to call when Origin changes. Triggers 'onOriginChange' methods - * on the node and all of the node's components - * - * @method - * @private - * - * @param {Node} node the node on which to trigger a change event if necessary - * @param {Array} components the components on which to trigger a change event if necessary - * @param {Object} offsets the set of offsets from the transform - * - * @return {undefined} undefined - */ + * Private method to call when Origin changes. Triggers 'onOriginChange' methods + * on the node and all of the node's components + * + * @method + * @private + * + * @param {Node} node the node on which to trigger a change event if necessary + * @param {Array} components the components on which to trigger a change event if necessary + * @param {Object} offsets the set of offsets from the transform + * + * @return {undefined} undefined + */ function originChanged (node, components, offsets) { - var x = offsets.origin[0]; - var y = offsets.origin[1]; - var z = offsets.origin[2]; - if (node.onOriginChange) node.onOriginChange(x, y, z); - for (var i = 0, len = components.length ; i < len ; i++) - if (components[i] && components[i].onOriginChange) - components[i].onOriginChange(x, y, z); - offsets.originChanged = false; + var x = offsets.origin[0]; + var y = offsets.origin[1]; + var z = offsets.origin[2]; + if (node.onOriginChange) node.onOriginChange(x, y, z); + for (var i = 0, len = components.length ; i < len ; i++) + if (components[i] && components[i].onOriginChange) + components[i].onOriginChange(x, y, z); + offsets.originChanged = false; } /** - * Private method to call when Position changes. Triggers 'onPositionChange' methods - * on the node and all of the node's components - * - * @method - * @private - * - * @param {Node} node the node on which to trigger a change event if necessary - * @param {Array} components the components on which to trigger a change event if necessary - * @param {Object} vectors the set of vectors from the transform - * - * @return {undefined} undefined - */ + * Private method to call when Position changes. Triggers 'onPositionChange' methods + * on the node and all of the node's components + * + * @method + * @private + * + * @param {Node} node the node on which to trigger a change event if necessary + * @param {Array} components the components on which to trigger a change event if necessary + * @param {Object} vectors the set of vectors from the transform + * + * @return {undefined} undefined + */ function positionChanged (node, components, vectors) { - var x = vectors.position[0]; - var y = vectors.position[1]; - var z = vectors.position[2]; - if (node.onPositionChange) node.onPositionChange(x, y, z); - for (var i = 0, len = components.length ; i < len ; i++) - if (components[i] && components[i].onPositionChange) - components[i].onPositionChange(x, y, z); - vectors.positionChanged = false; + var x = vectors.position[0]; + var y = vectors.position[1]; + var z = vectors.position[2]; + if (node.onPositionChange) node.onPositionChange(x, y, z); + for (var i = 0, len = components.length ; i < len ; i++) + if (components[i] && components[i].onPositionChange) + components[i].onPositionChange(x, y, z); + vectors.positionChanged = false; } /** - * Private method to call when Rotation changes. Triggers 'onRotationChange' methods - * on the node and all of the node's components - * - * @method - * @private - * - * @param {Node} node the node on which to trigger a change event if necessary - * @param {Array} components the components on which to trigger a change event if necessary - * @param {Object} vectors the set of vectors from the transform - * - * @return {undefined} undefined - */ + * Private method to call when Rotation changes. Triggers 'onRotationChange' methods + * on the node and all of the node's components + * + * @method + * @private + * + * @param {Node} node the node on which to trigger a change event if necessary + * @param {Array} components the components on which to trigger a change event if necessary + * @param {Object} vectors the set of vectors from the transform + * + * @return {undefined} undefined + */ function rotationChanged (node, components, vectors) { - var x = vectors.rotation[0]; - var y = vectors.rotation[1]; - var z = vectors.rotation[2]; - var w = vectors.rotation[3]; - if (node.onRotationChange) node.onRotationChange(x, y, z, w); - for (var i = 0, len = components.length ; i < len ; i++) - if (components[i] && components[i].onRotationChange) - components[i].onRotationChange(x, y, z, w); - vectors.rotationChanged = false; + var x = vectors.rotation[0]; + var y = vectors.rotation[1]; + var z = vectors.rotation[2]; + var w = vectors.rotation[3]; + if (node.onRotationChange) node.onRotationChange(x, y, z, w); + for (var i = 0, len = components.length ; i < len ; i++) + if (components[i] && components[i].onRotationChange) + components[i].onRotationChange(x, y, z, w); + vectors.rotationChanged = false; } /** - * Private method to call when Scale changes. Triggers 'onScaleChange' methods - * on the node and all of the node's components - * - * @method - * @private - * - * @param {Node} node the node on which to trigger a change event if necessary - * @param {Array} components the components on which to trigger a change event if necessary - * @param {Object} vectors the set of vectors from the transform - * - * @return {undefined} undefined - */ + * Private method to call when Scale changes. Triggers 'onScaleChange' methods + * on the node and all of the node's components + * + * @method + * @private + * + * @param {Node} node the node on which to trigger a change event if necessary + * @param {Array} components the components on which to trigger a change event if necessary + * @param {Object} vectors the set of vectors from the transform + * + * @return {undefined} undefined + */ function scaleChanged (node, components, vectors) { - var x = vectors.scale[0]; - var y = vectors.scale[1]; - var z = vectors.scale[2]; - if (node.onScaleChange) node.onScaleChange(x, y, z); - for (var i = 0, len = components.length ; i < len ; i++) - if (components[i] && components[i].onScaleChange) - components[i].onScaleChange(x, y, z); - vectors.scaleChanged = false; + var x = vectors.scale[0]; + var y = vectors.scale[1]; + var z = vectors.scale[2]; + if (node.onScaleChange) node.onScaleChange(x, y, z); + for (var i = 0, len = components.length ; i < len ; i++) + if (components[i] && components[i].onScaleChange) + components[i].onScaleChange(x, y, z); + vectors.scaleChanged = false; } /** - * Private method to call when either the Local or World Transform changes. - * Triggers 'onTransformChange' methods on the node and all of the node's components - * - * @method - * @private - * - * @param {Node} node the node on which to trigger a change event if necessary - * @param {Array} components the components on which to trigger a change event if necessary - * @param {Transform} transform the transform class that changed - * - * @return {undefined} undefined - */ + * Private method to call when either the Local or World Transform changes. + * Triggers 'onTransformChange' methods on the node and all of the node's components + * + * @method + * @private + * + * @param {Node} node the node on which to trigger a change event if necessary + * @param {Array} components the components on which to trigger a change event if necessary + * @param {Transform} transform the transform class that changed + * + * @return {undefined} undefined + */ function transformChanged (node, components, transform) { - if (node.onTransformChange) node.onTransformChange(transform); - for (var i = 0, len = components.length ; i < len ; i++) - if (components[i] && components[i].onTransformChange) - components[i].onTransformChange(transform); + if (node.onTransformChange) node.onTransformChange(transform); + for (var i = 0, len = components.length ; i < len ; i++) + if (components[i] && components[i].onTransformChange) + components[i].onTransformChange(transform); } /** - * Private method to call when the local transform changes. Triggers 'onLocalTransformChange' methods - * on the node and all of the node's components - * - * @method - * @private - * - * @param {Node} node the node on which to trigger a change event if necessary - * @param {Array} components the components on which to trigger a change event if necessary - * @param {Array} transform the local transform - * - * @return {undefined} undefined - */ + * Private method to call when the local transform changes. Triggers 'onLocalTransformChange' methods + * on the node and all of the node's components + * + * @method + * @private + * + * @param {Node} node the node on which to trigger a change event if necessary + * @param {Array} components the components on which to trigger a change event if necessary + * @param {Array} transform the local transform + * + * @return {undefined} undefined + */ function localTransformChanged (node, components, transform) { - if (node.onLocalTransformChange) node.onLocalTransformChange(transform); - for (var i = 0, len = components.length ; i < len ; i++) - if (components[i] && components[i].onLocalTransformChange) - components[i].onLocalTransformChange(transform); + if (node.onLocalTransformChange) node.onLocalTransformChange(transform); + for (var i = 0, len = components.length ; i < len ; i++) + if (components[i] && components[i].onLocalTransformChange) + components[i].onLocalTransformChange(transform); } /** - * Private method to call when the world transform changes. Triggers 'onWorldTransformChange' methods - * on the node and all of the node's components - * - * @method - * @private - * - * @param {Node} node the node on which to trigger a change event if necessary - * @param {Array} components the components on which to trigger a change event if necessary - * @param {Array} transform the world transform - * - * @return {undefined} undefined - */ + * Private method to call when the world transform changes. Triggers 'onWorldTransformChange' methods + * on the node and all of the node's components + * + * @method + * @private + * + * @param {Node} node the node on which to trigger a change event if necessary + * @param {Array} components the components on which to trigger a change event if necessary + * @param {Array} transform the world transform + * + * @return {undefined} undefined + */ function worldTransformChanged (node, components, transform) { - if (node.onWorldTransformChange) node.onWorldTransformChange(transform); - for (var i = 0, len = components.length ; i < len ; i++) - if (components[i] && components[i].onWorldTransformChange) - components[i].onWorldTransformChange(transform); + if (node.onWorldTransformChange) node.onWorldTransformChange(transform); + for (var i = 0, len = components.length ; i < len ; i++) + if (components[i] && components[i].onWorldTransformChange) + components[i].onWorldTransformChange(transform); } module.exports = new TransformSystem(); diff --git a/dom-renderers/Math.js b/dom-renderers/Math.js index 9b2dc09b..d30e86f5 100644 --- a/dom-renderers/Math.js +++ b/dom-renderers/Math.js @@ -114,10 +114,10 @@ function multiply (out, a, b) { out3 = b0*a03 + b1*a13 + b2*a23 + b3*a33; changed = changed ? - changed : out0 === out[0] || - out1 === out[1] || - out2 === out[2] || - out3 === out[3]; + changed : out0 !== out[0] || + out1 !== out[1] || + out2 !== out[2] || + out3 !== out[3]; out[0] = out0; out[1] = out1; @@ -131,10 +131,10 @@ function multiply (out, a, b) { out3 = b0*a03 + b1*a13 + b2*a23 + b3*a33; changed = changed ? - changed : out0 === out[4] || - out1 === out[5] || - out2 === out[6] || - out3 === out[7]; + changed : out0 !== out[4] || + out1 !== out[5] || + out2 !== out[6] || + out3 !== out[7]; out[4] = out0; out[5] = out1; @@ -148,10 +148,10 @@ function multiply (out, a, b) { out3 = b0*a03 + b1*a13 + b2*a23 + b3*a33; changed = changed ? - changed : out0 === out[8] || - out1 === out[9] || - out2 === out[10] || - out3 === out[11]; + changed : out0 !== out[8] || + out1 !== out[9] || + out2 !== out[10] || + out3 !== out[11]; out[8] = out0; out[9] = out1; @@ -165,10 +165,10 @@ function multiply (out, a, b) { out3 = b0*a03 + b1*a13 + b2*a23 + b3*a33; changed = changed ? - changed : out0 === out[12] || - out1 === out[13] || - out2 === out[14] || - out3 === out[15]; + changed : out0 !== out[12] || + out1 !== out[13] || + out2 !== out[14] || + out3 !== out[15]; out[12] = out0; out[13] = out1; diff --git a/render-loops/RequestAnimationFrameLoop.js b/render-loops/RequestAnimationFrameLoop.js index e2b1fd37..09417e76 100644 --- a/render-loops/RequestAnimationFrameLoop.js +++ b/render-loops/RequestAnimationFrameLoop.js @@ -76,7 +76,9 @@ function RequestAnimationFrameLoop() { this._updates = []; this._looper = function(time) { - _this.loop(time); + if (stats) stats.ProfileStart("gui"); + _this.loop(time); + if (stats) stats.ProfileEnd("gui"); }; this._time = 0; this._stoppedAt = 0; diff --git a/renderers/Context.js b/renderers/Context.js index e59df0db..372856ee 100644 --- a/renderers/Context.js +++ b/renderers/Context.js @@ -484,9 +484,13 @@ function glBufferData (context, path, commands, iterator) { } function glCutoutState (context, path, commands, iterator) { - if (!context._webGLRenderer) context._initWebGLRenderer(); - context._webGLRenderer.setCutoutState(path, commands[++iterator]); - return iterator; + var state = commands[++iterator]; + if (!context._webGLRenderer && state) context._initWebGLRenderer(); + if (context._webGLRenderer) + { + context._webGLRenderer.setCutoutState(path, state); + } + return iterator; } function glMeshVisibility (context, path, commands, iterator) {