/* <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> */ var RDGE = RDGE || {}; /* * Manage state instances */ RDGE.stateManager = function () { // a stack of states this.stateStack = []; // number of states on the stack this.stateTop = undefined; // the states of the context this.RDGEInitState = null; this.RDGERunState = null; this.currentState = function () { if(this.stateTop != undefined) return this.stateStack[this.stateTop]; return null; }; /* * Push new IRuntime state - engine executes the new state */ this.PushState = function (state, flags) { if (state != null && typeof state.Init == 'function') { if(this.stateTop != undefined) this.stateStack[this.stateTop].LeaveState(); if(flags == undefined || flags != "noInit") state.Init(); this.stateTop = this.stateStack.push(state) - 1; } }; /* * Remove IRuntime state from stack, engine executes previous state */ this.PopState = function () { state = this.stateStack.pop(); if (state != null) { state.Shutdown(); } this.stateTop = this.stateTop > 0 ? this.stateTop - 1 : 0; if (this.stateStack[this.stateTop]) { this.stateStack[this.stateTop].ReInit(); } }; /* * Remove all states from the stack */ this.PopAll = function () { while (this.stateStack[this.stateTop] != null) { this.PopState(); } }; this.tick = function (dt) { if (this.stateStack[this.stateTop] != null) { this.stateStack[this.stateTop].Update(dt); this.stateStack[this.stateTop].Resize(); this.stateStack[this.stateTop].Draw(); } }; }; RDGE.Engine = function () { this._assetPath = "assets/"; // map of scene graphs to names this.sceneMap = []; // number of states on the stack this.stateTop = undefined; // size of the browser window this.lastWindowWidth = window.innerWidth; this.lastWindowHeight = window.innerHeight; this.defaultContext = null; this.lightManager = null; clearColor = [0.0, 0.0, 0.0, 0.0]; this.initializeComplete = false; this.RDGECanvas = null; /* * a map of canvas names to renderer */ this.canvasToRendererMap = {}; /* * states to canvas map - maps a state stack to the canvas context it belongs to */ this.canvasNameToStateStack = {}; /* * the list of context's that are active */ this.canvasCtxList = []; /* * regex object to verify runtime object is not some sort of exploit */ invalidObj = new RegExp("([()]|function)"); isValidObj = function (name) { // do a quick test make sure user isn't trying to execute a function if (invalidObj.test(name)) { window.console.error("invalid object name passed to RDGE, " + name + " - looks like a function"); return false; } return true; }; /* * The context definition - every context shares these parameters */ contextDef = function () { this.id = null; this.renderer = null; this.ctxStateManager = null; this.startUpState = null; this.sceneGraphMap = []; this.currentScene = null; this.getScene = function () { return this.sceneGraphMap[this.currentScene]; } this.debug = { 'frameCounter': 0, 'mat4CallCount': 0 } }; // maintains the contexts contextManager = new RDGE.objectManager(); this.ctxMan = contextManager; // the context currently being updated contextManager.currentCtx = null; contextManager._addObject = contextManager.addObject; contextManager.contextMap = {}; contextManager.addObject = function (context) { this.contextMap[context.id] = context; return this._addObject(context); }; contextManager.start = function () { var len = this.objects.length; for (var i = 0; i < len; ++i) { // set the current context contextManager.currentCtx = this.objects[i]; this.objects[i].ctxStateManager.PushState(this.objects[i].startUpState); } }; contextManager.forEach = function (cb) { var len = this.objects.length; for (var i = 0; i < len; ++i) { cb(this.objects[i]); } }; this.getContext = function (optCanvasID) { if (!optCanvasID) { return contextManager.currentCtx; } else { return contextManager.contextMap[optCanvasID]; } }; this.clearContext = function (canvasID) { contextManager.contextMap[canvasID] = undefined; }; /* * give the contextID (canvas id) of the context to set */ this.setContext = function (contextID) { contextManager.currentCtx = contextManager.contextMap[contextID]; }; this.tickContext = function (contextID) { var savedCtx = contextManager.currentCtx; contextManager.currentCtx = contextManager.contextMap[contextID]; this.objects[i].ctxStateManager.tick(dt); contextManager.currentCtx = savedCtx; }; this.setAssetPath = function (path) { this._assetPath = path.slice(); }; this.remapAssetFolder = function (url) { var searchStr = "assets/"; var index = url.indexOf(searchStr); var rtnPath = url; if (index >= 0) { rtnPath = url.substr(index + searchStr.length); rtnPath = this._assetPath + rtnPath; } return rtnPath; }; }; /* * Initialize the RDGE web engine */ RDGE.Engine.prototype.init = function (userInitState, userRunState, canvasObject) { this.GlInit(canvasObject); globalParamFuncSet = function (param) { this.data = param.data; this.type =param.type; this.set = function (v) { var len = this.data ? this.data.length : 0; for(var i=0;i<len;++i) this.data[i]=v[i]; } this.get = function () { if (this.data.length == undefined) { return this.data; } else { return this.data.slice(); } } }; // light manager init before global parameters structure is reconfigured this.lightManager = new RDGE.LightManager(RDGE.rdgeGlobalParameters.rdge_lights); // added getter and setter to global uniforms for (var p in RDGE.rdgeGlobalParameters) { if (p != "rdge_lights") { RDGE.rdgeGlobalParameters[p] = new globalParamFuncSet(RDGE.rdgeGlobalParameters[p]); } else { var lights = RDGE.rdgeGlobalParameters[p]; for (var l in lights) { RDGE.rdgeGlobalParameters[l] = new globalParamFuncSet(lights[l]); } } } // initial window this.lastWindowWidth = window.innerWidth; this.lastWindowHeight = window.innerHeight; // setup default render context this.defaultContext = new RDGE.RenderContext(); this.defaultContext.uniforms = [ { 'name': "u_matAmbient", 'value': [0.02,0.02,0.02, 1.0] }, { 'name': "u_matDiffuse", 'value': [1.0, 1.0, 1.0, 1.0] }, { 'name': "u_matSpecular", 'value': [1.0, 1.0, 1.0, 1.0] }, { 'name': "u_matShininess", 'value': [128.0] }, { 'name': "u_matEmission", 'value': [0.0, 0.0, 0.0, 1.0] } ]; // startup the contexts contextManager.start(); this.initializeComplete = true; }; // shutdown the engine clears all states RDGE.Engine.prototype.Shutdown = function () { this.PopAll(); }; // initialize WebGL RDGE.Engine.prototype.GlInit = function (canvasObject) { // Initialize var canvases = document.getElementsByTagName("canvas"); // transverse the canvases and create the contexts var numCv = canvases.length; for (var cvIdx = 0; cvIdx < numCv; ++cvIdx) { var canvas; // if this canvas has a rdge attribute initialize the render context var rdgeAttr = canvases[cvIdx].getAttribute("rdge"); if (rdgeAttr == "true") { // hack ~ while implementing multi-context canvas = canvases[cvIdx]; this.registerCanvas(canvas); } } /* canvas.addEventListener("webglcontextlost", contextLostHandler, false); canvas.addEventListener("webglcontextrestored", contextRestoredHandler, false); */ }; RDGE.Engine.prototype.loadScene = function (name) { var url = "assets_web/mesh/" + name + ".json" // if we are not in the load state than push it on again if (contextManager.currentCtx.stateMan.currentState().name == "RunState") { contextManager.currentCtx.stateMan.PushState(contextManager.currentCtx.stateMan.RDGEInitState); contextManager.currentCtx.loadScene(url, name); } }; RDGE.Engine.prototype.getScene = function (name) { return contextManager.currentCtx.sceneGraphMap[name]; }; RDGE.Engine.prototype.AddScene = function (name, sceneGraph) { contextManager.currentCtx.sceneGraphMap[name] = sceneGraph; contextManager.currentCtx.currentScene = name; }; RDGE.Engine.prototype.registerCanvas = function (canvas, runState) { if (canvas && this.getContext(canvas.rdgeid)) return; canvas.renderer = new RDGE._renderer(canvas); // create the renderer for the context this.canvasToRendererMap[canvas.rdgeid] = canvas; // store the canvas in the context map canvas.renderer.id = canvas.rdgeid; // configure the state manager for this context var stateMan = new RDGE.stateManager(); // add this context to the contextManager and attach the handle to DOM canvas for user retrieval var context = new contextDef(); context.id = canvas.rdgeid; context.renderer = canvas.renderer; context.ctxStateManager = stateMan; context.renderer.mvMatrix = RDGE.mat4.identity(); context.renderer.invMvMatrix = RDGE.mat4.identity(); context.renderer.projectionMatrix = RDGE.mat4.identity(); context.renderer.normalMatrix = RDGE.mat4.identity(); canvas.rdgeCtxHandle = contextManager.addObject(context); // set new context as the current context so that when the runtime object is instantiated // it can use the context during construction var oldCtx = contextManager.currentCtx; contextManager.currentCtx = context; var _runState; // check for runtime handlers if (runState) { _runState = runState; } else { var runAttr = canvas.getAttribute("rdgerun"); if (runAttr) { // make sure attribute is valid if (!isValidObj(runAttr)) return; try { var state = eval(runAttr); _runState = new state(); } catch (err) { window.console.error("The provided RDGE state object \"" + runAttr + "\" is not defined"); } } else { _runState = {}; RDGE.utilities.validateUserState(_runState); } } // check for a scene var sceneName = canvas.getAttribute("rdgescene"); // setup the RDGE states passing the user state or undefined stateMan.RDGEInitState = new RDGE.LoadState(_runState, context); stateMan.RDGERunState = new RDGE.RunState(_runState, context); // fill out any user state missing methods with dummy methods RDGE.utilities.validateUserState(_runState); if (sceneName) { stateMan.RDGEInitState.sceneName = sceneName; // run is now always the bottom state, loading can happen at any time stateMan.PushState(stateMan.RDGERunState, "noInit"); context.startUpState = stateMan.RDGEInitState; } else { context.startUpState = stateMan.RDGERunState; } if (this.initializeComplete) { context.ctxStateManager.PushState(context.startUpState); } // restore previous context // NOTE: Ninja requires this to be commented out! // if (oldCtx) // { // contextManager.currentCtx = oldCtx; // } }; RDGE.Engine.prototype.unregisterCanvas = function (canvas) { contextManager.removeObject(canvas.rdgeCtxHandle); this.clearContext( canvas.rdgeid ); }; RDGE.Engine.prototype.getCanvas = function (id) { return this.canvasToRendererMap[id]; };