/* <copyright> This file contains proprietary software owned by Motorola Mobility, Inc.<br/> No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.<br/> (c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. </copyright> */ /* * camera class */ camera = function() { this.proj = mat4.identity(); this.view = mat4.identity(); this.world = mat4.identity(); this.viewProj = mat4.identity(); this.invViewProj = mat4.identity(); this.frustum = []; this.frustumPts = []; this.controller = null; this.setPerspective = function(fov, aratio, near, far) { this.ortho = null; this.persp = {}; this.persp.fov = fov; this.persp.aratio = aratio; this.persp.near = near; this.persp.far = far; this.proj = mat4.perspective(fov, aratio, near, far); this.recalc(); } this.reset = function() { this.world = mat4.identity(); this.recalc(); } this.copy = function(cam) { mat4.inplace_copy(this.view, cam.view); mat4.inplace_copy(this.world, cam.world); mat4.inplace_copy(this.proj, cam.proj); mat4.inplace_copy(this.viewProj, cam.viewProj); mat4.inplace_copy(this.invViewProj, cam.invViewProj); this.frustum = cam.frustum.slice(); this.frustumPts = cam.frustumPts.slice(); } this.recalc = function() { // update frustum planes this.frustum = []; var vp = this.viewProj; normalizePlane = function( p ) { var len = vec3.length( p ); if( Math.abs( 1.0 - len ) > 0.001 ) { p[0] /= len; p[1] /= len; p[2] /= len; p[3] /= len; } return p; } /* This is the old way var t = this.persp.near * Math.tan(0.017453292519943295769236 * this.persp.fov * 0.5); var r = t * this.persp.aratio; var u = t; var l = -r; var b = -u; tview = mat4.transpose(this.view); this.frustum.push( normalizePlane( mat4.transformPoint(tview, [this.persp.near, 0.0, l, 0.0] ) ) ); // left this.frustum.push( normalizePlane( mat4.transformPoint(tview, [-this.persp.near, 0.0, -r, 0.0] ) ) ); // right this.frustum.push( normalizePlane( mat4.transformPoint(tview, [0.0, this.persp.near, b, 0.0] ) ) ); // bottom this.frustum.push( normalizePlane( mat4.transformPoint(tview, [0.0, -this.persp.near, -u, 0.0] ) ) ); // top this.frustum.push( normalizePlane( mat4.transformPoint(tview, [0.0, 0.0, -1.0, -this.persp.near] ) ) ); // near this.frustum.push( normalizePlane( mat4.transformPoint(tview, [0.0, 0.0, 1.0, this.persp.far] ) ) ); // far */ var l = normalizePlane( [vp[3] + vp[0], vp[7] + vp[4], vp[11] + vp[8], vp[15]+vp[12]] ); var r = normalizePlane( [vp[3] - vp[0], vp[7] - vp[4], vp[11] - vp[8], vp[15]-vp[12]] ); var t = normalizePlane( [vp[3] - vp[1], vp[7] - vp[5], vp[11] - vp[9], vp[15]-vp[13]] ); var b = normalizePlane( [vp[3] + vp[1], vp[7] + vp[5], vp[11] + vp[9], vp[15]+vp[13]] ); var n = normalizePlane( [vp[3] + vp[2], vp[7] + vp[6], vp[11] + vp[10], vp[15]+vp[14]] ); var f = normalizePlane( [vp[3] - vp[2], vp[7] - vp[6], vp[11] - vp[10], vp[15]-vp[14]] ); this.frustum.push(l); this.frustum.push(r); this.frustum.push(t); this.frustum.push(b); this.frustum.push(n); this.frustum.push(f); // update frustum points this.frustumPts = []; var invvp = this.viewProj; this.frustumPts.push( mat4.transformPoint( invvp, [-1,-1,-1] ) ); this.frustumPts.push( mat4.transformPoint( invvp, [-1,1,-1] ) ); this.frustumPts.push( mat4.transformPoint( invvp, [1,1,-1] ) ); this.frustumPts.push( mat4.transformPoint( invvp, [1,-1,-1] ) ); this.frustumPts.push( mat4.transformPoint( invvp, [-1,-1,1] ) ); this.frustumPts.push( mat4.transformPoint( invvp, [-1,1,1] ) ); this.frustumPts.push( mat4.transformPoint( invvp, [1,1,1] ) ); this.frustumPts.push( mat4.transformPoint( invvp, [1,-1,1] ) ); }; this.setWorld = function(m) { this.world = m; this.view = mat4.inverse(m); this.viewProj = mat4.mul( this.view, this.proj ); this.invViewProj = mat4.inverse(this.viewProj); this.recalc(); } this.setView = function(m) { this.view = m; this.world = mat4.inverse(m); this.viewProj = mat4.mul( this.view, this.proj ); this.invViewProj = mat4.inverse(this.viewProj); this.recalc(); } this.setLookAt = function(eyePos, targetPos, upVec) { this.setWorld( mat4.lookAt(eyePos, targetPos, upVec) ); //this.recalc(); }; this.setPerspective = function(fov, aratio, near, far) { this.ortho = null; this.persp = {}; this.persp.fov = fov; this.persp.aratio = aratio; this.persp.near = near; this.persp.far = far; this.proj = mat4.perspective(fov, aratio, near, far); this.recalc(); } this.setOrthographic = function( l, r, t, b, n, f ) { this.persp = null; this.ortho = {}; this.ortho.left = l; this.ortho.right = r; this.ortho.top = t; this.ortho.bottom = b; this.ortho.near = n; this.ortho.far = f; this.proj = mat4.orthographic(l, r, t, b, n, f); this.recalc(); } this.onResize = function(x, y, width, height) { if( this.persp ) { this.setPerspective(this.persp.fov, width / height, this.persp.near, this.persp.far); } if( this.ortho ) { this.setOrthographic(x, x + width, y, y + height, this.ortho.near, this.ortho.far); } } this.zNear = function() { if( this.persp ) { return this.persp.near; } if( this.ortho ) { return this.ortho.near; } return 0.0; } this.zFar = function() { if( this.persp ) { return this.persp.far; } if( this.ortho ) { return this.ortho.far; } return 0.0; } // this is used by ambient occlusion... this.getFTR = function() { var fovyRad = (this.persp.fov * 0.5) * Math.PI / 180.0; return [ Math.tan(fovyRad) * this.persp.far, Math.tan(fovyRad / this.persp.aratio) * this.persp.far, this.persp.far ]; } this.attachCameraToNode = function( node ) { this.controller = node; } } /** Camera Manager * This class is used to manage the active camera. It provides functionality * for getting and setting the active camera, as well as providing stack operations * to switch to and from multiple cameras. */ cameraManager = function() { this.stack = []; /* Set the active camera. * This function sets the active camera to the given camera. */ this.setActiveCamera = function(c) { // pop the active camera off the stack. if( this.stack.length > 0 ) { this.stack.pop(); } // push the given camera onto the stack. this.stack.push(c); } /* Get the active camera. * The active camera always resides at the top of the stack. */ this.getActiveCamera = function() { if( this.stack.length > 0 ) { return this.stack[this.stack.length - 1]; } else { return null; } } /* Push a camera onto the stack. * The given camera becomes the active camera. */ this.pushCamera = function(c) { this.stack.push(c); } /* Pop a camera off the stack. * Returns the camera that was popped. * The next camera on the stack becomes active. */ this.popCamera = function() { return this.stack.pop(); } this.onResize = function(x, y, w, h) { var i = this.stack.length - 1; while( i >= 0 ) { this.stack[i].onResize( x, y, w, h ); i--; } } }